]> git.saurik.com Git - apple/mdnsresponder.git/commitdiff
mDNSResponder-66.3.tar.gz v66.3
authorApple <opensource@apple.com>
Tue, 29 Jun 2004 05:26:23 +0000 (05:26 +0000)
committerApple <opensource@apple.com>
Tue, 29 Jun 2004 05:26:23 +0000 (05:26 +0000)
233 files changed:
Clients/DNS-SD.xcode/project.pbxproj [new file with mode: 0644]
Clients/DNSServiceBrowser-Info.plist [new file with mode: 0644]
Clients/DNSServiceBrowser.m
Clients/DNSServiceBrowser.nib/classes.nib
Clients/DNSServiceBrowser.nib/info.nib
Clients/DNSServiceBrowser.nib/objects.nib
Clients/DNSServiceReg.m [deleted file]
Clients/DNSServiceReg.nib/classes.nib [deleted file]
Clients/DNSServiceReg.nib/info.nib [deleted file]
Clients/DNSServiceReg.nib/objects.nib [deleted file]
Clients/DNSServiceRegistration-Info.plist [new file with mode: 0644]
Clients/DNSServiceRegistration.m
Clients/Java/BrowserApp.java [new file with mode: 0644]
Clients/Java/DNSSDUnitTest.java [new file with mode: 0644]
Clients/Java/SimpleChat.java [new file with mode: 0644]
Clients/Java/SwingBrowseListener.java [new file with mode: 0644]
Clients/Java/SwingDomainListener.java [new file with mode: 0644]
Clients/Java/SwingQueryListener.java [new file with mode: 0644]
Clients/Java/SwingResolveListener.java [new file with mode: 0644]
Clients/Makefile [new file with mode: 0755]
Clients/ReadMe.txt [new file with mode: 0644]
Clients/dns-sd.c [new file with mode: 0644]
Makefile
README.txt
mDNSCore/DNSCommon.c [new file with mode: 0644]
mDNSCore/DNSCommon.h [new file with mode: 0644]
mDNSCore/DNSDigest.c [new file with mode: 0644]
mDNSCore/mDNS.c
mDNSCore/mDNSClientAPI.h
mDNSCore/mDNSDebug.h
mDNSCore/mDNSEmbeddedAPI.h [deleted file]
mDNSCore/mDNSPlatformFunctions.h [deleted file]
mDNSCore/uDNS.c [new file with mode: 0755]
mDNSCore/uDNS.h [new file with mode: 0755]
mDNSMacOS9/CarbonResource.r
mDNSMacOS9/Mac OS Test Responder.c
mDNSMacOS9/Mac OS Test Searcher.c
mDNSMacOS9/README.txt
mDNSMacOS9/Responder.c [new file with mode: 0644]
mDNSMacOS9/Searcher.c [new file with mode: 0644]
mDNSMacOS9/ShowInitIcon.c [new file with mode: 0755]
mDNSMacOS9/ShowInitIcon.h [new file with mode: 0755]
mDNSMacOS9/mDNS.mcp
mDNSMacOS9/mDNSLibrary.c [new file with mode: 0644]
mDNSMacOS9/mDNSLibraryLoader.c [new file with mode: 0644]
mDNSMacOS9/mDNSLibraryResources.r [new file with mode: 0644]
mDNSMacOS9/mDNSMacOS9.c
mDNSMacOS9/mDNSMacOS9.h
mDNSMacOS9/mDNSPrefix.h [new file with mode: 0644]
mDNSMacOS9/mDNSPrefixCarbon.h [deleted file]
mDNSMacOS9/mDNSPrefixCarbonDebug.h [deleted file]
mDNSMacOS9/mDNSPrefixClassic.h [deleted file]
mDNSMacOSX/Applications/DNSServiceBrowser/BrowserController.h [deleted file]
mDNSMacOSX/Applications/DNSServiceBrowser/BrowserController.m [deleted file]
mDNSMacOSX/Applications/DNSServiceBrowser/DNS Service Browser.pbproj/project.pbxproj [deleted file]
mDNSMacOSX/Applications/DNSServiceBrowser/English.lproj/InfoPlist.strings [deleted file]
mDNSMacOSX/Applications/DNSServiceBrowser/English.lproj/MainMenu.nib/classes.nib [deleted file]
mDNSMacOSX/Applications/DNSServiceBrowser/English.lproj/MainMenu.nib/info.nib [deleted file]
mDNSMacOSX/Applications/DNSServiceBrowser/English.lproj/MainMenu.nib/objects.nib [deleted file]
mDNSMacOSX/Applications/DNSServiceBrowser/main.m [deleted file]
mDNSMacOSX/Applications/DNSServiceRegistration/DNS Service Registration.pbproj/project.pbxproj [deleted file]
mDNSMacOSX/Applications/DNSServiceRegistration/English.lproj/InfoPlist.strings [deleted file]
mDNSMacOSX/Applications/DNSServiceRegistration/English.lproj/MainMenu.nib/classes.nib [deleted file]
mDNSMacOSX/Applications/DNSServiceRegistration/English.lproj/MainMenu.nib/info.nib [deleted file]
mDNSMacOSX/Applications/DNSServiceRegistration/English.lproj/MainMenu.nib/objects.nib [deleted file]
mDNSMacOSX/Applications/DNSServiceRegistration/RegistrationController.h [deleted file]
mDNSMacOSX/Applications/DNSServiceRegistration/RegistrationController.m [deleted file]
mDNSMacOSX/Applications/DNSServiceRegistration/main.m [deleted file]
mDNSMacOSX/Applications/HAAutomounter/HAAutomounter.h [deleted file]
mDNSMacOSX/Applications/HAAutomounter/HAAutomounter.m [deleted file]
mDNSMacOSX/Applications/HAAutomounter/HAAutomounter.pbproj/project.pbxproj [deleted file]
mDNSMacOSX/Applications/HAAutomounter/main.m [deleted file]
mDNSMacOSX/CFSocket.c
mDNSMacOSX/CFSocketPuma.c
mDNSMacOSX/DNSServiceDiscoveryDefines.h
mDNSMacOSX/DNSServiceDiscoveryReply.defs
mDNSMacOSX/DNSServiceDiscoveryRequest.defs
mDNSMacOSX/SampleUDSClient.c [deleted file]
mDNSMacOSX/SamplemDNSClient.c
mDNSMacOSX/daemon.c
mDNSMacOSX/dnssd_clientstub.c [deleted file]
mDNSMacOSX/dnssd_ipc.c [deleted file]
mDNSMacOSX/dnssd_ipc.h [deleted file]
mDNSMacOSX/mDNSMacOSX.c [deleted file]
mDNSMacOSX/mDNSMacOSX.h
mDNSMacOSX/mDNSMacOSXPuma.c [deleted file]
mDNSMacOSX/mDNSResponder.pbproj/project.pbxproj
mDNSMacOSX/uds_daemon.c [deleted file]
mDNSPosix/Client.c
mDNSPosix/ExampleClientApp.c
mDNSPosix/ExampleClientApp.h
mDNSPosix/Identify.c
mDNSPosix/Makefile
mDNSPosix/NetMonitor.c
mDNSPosix/PosixDaemon.c [new file with mode: 0644]
mDNSPosix/ProxyResponder.c
mDNSPosix/ReadMe.txt
mDNSPosix/Responder.c
mDNSPosix/mDNSPosix.c
mDNSPosix/mDNSPosix.h
mDNSPosix/mDNSUNP.c
mDNSPosix/mDNSUNP.h
mDNSPosix/mdnsd.sh [new file with mode: 0644]
mDNSShared/GenLinkedList.c [new file with mode: 0755]
mDNSShared/GenLinkedList.h [new file with mode: 0755]
mDNSShared/Java/BaseListener.java
mDNSShared/Java/BrowseListener.java
mDNSShared/Java/DNSRecord.java
mDNSShared/Java/DNSSD.java
mDNSShared/Java/DNSSDException.java
mDNSShared/Java/DNSSDRegistration.java
mDNSShared/Java/DNSSDService.java
mDNSShared/Java/DomainListener.java
mDNSShared/Java/JNISupport.c
mDNSShared/Java/QueryListener.java
mDNSShared/Java/RegisterListener.java
mDNSShared/Java/ResolveListener.java
mDNSShared/Java/TXTRecord.java
mDNSShared/dns_sd.h
mDNSShared/dnssd_clientlib.c [new file with mode: 0755]
mDNSShared/dnssd_clientshim.c [new file with mode: 0644]
mDNSShared/dnssd_clientstub.c
mDNSShared/dnssd_ipc.c
mDNSShared/dnssd_ipc.h
mDNSShared/mDNS.1 [new file with mode: 0644]
mDNSShared/mDNSDebug.c [new file with mode: 0644]
mDNSShared/mDNSResponder.8 [new file with mode: 0644]
mDNSShared/uds_daemon.c
mDNSShared/uds_daemon.h [new file with mode: 0644]
mDNSVxWorks/mDNSVxWorks.c
mDNSVxWorks/mDNSVxWorks.h
mDNSWindows/Applications/DLL/dllmain.c [new file with mode: 0644]
mDNSWindows/Applications/DLL/dnssd.def [new file with mode: 0644]
mDNSWindows/Applications/DLL/dnssd.vcproj [new file with mode: 0644]
mDNSWindows/Applications/DNSServiceBrowser/Windows/ApplicationVS2002.sln
mDNSWindows/Applications/DNSServiceBrowser/Windows/ApplicationVS2002.vcproj
mDNSWindows/Applications/DNSServiceBrowser/Windows/ApplicationVS2003.sln
mDNSWindows/Applications/DNSServiceBrowser/Windows/ApplicationVS2003.vcproj
mDNSWindows/Applications/DNSServiceBrowser/Windows/Resources/Application.ico
mDNSWindows/Applications/DNSServiceBrowser/Windows/Resources/Application.rc
mDNSWindows/Applications/DNSServiceBrowser/Windows/Resources/Application.rc2
mDNSWindows/Applications/DNSServiceBrowser/Windows/Resources/Resource.h
mDNSWindows/Applications/DNSServiceBrowser/Windows/Sources/AboutDialog.cpp
mDNSWindows/Applications/DNSServiceBrowser/Windows/Sources/AboutDialog.h
mDNSWindows/Applications/DNSServiceBrowser/Windows/Sources/Application.cpp
mDNSWindows/Applications/DNSServiceBrowser/Windows/Sources/Application.h
mDNSWindows/Applications/DNSServiceBrowser/Windows/Sources/ChooserDialog.cpp
mDNSWindows/Applications/DNSServiceBrowser/Windows/Sources/ChooserDialog.h
mDNSWindows/Applications/DNSServiceBrowser/Windows/Sources/LoginDialog.cpp [new file with mode: 0644]
mDNSWindows/Applications/DNSServiceBrowser/Windows/Sources/LoginDialog.h [new file with mode: 0644]
mDNSWindows/Applications/DNSServiceBrowser/Windows/Sources/StdAfx.cpp
mDNSWindows/Applications/DNSServiceBrowser/Windows/Sources/StdAfx.h
mDNSWindows/Applications/DNSServiceBrowser/WindowsCE/Application.vcp
mDNSWindows/Applications/DNSServiceBrowser/WindowsCE/Resources/Application.ico
mDNSWindows/Applications/DNSServiceBrowser/WindowsCE/Resources/Application.rc
mDNSWindows/Applications/DNSServiceBrowser/WindowsCE/Sources/Application.cpp
mDNSWindows/Applications/DNSServiceBrowser/WindowsCE/Sources/Application.h
mDNSWindows/Applications/DNSServiceBrowser/WindowsCE/Sources/BrowserDialog.cpp
mDNSWindows/Applications/DNSServiceBrowser/WindowsCE/Sources/BrowserDialog.h
mDNSWindows/Applications/DNSServiceBrowser/WindowsCE/Sources/StdAfx.cpp
mDNSWindows/Applications/DNSServiceBrowser/WindowsCE/Sources/StdAfx.h
mDNSWindows/Applications/DNSServiceTest/Tool.c
mDNSWindows/Applications/DNSServiceTest/ToolPrefixWindows.h
mDNSWindows/Applications/DNSServiceTest/ToolPrefixWindowsDebug.h
mDNSWindows/Applications/DNSServiceTest/ToolWin32.mcp
mDNSWindows/Applications/DNSServiceTest/ToolWin32VS2002.sln
mDNSWindows/Applications/DNSServiceTest/ToolWin32VS2002.vcproj
mDNSWindows/Applications/DNSServiceTest/ToolWin32VS2003.sln
mDNSWindows/Applications/DNSServiceTest/ToolWin32VS2003.vcproj
mDNSWindows/Applications/ExplorerPlugin/ClassFactory.cpp [new file with mode: 0644]
mDNSWindows/Applications/ExplorerPlugin/ClassFactory.h [new file with mode: 0644]
mDNSWindows/Applications/ExplorerPlugin/ExplorerBar.cpp [new file with mode: 0644]
mDNSWindows/Applications/ExplorerPlugin/ExplorerBar.h [new file with mode: 0644]
mDNSWindows/Applications/ExplorerPlugin/ExplorerBarWindow.cpp [new file with mode: 0644]
mDNSWindows/Applications/ExplorerPlugin/ExplorerBarWindow.h [new file with mode: 0644]
mDNSWindows/Applications/ExplorerPlugin/ExplorerPlugin.cpp [new file with mode: 0644]
mDNSWindows/Applications/ExplorerPlugin/ExplorerPlugin.def [new file with mode: 0644]
mDNSWindows/Applications/ExplorerPlugin/ExplorerPlugin.h [new file with mode: 0644]
mDNSWindows/Applications/ExplorerPlugin/ExplorerPlugin.rc [new file with mode: 0644]
mDNSWindows/Applications/ExplorerPlugin/ExplorerPlugin.sln [new file with mode: 0644]
mDNSWindows/Applications/ExplorerPlugin/ExplorerPlugin.vcproj [new file with mode: 0644]
mDNSWindows/Applications/ExplorerPlugin/LoginDialog.cpp [new file with mode: 0644]
mDNSWindows/Applications/ExplorerPlugin/LoginDialog.h [new file with mode: 0644]
mDNSWindows/Applications/ExplorerPlugin/ReadMe.txt [new file with mode: 0644]
mDNSWindows/Applications/ExplorerPlugin/Resource.h [new file with mode: 0644]
mDNSWindows/Applications/ExplorerPlugin/StdAfx.cpp [new file with mode: 0644]
mDNSWindows/Applications/ExplorerPlugin/StdAfx.h [new file with mode: 0644]
mDNSWindows/Applications/Java/makefile [new file with mode: 0755]
mDNSWindows/Applications/NSPTool/Prefix.h [new file with mode: 0644]
mDNSWindows/Applications/NSPTool/Tool.c [new file with mode: 0644]
mDNSWindows/Applications/NSPTool/Tool.mcp [new file with mode: 0644]
mDNSWindows/Applications/SystemService/EventLogMessages.bin [new file with mode: 0644]
mDNSWindows/Applications/SystemService/Prefix.h [new file with mode: 0644]
mDNSWindows/Applications/SystemService/Resource.h [new file with mode: 0644]
mDNSWindows/Applications/SystemService/Service.c [new file with mode: 0644]
mDNSWindows/Applications/SystemService/Service.mcp [new file with mode: 0644]
mDNSWindows/Applications/SystemService/Service.rc [new file with mode: 0644]
mDNSWindows/Applications/SystemService/Service2002.sln [new file with mode: 0644]
mDNSWindows/Applications/SystemService/Service2002.vcproj [new file with mode: 0644]
mDNSWindows/Applications/SystemServiceTest/Prefix.h [new file with mode: 0644]
mDNSWindows/Applications/SystemServiceTest/Tool.c [new file with mode: 0644]
mDNSWindows/Applications/SystemServiceTest/Tool.mcp [new file with mode: 0644]
mDNSWindows/Applications/SystemServiceTest/Tool2002.sln [new file with mode: 0644]
mDNSWindows/Applications/SystemServiceTest/Tool2002.vcproj [new file with mode: 0644]
mDNSWindows/Applications/mdnsNSP/NSP.c [new file with mode: 0644]
mDNSWindows/Applications/mdnsNSP/NSP.def [new file with mode: 0644]
mDNSWindows/Applications/mdnsNSP/NSP.mcp [new file with mode: 0644]
mDNSWindows/Applications/mdnsNSP/Prefix.h [new file with mode: 0644]
mDNSWindows/Applications/mdnsNSP/ReadMe.txt [new file with mode: 0644]
mDNSWindows/Applications/mdnsNSP/mdnsNSP.c [new file with mode: 0644]
mDNSWindows/Applications/mdnsNSP/mdnsNSP.def [new file with mode: 0644]
mDNSWindows/Applications/mdnsNSP/mdnsNSP.mcp [new file with mode: 0644]
mDNSWindows/CommonServices.h [new file with mode: 0644]
mDNSWindows/DNSSD.c [new file with mode: 0644]
mDNSWindows/DNSSD.h [new file with mode: 0644]
mDNSWindows/DNSSDDirect.c [new file with mode: 0644]
mDNSWindows/DNSSDDirect.h [new file with mode: 0644]
mDNSWindows/DNSServices/DNSServiceDiscovery.c
mDNSWindows/DNSServices/DNSServiceDiscovery.h
mDNSWindows/DNSServices/DNSServices.c
mDNSWindows/DNSServices/DNSServices.h
mDNSWindows/DebugServices.c [new file with mode: 0644]
mDNSWindows/DebugServices.h [new file with mode: 0644]
mDNSWindows/Installer.vct [new file with mode: 0644]
mDNSWindows/README.txt
mDNSWindows/RMxClient.c [new file with mode: 0644]
mDNSWindows/RMxClient.h [new file with mode: 0644]
mDNSWindows/RMxCommon.c [new file with mode: 0644]
mDNSWindows/RMxCommon.h [new file with mode: 0644]
mDNSWindows/RMxServer.c [new file with mode: 0644]
mDNSWindows/RMxServer.h [new file with mode: 0644]
mDNSWindows/mDNSWin32.c
mDNSWindows/mDNSWin32.h

diff --git a/Clients/DNS-SD.xcode/project.pbxproj b/Clients/DNS-SD.xcode/project.pbxproj
new file mode 100644 (file)
index 0000000..46805b9
--- /dev/null
@@ -0,0 +1,581 @@
+// !$*UTF8*$!
+{
+       archiveVersion = 1;
+       classes = {
+       };
+       objectVersion = 39;
+       objects = {
+               014CEA490018CE3211CA2923 = {
+                       buildRules = (
+                       );
+                       buildSettings = {
+                               COPY_PHASE_STRIP = NO;
+                               DEBUGGING_SYMBOLS = YES;
+                               GCC_DYNAMIC_NO_PIC = NO;
+                               GCC_ENABLE_FIX_AND_CONTINUE = YES;
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+                               GCC_OPTIMIZATION_LEVEL = 0;
+                               OPTIMIZATION_CFLAGS = "-O0";
+                               ZERO_LINK = NO;
+                       };
+                       isa = PBXBuildStyle;
+                       name = Development;
+               };
+               014CEA4A0018CE3211CA2923 = {
+                       buildRules = (
+                       );
+                       buildSettings = {
+                               COPY_PHASE_STRIP = YES;
+                               GCC_ENABLE_FIX_AND_CONTINUE = NO;
+                               ZERO_LINK = NO;
+                       };
+                       isa = PBXBuildStyle;
+                       name = Deployment;
+               };
+//010
+//011
+//012
+//013
+//014
+//080
+//081
+//082
+//083
+//084
+               08FB7793FE84155DC02AAC07 = {
+                       buildSettings = {
+                       };
+                       buildStyles = (
+                               014CEA490018CE3211CA2923,
+                               014CEA4A0018CE3211CA2923,
+                       );
+                       hasScannedForEncodings = 1;
+                       isa = PBXProject;
+                       mainGroup = 08FB7794FE84155DC02AAC07;
+                       projectDirPath = "";
+                       targets = (
+                               FFF520490671177900DA3D49,
+                               8DD76F740486A8DE00D96B5E,
+                               FF1B691006711383002304DD,
+                               FF1E351206711B5C003DD5BC,
+                       );
+               };
+               08FB7794FE84155DC02AAC07 = {
+                       children = (
+                               08FB7795FE84155DC02AAC07,
+                               08FB779DFE84155DC02AAC07,
+                               19C28FBDFE9D53C911CA2CBB,
+                       );
+                       isa = PBXGroup;
+                       name = mDNS;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               08FB7795FE84155DC02AAC07 = {
+                       children = (
+                               08FB7796FE84155DC02AAC07,
+                               FF1B6914067114AF002304DD,
+                               FF964DAB067115710099215A,
+                               FF1E351B06711BCF003DD5BC,
+                               FF1E352506711BD6003DD5BC,
+                       );
+                       isa = PBXGroup;
+                       name = Source;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               08FB7796FE84155DC02AAC07 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.c;
+                       path = "dns-sd.c";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               08FB779DFE84155DC02AAC07 = {
+                       children = (
+                               FF964CA90671155C0099215A,
+                               FF964AA00671153B0099215A,
+                       );
+                       isa = PBXGroup;
+                       name = Frameworks;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+//080
+//081
+//082
+//083
+//084
+//190
+//191
+//192
+//193
+//194
+               19C28FBDFE9D53C911CA2CBB = {
+                       children = (
+                               8DD76F7E0486A8DE00D96B5E,
+                               FF1B691106711383002304DD,
+                               FF1E351306711B5C003DD5BC,
+                       );
+                       isa = PBXGroup;
+                       name = Products;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+//190
+//191
+//192
+//193
+//194
+//8D0
+//8D1
+//8D2
+//8D3
+//8D4
+               8DD76F740486A8DE00D96B5E = {
+                       buildPhases = (
+                               8DD76F750486A8DE00D96B5E,
+                               8DD76F760486A8DE00D96B5E,
+                               8DD76F780486A8DE00D96B5E,
+                               8DD76F7A0486A8DE00D96B5E,
+                               8DD76F7B0486A8DE00D96B5E,
+                       );
+                       buildRules = (
+                       );
+                       buildSettings = {
+                               FRAMEWORK_SEARCH_PATHS = "";
+                               GCC_ENABLE_TRIGRAPHS = NO;
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+                               GCC_PRECOMPILE_PREFIX_HEADER = NO;
+                               GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO;
+                               GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+                               GCC_WARN_UNKNOWN_PRAGMAS = NO;
+                               HEADER_SEARCH_PATHS = "";
+                               INSTALL_PATH = "$(HOME)/bin";
+                               LIBRARY_SEARCH_PATHS = "";
+                               OTHER_CFLAGS = "";
+                               OTHER_LDFLAGS = "";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = "dns-sd";
+                               REZ_EXECUTABLE = YES;
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = "-Wmost -Wno-four-char-constants -Wno-unknown-pragmas";
+                               ZERO_LINK = NO;
+                       };
+                       dependencies = (
+                       );
+                       isa = PBXNativeTarget;
+                       name = "dns-sd";
+                       productInstallPath = "$(HOME)/bin";
+                       productName = mDNS;
+                       productReference = 8DD76F7E0486A8DE00D96B5E;
+                       productType = "com.apple.product-type.tool";
+               };
+               8DD76F750486A8DE00D96B5E = {
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       isa = PBXHeadersBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               8DD76F760486A8DE00D96B5E = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               8DD76F770486A8DE00D96B5E,
+                       );
+                       isa = PBXSourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               8DD76F770486A8DE00D96B5E = {
+                       fileRef = 08FB7796FE84155DC02AAC07;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                               );
+                       };
+               };
+               8DD76F780486A8DE00D96B5E = {
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       isa = PBXFrameworksBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               8DD76F7A0486A8DE00D96B5E = {
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       isa = PBXRezBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               8DD76F7B0486A8DE00D96B5E = {
+                       buildActionMask = 8;
+                       dstPath = /usr/share/man/man1/;
+                       dstSubfolderSpec = 0;
+                       files = (
+                       );
+                       isa = PBXCopyFilesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 1;
+               };
+               8DD76F7E0486A8DE00D96B5E = {
+                       explicitFileType = "compiled.mach-o.executable";
+                       includeInIndex = 0;
+                       isa = PBXFileReference;
+                       path = "dns-sd";
+                       refType = 3;
+                       sourceTree = BUILT_PRODUCTS_DIR;
+               };
+//8D0
+//8D1
+//8D2
+//8D3
+//8D4
+//FF0
+//FF1
+//FF2
+//FF3
+//FF4
+               FF1B690C06711383002304DD = {
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       isa = PBXHeadersBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               FF1B690D06711383002304DD = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               FF964DAC067115710099215A,
+                       );
+                       isa = PBXResourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               FF1B690E06711383002304DD = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               FF1B6915067114AF002304DD,
+                       );
+                       isa = PBXSourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               FF1B690F06711383002304DD = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               FF964AA10671153B0099215A,
+                               FF964CAA0671155C0099215A,
+                       );
+                       isa = PBXFrameworksBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               FF1B691006711383002304DD = {
+                       buildPhases = (
+                               FF1B690C06711383002304DD,
+                               FF1B690D06711383002304DD,
+                               FF1B690E06711383002304DD,
+                               FF1B690F06711383002304DD,
+                       );
+                       buildRules = (
+                       );
+                       buildSettings = {
+                               GCC_PRECOMPILE_PREFIX_HEADER = YES;
+                               GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/AppKit.framework/Headers/AppKit.h";
+                               GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+                               GCC_WARN_UNKNOWN_PRAGMAS = NO;
+                               INFOPLIST_FILE = "DNSServiceBrowser-Info.plist";
+                               INSTALL_PATH = "$(USER_APPS_DIR)";
+                               OTHER_CFLAGS = "";
+                               OTHER_LDFLAGS = "-framework Foundation -framework AppKit";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = "DNS Service Browser";
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = "-Wmost";
+                       };
+                       dependencies = (
+                       );
+                       isa = PBXNativeTarget;
+                       name = "DNS Service Browser";
+                       productName = "DNS Service Browser";
+                       productReference = FF1B691106711383002304DD;
+                       productSettingsXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
+<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
+<plist version=\"1.0\">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>DNS Service Browser</string>
+       <key>CFBundleGetInfoString</key>
+       <string></string>
+       <key>CFBundleIconFile</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>com.apple.DNS_Service_Browser</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundlePackageType</key>
+       <string>APPL</string>
+       <key>CFBundleShortVersionString</key>
+       <string></string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>1.0.0d1</string>
+       <key>NSMainNibFile</key>
+       <string>DNSServiceBrowser</string>
+       <key>NSPrincipalClass</key>
+       <string>NSApplication</string>
+</dict>
+</plist>
+";
+                       productType = "com.apple.product-type.application";
+               };
+               FF1B691106711383002304DD = {
+                       explicitFileType = wrapper.application;
+                       includeInIndex = 0;
+                       isa = PBXFileReference;
+                       path = "DNS Service Browser.app";
+                       refType = 3;
+                       sourceTree = BUILT_PRODUCTS_DIR;
+               };
+               FF1B6914067114AF002304DD = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = DNSServiceBrowser.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               FF1B6915067114AF002304DD = {
+                       fileRef = FF1B6914067114AF002304DD;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               FF1E350E06711B5C003DD5BC = {
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       isa = PBXHeadersBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               FF1E350F06711B5C003DD5BC = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               FF1E352606711BD6003DD5BC,
+                       );
+                       isa = PBXResourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               FF1E351006711B5C003DD5BC = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               FF1E351C06711BCF003DD5BC,
+                       );
+                       isa = PBXSourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               FF1E351106711B5C003DD5BC = {
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       isa = PBXFrameworksBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               FF1E351206711B5C003DD5BC = {
+                       buildPhases = (
+                               FF1E350E06711B5C003DD5BC,
+                               FF1E350F06711B5C003DD5BC,
+                               FF1E351006711B5C003DD5BC,
+                               FF1E351106711B5C003DD5BC,
+                       );
+                       buildRules = (
+                       );
+                       buildSettings = {
+                               GCC_PRECOMPILE_PREFIX_HEADER = YES;
+                               GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/AppKit.framework/Headers/AppKit.h";
+                               GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+                               GCC_WARN_UNKNOWN_PRAGMAS = NO;
+                               INFOPLIST_FILE = "DNSServiceRegistration-Info.plist";
+                               INSTALL_PATH = "$(USER_APPS_DIR)";
+                               OTHER_CFLAGS = "";
+                               OTHER_LDFLAGS = "-framework Foundation -framework AppKit";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = "DNS Service Registration";
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = "-Wmost";
+                       };
+                       dependencies = (
+                       );
+                       isa = PBXNativeTarget;
+                       name = "DNS Service Registration";
+                       productName = "DNS Service Registration";
+                       productReference = FF1E351306711B5C003DD5BC;
+                       productSettingsXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
+<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
+<plist version=\"1.0\">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>DNS Service Registration</string>
+       <key>CFBundleGetInfoString</key>
+       <string></string>
+       <key>CFBundleIconFile</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>com.apple.DNS_Service_Registration</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundlePackageType</key>
+       <string>APPL</string>
+       <key>CFBundleShortVersionString</key>
+       <string></string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>1.0.0d1</string>
+       <key>NSMainNibFile</key>
+       <string>DNSServiceRegistration</string>
+       <key>NSPrincipalClass</key>
+       <string>NSApplication</string>
+</dict>
+</plist>
+";
+                       productType = "com.apple.product-type.application";
+               };
+               FF1E351306711B5C003DD5BC = {
+                       explicitFileType = wrapper.application;
+                       includeInIndex = 0;
+                       isa = PBXFileReference;
+                       path = "DNS Service Registration.app";
+                       refType = 3;
+                       sourceTree = BUILT_PRODUCTS_DIR;
+               };
+               FF1E351706711B6A003DD5BC = {
+                       containerPortal = 08FB7793FE84155DC02AAC07;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = FF1E351206711B5C003DD5BC;
+                       remoteInfo = DNSServiceRegistration;
+               };
+               FF1E351806711B6A003DD5BC = {
+                       isa = PBXTargetDependency;
+                       target = FF1E351206711B5C003DD5BC;
+                       targetProxy = FF1E351706711B6A003DD5BC;
+               };
+               FF1E351B06711BCF003DD5BC = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = DNSServiceRegistration.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               FF1E351C06711BCF003DD5BC = {
+                       fileRef = FF1E351B06711BCF003DD5BC;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               FF1E352506711BD6003DD5BC = {
+                       isa = PBXFileReference;
+                       lastKnownFileType = wrapper.nib;
+                       path = DNSServiceRegistration.nib;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               FF1E352606711BD6003DD5BC = {
+                       fileRef = FF1E352506711BD6003DD5BC;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               FF383825067117F300FEF615 = {
+                       containerPortal = 08FB7793FE84155DC02AAC07;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = 8DD76F740486A8DE00D96B5E;
+                       remoteInfo = "dns-sd";
+               };
+               FF383826067117F300FEF615 = {
+                       isa = PBXTargetDependency;
+                       target = 8DD76F740486A8DE00D96B5E;
+                       targetProxy = FF383825067117F300FEF615;
+               };
+               FF383827067117F600FEF615 = {
+                       containerPortal = 08FB7793FE84155DC02AAC07;
+                       isa = PBXContainerItemProxy;
+                       proxyType = 1;
+                       remoteGlobalIDString = FF1B691006711383002304DD;
+                       remoteInfo = "DNS Service Browser";
+               };
+               FF383828067117F600FEF615 = {
+                       isa = PBXTargetDependency;
+                       target = FF1B691006711383002304DD;
+                       targetProxy = FF383827067117F600FEF615;
+               };
+               FF964AA00671153B0099215A = {
+                       isa = PBXFileReference;
+                       lastKnownFileType = wrapper.framework;
+                       name = Foundation.framework;
+                       path = /System/Library/Frameworks/Foundation.framework;
+                       refType = 0;
+                       sourceTree = "<absolute>";
+               };
+               FF964AA10671153B0099215A = {
+                       fileRef = FF964AA00671153B0099215A;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               FF964CA90671155C0099215A = {
+                       isa = PBXFileReference;
+                       lastKnownFileType = wrapper.framework;
+                       name = AppKit.framework;
+                       path = /System/Library/Frameworks/AppKit.framework;
+                       refType = 0;
+                       sourceTree = "<absolute>";
+               };
+               FF964CAA0671155C0099215A = {
+                       fileRef = FF964CA90671155C0099215A;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               FF964DAB067115710099215A = {
+                       isa = PBXFileReference;
+                       lastKnownFileType = wrapper.nib;
+                       path = DNSServiceBrowser.nib;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               FF964DAC067115710099215A = {
+                       fileRef = FF964DAB067115710099215A;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               FFF520490671177900DA3D49 = {
+                       buildPhases = (
+                       );
+                       buildSettings = {
+                               OTHER_CFLAGS = "";
+                               OTHER_LDFLAGS = "";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = "Build All";
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = "-Wmost -Wno-four-char-constants -Wno-unknown-pragmas";
+                       };
+                       dependencies = (
+                               FF383826067117F300FEF615,
+                               FF383828067117F600FEF615,
+                               FF1E351806711B6A003DD5BC,
+                       );
+                       isa = PBXAggregateTarget;
+                       name = "Build All";
+                       productName = "Build All";
+               };
+       };
+       rootObject = 08FB7793FE84155DC02AAC07;
+}
diff --git a/Clients/DNSServiceBrowser-Info.plist b/Clients/DNSServiceBrowser-Info.plist
new file mode 100644 (file)
index 0000000..9ccdde6
--- /dev/null
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>DNS Service Browser</string>
+       <key>CFBundleGetInfoString</key>
+       <string></string>
+       <key>CFBundleIconFile</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>com.apple.DNS_Service_Browser</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundlePackageType</key>
+       <string>APPL</string>
+       <key>CFBundleShortVersionString</key>
+       <string></string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>1.0.0d1</string>
+       <key>NSMainNibFile</key>
+       <string>DNSServiceBrowser</string>
+       <key>NSPrincipalClass</key>
+       <string>NSApplication</string>
+</dict>
+</plist>
index c11cb68c09b0785286989911e6b202f768f1c00d..f2a38c8359d040a55b6608b5cf25c7ba3724776f 100755 (executable)
@@ -3,6 +3,8 @@
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
     Change History (most recent first):
 
 $Log: DNSServiceBrowser.m,v $
+Revision 1.29  2004/06/04 20:58:36  cheshire
+Move DNSServiceBrowser from mDNSMacOSX directory to Clients directory
+
+Revision 1.28  2004/05/18 23:51:26  cheshire
+Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
+
+Revision 1.27  2003/11/19 18:49:48  rpantos
+<rdar://problem/3282283>: couple of little tweaks to previous checkin
+
+Revision 1.26  2003/11/07 19:35:20  rpantos
+<rdar://problem/3282283>/6: Display multiple IP addresses. Connect using host rather than IP addr.
+
+Revision 1.25  2003/10/29 05:16:54  rpantos
+Checkpoint: transition from DNSServiceDiscovery.h to dns_sd.h
+
+Revision 1.24  2003/10/28 02:25:45  rpantos
+<rdar://problem/3282283>/9,10: Cancel pending resolve when focus changes or service disappears.
+
+Revision 1.23  2003/10/28 01:29:15  rpantos
+<rdar://problem/3282283>/4,5: Restructure a bit to make arrow keys work & views behave better.
+
+Revision 1.22  2003/10/28 01:23:27  rpantos
+<rdar://problem/3282283>/11: Bail if mDNS cannot be initialized at startup.
+
+Revision 1.21  2003/10/28 01:19:45  rpantos
+<rdar://problem/3282283>/3,11: Do not put a trailing '.' on service names. Handle PATH for HTTP txtRecords.
+
+Revision 1.20  2003/10/28 01:13:49  rpantos
+<rdar://problem/3282283>/2: Remove filter when displaying browse results.
+
+Revision 1.19  2003/10/28 01:10:14  rpantos
+<rdar://problem/3282283>/1: Change 'compare' to 'caseInsensitiveCompare' to fix sort order.
+
 Revision 1.18  2003/08/12 19:55:07  cheshire
 Update to APSL 2.0
 
  */
 
-#import "BrowserController.h"
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <nameser.h>
+#include <sys/select.h>
 
-#include "arpa/inet.h"
+#import <Cocoa/Cocoa.h>
+#import <DNSServiceDiscovery/DNSServiceDiscovery.h>
 
-void
-MyHandleMachMessage ( CFMachPortRef port, void * msg, CFIndex size, void * info )
+#include <netinet/in.h>
+#include "dns_sd.h"
+
+@class         ServiceController;  // holds state corresponding to outstanding DNSServiceRef
+
+@interface BrowserController : NSObject
 {
-    DNSServiceDiscovery_handleReply(msg);
+    IBOutlet id domainField;
+    IBOutlet id nameField;
+    IBOutlet id typeField;
+
+    IBOutlet id serviceDisplayTable;
+    IBOutlet id typeColumn;
+    IBOutlet id nameColumn;
+    IBOutlet id serviceTypeField;
+    IBOutlet id serviceNameField;
+
+    IBOutlet id hostField;
+    IBOutlet id ipAddressField;
+    IBOutlet id ip6AddressField;
+    IBOutlet id portField;
+    IBOutlet id textField;
+    
+    NSMutableArray *srvtypeKeys;
+    NSMutableArray *srvnameKeys;
+    NSMutableArray *domainKeys;
+    NSMutableArray *nameKeys;
+    NSString *Domain;
+    NSString *SrvType;
+    NSString *SrvName;
+    NSString *Name;
+
+       ServiceController                       *fDomainBrowser;
+       ServiceController                       *fServiceBrowser;
+       ServiceController                       *fServiceResolver;
+       ServiceController                       *fAddressResolver;
+
 }
 
-void browse_reply (
-                   DNSServiceBrowserReplyResultType    resultType,             // One of DNSServiceBrowserReplyResultType
-                   const char          *replyName,
-                   const char          *replyType,
-                   const char          *replyDomain,
-                   DNSServiceDiscoveryReplyFlags       flags,                  // DNS Service Discovery reply flags information
-                   void        *context
-                   )
+- (IBAction)handleDomainClick:(id)sender;
+- (IBAction)handleNameClick:(id)sender;
+- (IBAction)handleTypeClick:(id)sender;
+- (void)notifyTypeSelectionChange:(NSNotification*)note;
+- (void)notifyNameSelectionChange:(NSNotification*)note;
+
+- (IBAction)connect:(id)sender;
+
+- (IBAction)handleTableClick:(id)sender;
+- (IBAction)removeSelected:(id)sender;
+- (IBAction)addNewService:(id)sender;
+
+- (IBAction)update:(NSString *)Type Domain:(NSString *)Domain;
+- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication;
+- (IBAction)loadDomains:(id)sender;
+
+- (void)updateBrowseWithResult:(DNSServiceFlags)flags name:(NSString *)name type:(NSString *)resulttype domain:(NSString *)domain;
+- (void)updateEnumWithResult:(DNSServiceFlags)flags domain:(NSString *)domain;
+- (void)resolveClientWitHost:(NSString *)host port:(uint16_t)port interfaceIndex:(uint32_t)interface txtRecord:(const char*)txtRecord txtLen:(uint16_t)txtLen;
+- (void)updateAddress:(uint16_t)rrtype addr:(const void *)buff addrLen:(uint16_t)addrLen 
+                                               host:(const char*) host interfaceIndex:(uint32_t)interface more:(boolean_t)moreToCome;
+
+- (void)_cancelPendingResolve;
+- (void)_clearResolvedInfo;
+
+@end
+
+// The ServiceController manages cleanup of DNSServiceRef & runloop info for an outstanding request
+@interface ServiceController : NSObject
 {
-    [[NSApp delegate] updateBrowseWithResult:resultType name:[NSString stringWithUTF8String:replyName] type:[NSString stringWithUTF8String:replyType] domain:[NSString stringWithUTF8String:replyDomain] flags:flags];
-    return;
+       DNSServiceRef                   fServiceRef;
+       CFSocketRef                             fSocketRef;
+       CFRunLoopSourceRef              fRunloopSrc;
 }
 
-void enum_reply (
-                 DNSServiceDomainEnumerationReplyResultType    resultType,
-                 const char    *replyDomain,
-                 DNSServiceDiscoveryReplyFlags         flags,
-                 void  *context
-                 )
+- (id) initWithServiceRef:(DNSServiceRef) ref;
+- (boolean_t) addToCurrentRunLoop;
+- (DNSServiceRef) serviceRef;
+- (void) dealloc;
+
+@end // interface ServiceController
+
+
+static void    ProcessSockData( CFSocketRef s, CFSocketCallBackType type, CFDataRef address, const void *data, void *info)
+// CFRunloop callback that notifies dns_sd when new data appears on a DNSServiceRef's socket.
 {
-    [[NSApp delegate] updateEnumWithResult:resultType domain:[NSString stringWithUTF8String:replyDomain] flags:flags];
+       DNSServiceRef           serviceRef = (DNSServiceRef) info;
+       DNSServiceErrorType err = DNSServiceProcessResult( serviceRef);
+       if ( err != kDNSServiceErr_NoError)
+               printf( "DNSServiceProcessResult() returned an error! %d\n", err);
+}
 
-    return;
+static void DomainEnumReply( DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, 
+                                                       DNSServiceErrorType errorCode, const char *replyDomain, void *context )
+// Report newly-discovered domains to the BrowserController.
+{
+       if ( errorCode == kDNSServiceErr_NoError) {
+               BrowserController   *pSelf = (BrowserController*) context;
+               [pSelf updateEnumWithResult:flags domain:[NSString stringWithUTF8String:replyDomain]];
+       } else {
+               printf( "DomainEnumReply got an error! %d\n", errorCode);
+       }
 }
 
-void resolve_reply (
-                    struct sockaddr    *interface,
-                    struct sockaddr    *address,
-                    const char                 *txtRecord,
-                    DNSServiceDiscoveryReplyFlags              flags,
-                    void               *context
-                    )
+static void    ServiceBrowseReply( DNSServiceRef sdRef, DNSServiceFlags servFlags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, 
+                                                               const char *serviceName, const char *regtype, const char *replyDomain, void *context )
+// Report newly-discovered services to the BrowserController.
 {
-    [[NSApp delegate] resolveClientWithInterface:interface address:address txtRecord:[NSString stringWithUTF8String:txtRecord]];
+       if ( errorCode == kDNSServiceErr_NoError) {
+               BrowserController   *pSelf = (BrowserController*) context;
+               [pSelf updateBrowseWithResult:servFlags name:[NSString stringWithUTF8String:serviceName] 
+                                                               type:[NSString stringWithUTF8String:regtype] domain:[NSString stringWithUTF8String:replyDomain]];
+       } else {
+               printf( "ServiceBrowseReply got an error! %d\n", errorCode);
+       }
+}
 
-    return;
+static void ServiceResolveReply( DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, 
+                                                               DNSServiceErrorType errorCode, const char *fullname, const char *hosttarget, uint16_t port, 
+                                                               uint16_t txtLen, const char *txtRecord, void *context )
+// Pass along resolved service info to the BrowserController.
+{
+       if ( errorCode == kDNSServiceErr_NoError) {
+               BrowserController   *pSelf = (BrowserController*) context;
+               [pSelf resolveClientWitHost:[NSString stringWithUTF8String:hosttarget] port:port interfaceIndex:interfaceIndex txtRecord:txtRecord txtLen:txtLen];
+       } else {
+               printf( "ServiceResolveReply got an error! %d\n", errorCode);
+       }
+}
+
+static void    QueryRecordReply( DNSServiceRef DNSServiceRef, DNSServiceFlags flags, uint32_t interfaceIndex, 
+                                                               DNSServiceErrorType errorCode, const char *fullname, uint16_t rrtype, uint16_t rrclass, 
+                                                               uint16_t rdlen, const void *rdata, uint32_t ttl, void *context )
+// DNSServiceQueryRecord callback used to look up IP addresses.
+{
+       BrowserController   *pBrowser = (BrowserController*) context;
+
+       [pBrowser updateAddress:rrtype addr:rdata addrLen:rdlen host:fullname interfaceIndex:interfaceIndex 
+                                               more:((flags & kDNSServiceFlagsMoreComing) != 0)];
 }
 
+
 @implementation BrowserController              //Begin implementation of BrowserController methods
 
 - (void)registerDefaults
 {
     NSMutableDictionary *regDict = [NSMutableDictionary dictionary];
 
-    NSArray *typeArray = [NSArray arrayWithObjects:@"_ftp._tcp.",          @"_tftp._tcp.",
-                                                                                                  @"_ssh._tcp.",          @"_telnet._tcp.",
-                                                                                                  @"_http._tcp.",
-                                                                                                  @"_printer._tcp.",      @"_ipp._tcp.",
-                                                                                                  @"_ichat._tcp.",        @"_eppc._tcp.",
-                                                                                                  @"_afpovertcp._tcp.",   @"_afpovertcp._tcp.",   @"_MacOSXDupSuppress._tcp.", nil];
+    NSArray *typeArray = [NSArray arrayWithObjects:@"_ftp._tcp",          @"_tftp._tcp",
+                                                                                                  @"_ssh._tcp",          @"_telnet._tcp",
+                                                                                                  @"_http._tcp",
+                                                                                                  @"_printer._tcp",      @"_ipp._tcp",
+                                                                                                  @"_ichat._tcp",        @"_eppc._tcp",
+                                                                                                  @"_afpovertcp._tcp",   @"_afpovertcp._tcp",   @"_MacOSXDupSuppress._tcp", nil];
     NSArray *nameArray = [NSArray arrayWithObjects:@"File Transfer (ftp)", @"Trivial File Transfer (tftp)",
                                                       @"Secure Shell (ssh)",  @"Telnet",
                                                       @"Web Server (http)",
@@ -106,7 +242,10 @@ void resolve_reply (
 {
     [self registerDefaults];
 
-    browse_client = nil;
+       fDomainBrowser = nil;
+    fServiceBrowser = nil;
+       fServiceResolver = nil;
+       fAddressResolver = nil;
 
     return [super init];
 }
@@ -126,27 +265,29 @@ void resolve_reply (
 
     [srvtypeKeys retain];                              //Keep arrays in memory until BrowserController closes
     [srvnameKeys retain];                              //Keep arrays in memory until BrowserController closes
-    [typeField setDataSource:self];            //Set application fields' data source to BrowserController
-    [typeField sizeLastColumnToFit];           //and set column sizes to use their whole table's width.
-    [nameField setDataSource:self];
+    [typeField sizeLastColumnToFit];    //Set column sizes to use their whole table's width.
     [nameField sizeLastColumnToFit];
-    [domainField setDataSource:self];
     [domainField sizeLastColumnToFit];
+//  (self is specified as the NSTableViews' data source in the nib)
 
     [nameField setDoubleAction:@selector(connect:)];
 
-    //[srvtypeKeys addObject:@"_ftp._tcp."];   //Add supported protocols and domains to their
+    // Listen for table selection changes
+    [[NSNotificationCenter defaultCenter]   addObserver:self selector:@selector(notifyTypeSelectionChange:) 
+                                            name:NSTableViewSelectionDidChangeNotification object:typeField];
+    [[NSNotificationCenter defaultCenter]   addObserver:self selector:@selector(notifyNameSelectionChange:) 
+                                            name:NSTableViewSelectionDidChangeNotification object:nameField];
+
+    //[srvtypeKeys addObject:@"_ftp._tcp"];    //Add supported protocols and domains to their
     //[srvnameKeys addObject:@"File Transfer (ftp)"];
-    //[srvtypeKeys addObject:@"_printer._tcp."];               //respective arrays
+    //[srvtypeKeys addObject:@"_printer._tcp"];                //respective arrays
     //[srvnameKeys addObject:@"Printer (lpr)"];
-    //[srvtypeKeys addObject:@"_http._tcp."];          //respective arrays
+    //[srvtypeKeys addObject:@"_http._tcp"];           //respective arrays
     //[srvnameKeys addObject:@"Web Server (http)"];
-    //[srvtypeKeys addObject:@"_afp._tcp."];           //respective arrays
+    //[srvtypeKeys addObject:@"_afp._tcp"];            //respective arrays
     //[srvnameKeys addObject:@"AppleShare Server (afp)"];
 
-    [ipAddressField setStringValue:@""];
-    [portField setStringValue:@""];
-    [textField setStringValue:@""];
+       [self _clearResolvedInfo];
 
     [srvtypeKeys addObjectsFromArray:[[NSUserDefaults standardUserDefaults] arrayForKey:@"SrvTypeKeys"]];
     [srvnameKeys addObjectsFromArray:[[NSUserDefaults standardUserDefaults] arrayForKey:@"SrvNameKeys"]];
@@ -205,7 +346,7 @@ void resolve_reply (
     }
     if (theTableView == nameField)
     {
-        return [[nameKeys sortedArrayUsingSelector:@selector(compare:)] objectAtIndex:rowIndex];
+        return [[nameKeys sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)] objectAtIndex:rowIndex];
     }
     if (theTableView == serviceDisplayTable)
     {
@@ -223,115 +364,81 @@ void resolve_reply (
 
 - (IBAction)handleTypeClick:(id)sender         //Handle clicks for Type
 {
-    int index=[sender selectedRow];                            //Find index of selected row
-    if (index==-1) return;                                     //Error checking
-    SrvType = [srvtypeKeys objectAtIndex:index];               //Save desired Type
-    SrvName = [srvnameKeys objectAtIndex:index];               //Save desired Type
-
-    [ipAddressField setStringValue:@""];
-    [portField setStringValue:@""];
-    [textField setStringValue:@""];
-
-    [self update:SrvType Domain:Domain];               //If Type and Domain are set, update records
+    // 3282283: No longer used - update happens in notifyTypeSelectionChange
 }
 
+
 - (IBAction)handleDomainClick:(id)sender                       //Handle clicks for Domain
 {
     int index=[sender selectedRow];                            //Find index of selected row
     if (index==-1) return;                                     //Error checking
     Domain = [domainKeys objectAtIndex:index];                 //Save desired Domain
 
-    [ipAddressField setStringValue:@""];
-    [portField setStringValue:@""];
-    [textField setStringValue:@""];
+    [self _cancelPendingResolve];
 
     if (SrvType!=NULL) [self update:SrvType Domain:Domain];    //If Type and Domain are set, update records
 }
 
 - (IBAction)handleNameClick:(id)sender                         //Handle clicks for Name
 {
-    int index=[sender selectedRow];                            //Find index of selected row
+    // 3282283: No longer used - update happens in notifyNameSelectionChange
+}
+
+- (void)notifyTypeSelectionChange:(NSNotification*)note
+/* Called when the selection of the Type table changes */
+{
+    int index=[[note object] selectedRow];  //Find index of selected row
     if (index==-1) return;                                     //Error checking
-    Name=[[nameKeys sortedArrayUsingSelector:@selector(compare:)] objectAtIndex:index];                        //Save desired name
+    SrvType = [srvtypeKeys objectAtIndex:index];               //Save desired Type
+    SrvName = [srvnameKeys objectAtIndex:index];               //Save desired Type
 
-    {
-        CFMachPortRef           cfMachPort;
-        CFMachPortContext       context;
-        Boolean                 shouldFreeInfo;
-        dns_service_discovery_ref      dns_client;
-        mach_port_t                    port;
-        CFRunLoopSourceRef             rls;
-
-        context.version                 = 1;
-        context.info                    = 0;
-        context.retain                  = NULL;
-        context.release                 = NULL;
-        context.copyDescription            = NULL;
-
-               [ipAddressField setStringValue:@"?"];
-               [portField setStringValue:@"?"];
-               [textField setStringValue:@"?"];
-        // start an enumerator on the local server
-        dns_client = DNSServiceResolverResolve
-            (
-             (char *)[Name UTF8String],
-             (char *)[SrvType UTF8String],
-             (char *)(Domain?[Domain UTF8String]:""),
-             resolve_reply,
-             nil
-             );
-
-        port = DNSServiceDiscoveryMachPort(dns_client);
-
-        if (port) {
-            cfMachPort = CFMachPortCreateWithPort ( kCFAllocatorDefault, port, ( CFMachPortCallBack ) MyHandleMachMessage,&context,&shouldFreeInfo );
-
-            /* Create and add a run loop source for the port */
-            rls = CFMachPortCreateRunLoopSource(NULL, cfMachPort, 0);
-            CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
-            CFRelease(rls);
-        } else {
-            printf("Could not obtain client port\n");
-            return;
-        }
-    }
+    [self _cancelPendingResolve];
+
+    [self update:SrvType Domain:Domain];               //If Type and Domain are set, update records
+}
+
+- (void)notifyNameSelectionChange:(NSNotification*)note
+/* Called when the selection of the Name table changes */
+{
+    int index=[[note object] selectedRow];  //Find index of selected row
+
+    [self _cancelPendingResolve];           // Cancel any pending Resolve for any table selection change
+
+    if (index==-1) {
+               Name = nil;             // Name may no longer point to a list member
+               return;
+       }
+    Name=[[nameKeys sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)] objectAtIndex:index];                 //Save desired name
+
+       [self _clearResolvedInfo];
+
+       DNSServiceRef           serviceRef;
+       DNSServiceErrorType err;
+       err = DNSServiceResolve ( &serviceRef, (DNSServiceFlags) 0, 0, (char *)[Name UTF8String], (char *)[SrvType UTF8String], 
+                                                       (char *)(Domain?[Domain UTF8String]:""), ServiceResolveReply, self);
+       if ( kDNSServiceErr_NoError == err) {
+               fServiceResolver = [[ServiceController alloc] initWithServiceRef:serviceRef];
+               [fServiceResolver addToCurrentRunLoop];
+       }
 }
 
 - (IBAction)loadDomains:(id)sender
 {
-    CFMachPortRef           cfMachPort;
-    CFMachPortContext       context;
-    Boolean                 shouldFreeInfo;
-    dns_service_discovery_ref  dns_client;
-    mach_port_t                        port;
-    CFRunLoopSourceRef         rls;
-
-    context.version                 = 1;
-    context.info                    = 0;
-    context.retain                  = NULL;
-    context.release                 = NULL;
-    context.copyDescription        = NULL;
-
-    // start an enumerator on the local server
-    dns_client =  DNSServiceDomainEnumerationCreate
-        (
-         0,
-         enum_reply,
-         nil
-         );
-
-    port = DNSServiceDiscoveryMachPort(dns_client);
-
-    if (port) {
-        cfMachPort = CFMachPortCreateWithPort ( kCFAllocatorDefault, port, ( CFMachPortCallBack ) MyHandleMachMessage,&context,&shouldFreeInfo );
-
-        /* Create and add a run loop source for the port */
-        rls = CFMachPortCreateRunLoopSource(NULL, cfMachPort, 0);
-        CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
-        CFRelease(rls);
-    } else {
-        printf("Could not obtain client port\n");
-        return;
+    DNSServiceErrorType err;
+       DNSServiceRef           serviceRef;
+
+       err = DNSServiceEnumerateDomains( &serviceRef, kDNSServiceFlagsBrowseDomains, 0, DomainEnumReply, self);
+       if ( kDNSServiceErr_NoError == err) {
+               fDomainBrowser = [[ServiceController alloc] initWithServiceRef:serviceRef];
+               [fDomainBrowser addToCurrentRunLoop];
+       }
+   else {
+        NSAlert *alert = [NSAlert alertWithMessageText:@"Could not connect to mDNSResponder!"
+                        defaultButton:@"Quit" alternateButton:nil otherButton:nil informativeTextWithFormat:
+                        @"Check to see if mDNSResponder is still running."];
+        if ( alert != NULL)
+            [alert runModal];
+        exit( err);
     }
 }
 
@@ -340,6 +447,8 @@ void resolve_reply (
     const char * DomainC;
     const char * TypeC=[theType UTF8String];           //Type in C string format
 
+    DNSServiceErrorType err = kDNSServiceErr_NoError;
+
     if (theDomain) {
         DomainC = [theDomain UTF8String];      //Domain in C string format
     } else {
@@ -350,49 +459,18 @@ void resolve_reply (
     [nameField reloadData];            //Reload (redraw) names to show the old data is gone
 
     // get rid of the previous browser if one exists
-    if (browse_client) {
-        DNSServiceDiscoveryDeallocate(browse_client);
-        browse_client = nil;
+    if ( fServiceBrowser != nil) {
+               [fServiceBrowser release];
+        fServiceBrowser = nil;
     }
 
     // now create a browser to return the values for the nameField ...
-    {
-        CFMachPortRef           cfMachPort;
-        CFMachPortContext       context;
-        Boolean                 shouldFreeInfo;
-        mach_port_t                    port;
-        CFRunLoopSourceRef             rls;
-
-        context.version                 = 1;
-        context.info                    = 0;
-        context.retain                  = NULL;
-        context.release                 = NULL;
-        context.copyDescription            = NULL;
-
-        // start an enumerator on the local server
-        browse_client = DNSServiceBrowserCreate
-            (
-             (char *)TypeC,
-             (char *)DomainC,
-             browse_reply,
-             nil
-             );
-
-        port = DNSServiceDiscoveryMachPort(browse_client);
-
-        if (port) {
-            cfMachPort = CFMachPortCreateWithPort ( kCFAllocatorDefault, port, ( CFMachPortCallBack ) MyHandleMachMessage,&context,&shouldFreeInfo );
-
-            /* Create and add a run loop source for the port */
-            rls = CFMachPortCreateRunLoopSource(NULL, cfMachPort, 0);
-            CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
-            CFRelease(rls);
-        } else {
-            printf("Could not obtain client port\n");
-            return;
-        }
-    }
-
+       DNSServiceRef           serviceRef;
+       err = DNSServiceBrowse( &serviceRef, (DNSServiceFlags) 0, 0, TypeC, DomainC, ServiceBrowseReply, self);
+       if ( kDNSServiceErr_NoError == err) {
+               fServiceBrowser = [[ServiceController alloc] initWithServiceRef:serviceRef];
+               [fServiceBrowser addToCurrentRunLoop];
+       }
 }
 
 
@@ -407,13 +485,12 @@ void resolve_reply (
     return YES;
 }
 
-- (void)updateEnumWithResult:(int)resultType domain:(NSString *)domain flags:(int)flags
+- (void)updateEnumWithResult:(DNSServiceFlags)flags domain:(NSString *)domain
 {
-    // new domain received
-    if (DNSServiceDomainEnumerationReplyAddDomain == resultType || DNSServiceDomainEnumerationReplyAddDomainDefault == resultType) {
+    if ( ( flags & kDNSServiceFlagsAdd) != 0) {    // new domain received
         // add the domain to the list
         [domainKeys addObject:domain];
-    } else {
+    } else if (!(flags & kDNSServiceFlagsAdd)) {
         // remove the domain from the list
         NSEnumerator *dmnEnum = [domainKeys objectEnumerator];
         NSString *aDomain = nil;
@@ -427,70 +504,165 @@ void resolve_reply (
     }
     // update the domain table
     [domainField reloadData];
+
+       // Terminate the enumeration once the last domain is delivered.
+       if ( ( flags & kDNSServiceFlagsMoreComing) == 0) {
+               [fDomainBrowser release];
+               fDomainBrowser = nil;
+       }
+
+       // At some point, we may want to support a TableView for domain browsing. For now, just pick first domain that comes up.
+       if ( Domain == nil)
+               Domain = [domain retain];
+
     return;
 }
 
 
 
-- (void)updateBrowseWithResult:(int)type name:(NSString *)name type:(NSString *)resulttype domain:(NSString *)domain flags:(int)flags
+- (void)updateBrowseWithResult:(DNSServiceFlags)flags name:(NSString *)name type:(NSString *)resulttype domain:(NSString *)domain
 {
 
     //NSLog(@"Received result %@ %@ %@ %d", name, resulttype, domain, type);
 
-    if (([domain isEqualToString:Domain] || [domain isEqualToString:@"local."]) && [resulttype isEqualToString:SrvType]) {
+    if (!(flags & kDNSServiceFlagsAdd)) {
+        if ([nameKeys containsObject:name]) {
+            [nameKeys removeObject:name];
 
-        if (type == DNSServiceBrowserReplyRemoveInstance) {
-            if ([nameKeys containsObject:name]) {
-                [nameKeys removeObject:name];
-            }
+            // 3282283: Cancel pending browse if object goes away.
+            if ( [name isEqualToString:Name])
+                [nameField deselectAll:self];
         }
-        if (type == DNSServiceBrowserReplyAddInstance) {
-            if (![nameKeys containsObject:name]) {
-                [nameKeys addObject:name];
-            }
+    }
+       else if ( ( flags & kDNSServiceFlagsAdd) != 0) {
+        if (![nameKeys containsObject:name]) {
+            [nameKeys addObject:name];
         }
-
-               // If not expecting any more data, then reload (redraw) Name TableView with newly found data
-               if ((flags & kDNSServiceDiscoveryMoreRepliesImmediately) == 0)
-                       [nameField reloadData];
     }
+
+    // If not expecting any more data, then reload (redraw) Name TableView with newly found data
+    if ((flags & kDNSServiceFlagsMoreComing) == 0)
+        [nameField reloadData];
     return;
 }
 
-- (void)resolveClientWithInterface:(struct sockaddr *)interface address:(struct sockaddr *)address txtRecord:(NSString *)txtRecord
+- (void)resolveClientWitHost:(NSString *)host port:(uint16_t)port interfaceIndex:(uint32_t)interface 
+                                                       txtRecord:(const char*)txtRecord txtLen:(uint16_t)txtLen
+/* Display resolved information about the selected service. */
 {
-       if (address->sa_family != AF_INET) return; // For now we only handle IPv4
-    //printf("interface length = %d, port = %d, family = %d, address = %s\n", ((struct sockaddr_in *)interface)->sin_len, ((struct sockaddr_in *)interface)->sin_port, ((struct sockaddr_in *)interface)->sin_family, inet_ntoa(((struct in_addr)((struct sockaddr_in *)interface)->sin_addr)));
-    //printf("address length = %d, port = %d, family = %d, address = %s\n", ((struct sockaddr_in *)address)->sin_len, ((struct sockaddr_in *)address)->sin_port, ((struct sockaddr_in *)address)->sin_family, inet_ntoa(((struct in_addr)((struct sockaddr_in *)address)->sin_addr)));
-    NSString *ipAddr = [NSString stringWithCString:inet_ntoa(((struct in_addr)((struct sockaddr_in *)address)->sin_addr))];
-    int port = ((struct sockaddr_in *)address)->sin_port;
-
-    [ipAddressField setStringValue:ipAddr];
+       DNSServiceErrorType err;
+       DNSServiceRef           serviceRef;
+
+       // Start an async lookup for IPv4 & IPv6 addresses
+       if ( fAddressResolver != nil) {
+               [fAddressResolver release];
+               fAddressResolver = nil;
+       }
+       err = DNSServiceQueryRecord( &serviceRef, (DNSServiceFlags) 0, interface, [host UTF8String], 
+                                                               ns_t_a, ns_c_in, QueryRecordReply, self);
+       if ( err == kDNSServiceErr_NoError) {
+               fAddressResolver = [[ServiceController alloc] initWithServiceRef:serviceRef];
+               [fAddressResolver addToCurrentRunLoop];
+       }
+
+    [hostField setStringValue:host];
     [portField setIntValue:port];
-    [textField setStringValue:txtRecord];
 
-    return;
+       // kind of a hack: munge txtRecord so it's human-readable
+       if ( txtLen > 0) {
+               char    *readableText = (char*) malloc( txtLen);
+               if ( readableText != nil) {
+                       ByteCount   index, subStrLen;
+                       memcpy( readableText, txtRecord, txtLen);
+                       for ( index=0; index < txtLen - 1; index += subStrLen + 1) {
+                               subStrLen = readableText[ index];
+                               readableText[ index] = '\n';
+                       }
+                       [textField setStringValue:[NSString stringWithCString:&readableText[1] length:txtLen - 1]];
+                       free( readableText);
+               }
+       }
+}
+
+- (void)updateAddress:(uint16_t)rrtype  addr:(const void *)buff addrLen:(uint16_t)addrLen 
+                                               host:(const char*) host interfaceIndex:(uint32_t)interface more:(boolean_t)moreToCome
+/* Update address field(s) with info obtained by fAddressResolver. */
+{
+       if ( rrtype == ns_t_a) {                // IPv4
+               char    addrBuff[256];
+               inet_ntop( AF_INET, buff, addrBuff, sizeof addrBuff);
+               strcat( addrBuff, " ");
+               [ipAddressField setStringValue:[NSString stringWithFormat:@"%@%s", [ipAddressField stringValue], addrBuff]];
+
+               if ( !moreToCome) {
+                       [fAddressResolver release];
+                       fAddressResolver = nil;
+       
+                       // After we find v4 we look for v6
+                       DNSServiceRef           serviceRef;
+                       DNSServiceErrorType err;
+                       err = DNSServiceQueryRecord( &serviceRef, (DNSServiceFlags) 0, interface, host, 
+                                                                       ns_t_aaaa, ns_c_in, QueryRecordReply, self);
+                       if ( err == kDNSServiceErr_NoError) {
+                               fAddressResolver = [[ServiceController alloc] initWithServiceRef:serviceRef];
+                               [fAddressResolver addToCurrentRunLoop];
+                       }
+               }
+       }
+       else if ( rrtype == ns_t_aaaa)  // IPv6
+       {
+               char    addrBuff[256];
+               inet_ntop( AF_INET6, buff, addrBuff, sizeof addrBuff);
+               strcat( addrBuff, " ");
+               [ip6AddressField setStringValue:[NSString stringWithFormat:@"%@%s", [ip6AddressField stringValue], addrBuff]];
+
+               if ( !moreToCome) {
+                       [fAddressResolver release];
+                       fAddressResolver = nil;
+               }
+       }
 }
 
+
 - (void)connect:(id)sender
 {
-    NSString *ipAddr = [ipAddressField stringValue];
+    NSString *host = [hostField stringValue];
     int port = [portField intValue];
     NSString *txtRecord = [textField stringValue];
 
     if (!txtRecord) txtRecord = @"";
 
-    if (!ipAddr || !port) return;
+    if (!host || !port) return;
 
-    if      ([SrvType isEqualToString:@"_ftp._tcp."])        [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"ftp://%@:%d/",    ipAddr, port]]];
-    else if ([SrvType isEqualToString:@"_tftp._tcp."])       [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"tftp://%@:%d/",   ipAddr, port]]];
-    else if ([SrvType isEqualToString:@"_ssh._tcp."])        [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"ssh://%@:%d/",    ipAddr, port]]];
-    else if ([SrvType isEqualToString:@"_telnet._tcp."])     [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"telnet://%@:%d/", ipAddr, port]]];
-    else if ([SrvType isEqualToString:@"_http._tcp."])       [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"http://%@:%d",    ipAddr, port]]];
-    else if ([SrvType isEqualToString:@"_printer._tcp."])    [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"lpr://%@:%d/",    ipAddr, port]]];
-    else if ([SrvType isEqualToString:@"_ipp._tcp."])        [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"ipp://%@:%d/",    ipAddr, port]]];
-    else if ([SrvType isEqualToString:@"_afpovertcp._tcp."]) [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"afp://%@:%d/",    ipAddr, port]]];
-    else if ([SrvType isEqualToString:@"_smb._tcp."])        [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"smb://%@:%d/",    ipAddr, port]]];
+    if ([SrvType isEqualToString:@"_http._tcp"])
+    {
+        NSString    *pathDelim = @"path=";
+               NSRange         where;
+
+        // If the TXT record specifies a path, extract it.
+               where = [txtRecord rangeOfString:pathDelim options:NSCaseInsensitiveSearch];
+        if ( where.length)
+        {
+                       NSRange         targetRange = { where.location + where.length, [txtRecord length] - where.location - where.length };
+                       NSRange         endDelim = [txtRecord rangeOfString:@"\n" options:kNilOptions range:targetRange];
+                       
+                       if ( endDelim.length)   // if a delimiter was found, truncate the target range
+                               targetRange.length = endDelim.location - targetRange.location;
+
+            NSString    *path = [txtRecord substringWithRange:targetRange];
+            [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"http://%@:%d%@", host, port, path]]];
+        }
+        else
+            [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"http://%@:%d", host, port]]];
+    }
+    else if ([SrvType isEqualToString:@"_ftp._tcp"])        [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"ftp://%@:%d/",    host, port]]];
+    else if ([SrvType isEqualToString:@"_tftp._tcp"])       [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"tftp://%@:%d/",   host, port]]];
+    else if ([SrvType isEqualToString:@"_ssh._tcp"])        [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"ssh://%@:%d/",    host, port]]];
+    else if ([SrvType isEqualToString:@"_telnet._tcp"])     [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"telnet://%@:%d/", host, port]]];
+    else if ([SrvType isEqualToString:@"_printer._tcp"])    [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"lpr://%@:%d/",    host, port]]];
+    else if ([SrvType isEqualToString:@"_ipp._tcp"])        [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"ipp://%@:%d/",    host, port]]];
+    else if ([SrvType isEqualToString:@"_afpovertcp._tcp"]) [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"afp://%@:%d/",    host, port]]];
+    else if ([SrvType isEqualToString:@"_smb._tcp"])        [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"smb://%@:%d/",    host, port]]];
 
     return;
 }
@@ -522,10 +694,16 @@ void resolve_reply (
 - (IBAction)addNewService:(id)sender
 {
     // add new entries from the edit fields to the arrays for the defaults
+    NSString  *newType = [serviceTypeField stringValue];
+    NSString  *newName = [serviceNameField stringValue];
+
+    // 3282283: trim trailing '.' from service type field
+    if ([newType length] && [newType hasSuffix:@"."])
+        newType = [newType substringToIndex:[newType length] - 1];
 
-    if ([[serviceTypeField stringValue] length] && [[serviceNameField stringValue] length]) {
-        [srvtypeKeys addObject:[serviceTypeField stringValue]];
-        [srvnameKeys addObject:[serviceNameField stringValue]];
+    if ([newType length] && [newName length]) {
+        [srvtypeKeys addObject:newType];
+        [srvnameKeys addObject:newName];
 
         [[NSUserDefaults standardUserDefaults] setObject:srvtypeKeys forKey:@"SrvTypeKeys"];
         [[NSUserDefaults standardUserDefaults] setObject:srvnameKeys forKey:@"SrvNameKeys"];
@@ -533,9 +711,94 @@ void resolve_reply (
         [typeField reloadData];
         [serviceDisplayTable reloadData];
     }
+}
+
+- (void)_cancelPendingResolve
+// If there a a Resolve outstanding, cancel it.
+{
+       if ( fAddressResolver != nil) {
+               [fAddressResolver release];
+               fAddressResolver = nil;
+       }
+
+       if ( fServiceResolver != nil) {
+               [fServiceResolver release];
+               fServiceResolver = nil;
+       }
+
+       [self _clearResolvedInfo];
+}
+
+- (void)_clearResolvedInfo
+// Erase the display of resolved info.
+{
+       [hostField setStringValue:@""];
+       [ipAddressField setStringValue:@""];
+       [ip6AddressField setStringValue:@""];
+       [portField setStringValue:@""];
+       [textField setStringValue:@""];
+}
+
+@end // implementation BrowserController
+
+
+@implementation ServiceController : NSObject
+{
+       DNSServiceRef                   fServiceRef;
+       CFSocketRef                             fSocketRef;
+       CFRunLoopSourceRef              fRunloopSrc;
+}
 
+- (id) initWithServiceRef:(DNSServiceRef) ref
+{
+       [super init];
+       fServiceRef = ref;
+       return self;
+}
+
+- (boolean_t) addToCurrentRunLoop
+/* Add the service to the current runloop. Returns non-zero on success. */
+{
+       CFSocketContext                 ctx = { 1, (void*) fServiceRef, nil, nil, nil };
+
+       fSocketRef = CFSocketCreateWithNative( kCFAllocatorDefault, DNSServiceRefSockFD( fServiceRef), 
+                                                                               kCFSocketReadCallBack, ProcessSockData, &ctx);
+       if ( fSocketRef != nil)
+               fRunloopSrc = CFSocketCreateRunLoopSource( kCFAllocatorDefault, fSocketRef, 1);
+       if ( fRunloopSrc != nil)
+               CFRunLoopAddSource( CFRunLoopGetCurrent(), fRunloopSrc, kCFRunLoopDefaultMode);
+       else
+               printf("Could not listen to runloop socket\n");
+
+       return fRunloopSrc != nil;
+}
+
+- (DNSServiceRef) serviceRef
+{
+       return fServiceRef;
 }
 
+- (void) dealloc
+/* Remove service from runloop, deallocate service and associated resources */
+{
+       if ( fSocketRef != nil) {
+               CFSocketInvalidate( fSocketRef);
+               CFRelease( fSocketRef);
+       }
+
+       if ( fRunloopSrc != nil) {
+               CFRunLoopRemoveSource( CFRunLoopGetCurrent(), fRunloopSrc, kCFRunLoopDefaultMode);
+               CFRelease( fRunloopSrc);
+       }
 
+       DNSServiceRefDeallocate( fServiceRef);
+
+       [super dealloc];
+}
 
-@end
\ No newline at end of file
+@end // implementation ServiceController
+
+int main(int argc, const char *argv[])
+{
+    return NSApplicationMain(argc, argv);
+}
index 2668d5d0f7505136d8e5d01d0a58cb2ad5306804..f5d5e98c34c44fb4a0155789d3079901ba0b474e 100644 (file)
@@ -4,7 +4,6 @@
             ACTIONS = {
                 addNewService = id; 
                 connect = id; 
-                editDomains = id; 
                 handleDomainClick = id; 
                 handleNameClick = id; 
                 handleTableClick = id; 
@@ -15,9 +14,9 @@
             CLASS = BrowserController; 
             LANGUAGE = ObjC; 
             OUTLETS = {
-                domainEditField = id; 
                 domainField = id; 
-                domainWindow = id; 
+                hostField = id; 
+                ip6AddressField = id; 
                 ipAddressField = id; 
                 nameColumn = id; 
                 nameField = id; 
index e31cf4cfff12311ee267f4c0302a7e57ee7afaf7..ffdf970ab8b8dd8d0535270d054005c29eb7485f 100644 (file)
@@ -3,20 +3,20 @@
 <plist version="1.0">
 <dict>
        <key>IBDocumentLocation</key>
-       <string>14 102 356 240 0 0 1152 746 </string>
+       <string>257 25 522 680 0 0 1280 1002 </string>
        <key>IBEditorPositions</key>
        <dict>
                <key>29</key>
                <string>22 474 271 44 0 0 1152 746 </string>
        </dict>
        <key>IBFramework Version</key>
-       <string>273.0</string>
+       <string>349.0</string>
        <key>IBOpenObjects</key>
        <array>
                <integer>220</integer>
                <integer>201</integer>
        </array>
        <key>IBSystem Version</key>
-       <string>6C35</string>
+       <string>7B85</string>
 </dict>
 </plist>
index b330188906e31390fc577041682f1d3332a25082..3cebce38cee6e21bf38eb5ad455335fa409a594c 100644 (file)
Binary files a/Clients/DNSServiceBrowser.nib/objects.nib and b/Clients/DNSServiceBrowser.nib/objects.nib differ
diff --git a/Clients/DNSServiceReg.m b/Clients/DNSServiceReg.m
deleted file mode 100644 (file)
index 7efd864..0000000
+++ /dev/null
@@ -1,247 +0,0 @@
-/*
- * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- * 
- * @APPLE_LICENSE_HEADER_END@
-
-    Change History (most recent first):
-
-$Log: DNSServiceReg.m,v $
-Revision 1.13  2003/08/12 19:55:07  cheshire
-Update to APSL 2.0
-
- */
-
-#import "RegistrationController.h"
-
-#include <DNSServiceDiscovery/DNSServiceDiscovery.h>
-
-void reg_reply (
-                int            errorCode,
-                void           *context
-                )
-{
-    // registration reply
-    printf("Got a reply from the server with error %d\n", errorCode);
-    return;
-}
-
-void
-MyHandleMachMessage ( CFMachPortRef port, void * msg, CFIndex size, void * info )
-{
-    DNSServiceDiscovery_handleReply(msg);
-}
-
-@implementation RegistrationController
-
-- (void)registerDefaults
-{
-    NSMutableDictionary *regDict = [NSMutableDictionary dictionary];
-
-    NSArray *typeArray   = [NSArray arrayWithObjects:@"_ftp._tcp.",    @"_ssh._tcp.",  @"_tftp._tcp.",        @"_http._tcp.",      @"_printer._tcp.",  @"_afpovertcp._tcp.",         nil];
-    NSArray *nameArray   = [NSArray arrayWithObjects:@"My ftp Server", @"My Computer", @"Testing Boot Image", @"A Web Server",     @"SteveÕs Printer", @"Company AppleShare Server", nil];
-    NSArray *portArray   = [NSArray arrayWithObjects:@"21",            @"22",          @"69",                 @"80",               @"515",             @"548",                       nil];
-    NSArray *domainArray = [NSArray arrayWithObjects:@"",              @"",            @"",                   @"",                 @"",                @"",                          nil];
-    NSArray *textArray   = [NSArray arrayWithObjects:@"",              @"",            @"image=mybootimage",  @"path=/index.html", @"rn=lpt1",         @"Vol=Public",                nil];
-
-    [regDict setObject:typeArray forKey:@"SrvTypeKeys"];
-    [regDict setObject:nameArray forKey:@"SrvNameKeys"];
-    [regDict setObject:portArray forKey:@"SrvPortKeys"];
-    [regDict setObject:domainArray forKey:@"SrvDomainKeys"];
-    [regDict setObject:textArray forKey:@"SrvTextKeys"];
-
-    [[NSUserDefaults standardUserDefaults] registerDefaults:regDict];
-}
-
-- (id)init
-{
-    srvtypeKeys = [[NSMutableArray array] retain];     //Define arrays for Type, Domain, and Name
-    srvnameKeys = [[NSMutableArray array] retain];
-    srvportKeys = [[NSMutableArray array] retain];
-    srvdomainKeys = [[NSMutableArray array] retain];
-    srvtextKeys = [[NSMutableArray array] retain];
-
-    registeredDict = [[NSMutableDictionary alloc] init];
-    
-    [self registerDefaults];
-    return [super init];
-}
-
-- (void)awakeFromNib                           //BrowserController startup procedure
-{
-    [srvtypeKeys addObjectsFromArray:[[NSUserDefaults standardUserDefaults] arrayForKey:@"SrvTypeKeys"]];
-    [srvnameKeys addObjectsFromArray:[[NSUserDefaults standardUserDefaults] arrayForKey:@"SrvNameKeys"]];
-    [srvportKeys addObjectsFromArray:[[NSUserDefaults standardUserDefaults] arrayForKey:@"SrvPortKeys"]];
-    [srvdomainKeys addObjectsFromArray:[[NSUserDefaults standardUserDefaults] arrayForKey:@"SrvDomainKeys"]];
-    [srvtextKeys addObjectsFromArray:[[NSUserDefaults standardUserDefaults] arrayForKey:@"SrvTextKeys"]];
-
-    [serviceDisplayTable reloadData];                          //Reload (redraw) data in fields
-
-}
-
-
-
- - (IBAction)registerService:(id)sender
-{
-    int selectedRow = [serviceDisplayTable selectedRow];
-    CFRunLoopSourceRef rls;
-    uint16_t   registerPort;
-    CFMachPortRef           cfMachPort;
-    CFMachPortContext       context;
-    Boolean                 shouldFreeInfo;
-    dns_service_discovery_ref  dns_client;
-    mach_port_t port;
-
-    if (selectedRow < 0) {
-        return;
-    }
-
-    context.version                 = 1;
-    context.info                    = 0;
-    context.retain                  = NULL;
-    context.release                 = NULL;
-    context.copyDescription        = NULL;
-
-    registerPort = [[srvportKeys objectAtIndex:selectedRow] intValue];
-    
-    dns_client = DNSServiceRegistrationCreate
-        (
-            [[srvnameKeys objectAtIndex:selectedRow] UTF8String],
-            [[srvtypeKeys objectAtIndex:selectedRow] UTF8String],
-            [[srvdomainKeys objectAtIndex:selectedRow] UTF8String],
-            registerPort,
-            [[srvtextKeys objectAtIndex:selectedRow] UTF8String],
-            reg_reply,
-            nil
-            );
-            
-    port = DNSServiceDiscoveryMachPort(dns_client);
-
-    if (port) {
-
-        //printf("port is %d\n", port);
-
-        cfMachPort = CFMachPortCreateWithPort ( kCFAllocatorDefault, port, ( CFMachPortCallBack ) MyHandleMachMessage,&context,&shouldFreeInfo );
-
-        rls = CFMachPortCreateRunLoopSource(NULL, cfMachPort, 0);
-        CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
-        CFRelease(rls);
-        [registeredDict setObject:[NSNumber numberWithUnsignedInt:(unsigned int)dns_client] forKey:[srvtypeKeys objectAtIndex:selectedRow]];
-    } else {
-        printf("Could not obtain client port\n");
-    }
-
-}
-
-- (IBAction)unregisterService:(id)sender
-{
-    int selectedRow = [serviceDisplayTable selectedRow];
-    NSString *key = [srvtypeKeys objectAtIndex:selectedRow];
-
-    NSNumber *refPtr = [registeredDict objectForKey:key];
-    dns_service_discovery_ref ref = (dns_service_discovery_ref)[refPtr unsignedIntValue];
-
-    if (ref) {
-        DNSServiceDiscoveryDeallocate(ref);
-        [registeredDict removeObjectForKey:key];
-    }
-}
-
--(void)tableView:(NSTableView *)theTableView setObjectValue:(id)object forTableColumn:(NSTableColumn *)tableColumn row:(int)row
-{
-    if (row<0) return;
-}
-
-- (int)numberOfRowsInTableView:(NSTableView *)theTableView     //Begin mandatory TableView methods
-{
-    return [srvtypeKeys count];
-}
-
-- (id)tableView:(NSTableView *)theTableView objectValueForTableColumn:(NSTableColumn *)theColumn row:(int)rowIndex
-{
-    if (theColumn == typeColumn) {
-        return [srvtypeKeys objectAtIndex:rowIndex];
-    }
-    if (theColumn == nameColumn) {
-        return [srvnameKeys objectAtIndex:rowIndex];
-    }
-    if (theColumn == portColumn) {
-        return [srvportKeys objectAtIndex:rowIndex];
-    }
-    if (theColumn == domainColumn) {
-        return [srvdomainKeys objectAtIndex:rowIndex];
-    }
-    if (theColumn == textColumn) {
-        return [srvtextKeys objectAtIndex:rowIndex];
-    }
-    
-    return(0);
-}                                              //End of mandatory TableView methods
-
-- (IBAction)removeSelected:(id)sender
-{
-    // remove the selected row and force a refresh
-
-    int selectedRow = [serviceDisplayTable selectedRow];
-
-    if (selectedRow) {
-
-        [srvtypeKeys removeObjectAtIndex:selectedRow];
-        [srvnameKeys removeObjectAtIndex:selectedRow];
-        [srvportKeys removeObjectAtIndex:selectedRow];
-        [srvdomainKeys removeObjectAtIndex:selectedRow];
-        [srvtextKeys removeObjectAtIndex:selectedRow];
-
-        [[NSUserDefaults standardUserDefaults] setObject:srvtypeKeys forKey:@"SrvTypeKeys"];
-        [[NSUserDefaults standardUserDefaults] setObject:srvnameKeys forKey:@"SrvNameKeys"];
-        [[NSUserDefaults standardUserDefaults] setObject:srvportKeys forKey:@"SrvPortKeys"];
-        [[NSUserDefaults standardUserDefaults] setObject:srvdomainKeys forKey:@"SrvDomainKeys"];
-        [[NSUserDefaults standardUserDefaults] setObject:srvtextKeys forKey:@"SrvTextKeys"];
-        
-        [serviceDisplayTable reloadData];
-    }
-}
-
-- (IBAction)addNewService:(id)sender
-{
-    // add new entries from the edit fields to the arrays for the defaults
-
-    if ([[serviceTypeField stringValue] length] && [[serviceNameField stringValue] length] && [[serviceDomainField stringValue] length]&& [[servicePortField stringValue] length]) {
-        [srvtypeKeys addObject:[serviceTypeField stringValue]];
-        [srvnameKeys addObject:[serviceNameField stringValue]];
-        [srvportKeys addObject:[servicePortField stringValue]];
-        [srvdomainKeys addObject:[serviceDomainField stringValue]];
-        [srvtextKeys addObject:[serviceTextField stringValue]];
-
-        [[NSUserDefaults standardUserDefaults] setObject:srvtypeKeys forKey:@"SrvTypeKeys"];
-        [[NSUserDefaults standardUserDefaults] setObject:srvnameKeys forKey:@"SrvNameKeys"];
-        [[NSUserDefaults standardUserDefaults] setObject:srvportKeys forKey:@"SrvPortKeys"];
-        [[NSUserDefaults standardUserDefaults] setObject:srvdomainKeys forKey:@"SrvDomainKeys"];
-        [[NSUserDefaults standardUserDefaults] setObject:srvtextKeys forKey:@"SrvTextKeys"];
-
-        [serviceDisplayTable reloadData];
-    } else {
-        NSBeep();
-    }
-
-}
-
-
-
-@end
diff --git a/Clients/DNSServiceReg.nib/classes.nib b/Clients/DNSServiceReg.nib/classes.nib
deleted file mode 100644 (file)
index 46f466c..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-{
-    IBClasses = (
-        {CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, 
-        {
-            ACTIONS = {
-                addNewService = id; 
-                registerService = id; 
-                removeSelected = id; 
-                unregisterService = id; 
-            }; 
-            CLASS = RegistrationController; 
-            LANGUAGE = ObjC; 
-            OUTLETS = {
-                domainColumn = NSTableColumn; 
-                nameColumn = NSTableColumn; 
-                portColumn = NSTableColumn; 
-                serviceDisplayTable = NSTableView; 
-                serviceDomainField = NSTextField; 
-                serviceNameField = NSTextField; 
-                servicePortField = NSTextField; 
-                serviceTextField = NSTextField; 
-                serviceTypeField = NSTextField; 
-                textColumn = NSTableColumn; 
-                typeColumn = NSTableColumn; 
-            }; 
-            SUPERCLASS = NSObject; 
-        }
-    ); 
-    IBVersion = 1; 
-}
\ No newline at end of file
diff --git a/Clients/DNSServiceReg.nib/info.nib b/Clients/DNSServiceReg.nib/info.nib
deleted file mode 100644 (file)
index 9d2eb74..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-       <key>IBDocumentLocation</key>
-       <string>32 111 356 240 0 0 1152 746 </string>
-       <key>IBEditorPositions</key>
-       <dict>
-               <key>29</key>
-               <string>103 609 252 44 0 0 1152 746 </string>
-       </dict>
-       <key>IBFramework Version</key>
-       <string>273.0</string>
-       <key>IBOpenObjects</key>
-       <array>
-               <integer>243</integer>
-               <integer>21</integer>
-       </array>
-       <key>IBSystem Version</key>
-       <string>6C30</string>
-</dict>
-</plist>
diff --git a/Clients/DNSServiceReg.nib/objects.nib b/Clients/DNSServiceReg.nib/objects.nib
deleted file mode 100644 (file)
index 705e77d..0000000
Binary files a/Clients/DNSServiceReg.nib/objects.nib and /dev/null differ
diff --git a/Clients/DNSServiceRegistration-Info.plist b/Clients/DNSServiceRegistration-Info.plist
new file mode 100644 (file)
index 0000000..fafaa99
--- /dev/null
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>DNS Service Registration</string>
+       <key>CFBundleGetInfoString</key>
+       <string></string>
+       <key>CFBundleIconFile</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>com.apple.DNS_Service_Registration</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundlePackageType</key>
+       <string>APPL</string>
+       <key>CFBundleShortVersionString</key>
+       <string></string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>1.0.0d1</string>
+       <key>NSMainNibFile</key>
+       <string>DNSServiceRegistration</string>
+       <key>NSPrincipalClass</key>
+       <string>NSApplication</string>
+</dict>
+</plist>
index d58de3c2cf2e462327137e60f27c9623c13540b4..3b50a0740cd500f5ccda3c1e646134f54cdec9a7 100644 (file)
@@ -3,6 +3,8 @@
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
     Change History (most recent first):
 
 $Log: DNSServiceRegistration.m,v $
+Revision 1.15  2004/06/05 02:01:08  cheshire
+Move DNSServiceRegistration from mDNSMacOSX directory to Clients directory
+
+Revision 1.14  2004/03/04 19:20:23  cheshire
+Remove invalid UTF-8 character
+
 Revision 1.13  2003/08/12 19:55:07  cheshire
 Update to APSL 2.0
 
  */
 
-#import "RegistrationController.h"
+#include "dns_sd.h"
+
+@interface RegistrationController : NSObject
+{
+    IBOutlet NSTableColumn     *typeColumn;
+    IBOutlet NSTableColumn     *nameColumn;
+    IBOutlet NSTableColumn     *portColumn;
+    IBOutlet NSTableColumn     *domainColumn;
+    IBOutlet NSTableColumn     *textColumn;
+
+    IBOutlet NSTableView       *serviceDisplayTable;
+
+    IBOutlet NSTextField       *serviceTypeField;
+    IBOutlet NSTextField       *serviceNameField;
+    IBOutlet NSTextField       *servicePortField;
+    IBOutlet NSTextField       *serviceDomainField;
+    IBOutlet NSTextField       *serviceTextField;
+    
+    NSMutableArray             *srvtypeKeys;
+    NSMutableArray             *srvnameKeys;
+    NSMutableArray             *srvportKeys;
+    NSMutableArray             *srvdomainKeys;
+    NSMutableArray             *srvtextKeys;
+
+    NSMutableDictionary                *registeredDict;
+}
 
-#include <DNSServiceDiscovery/DNSServiceDiscovery.h>
+- (IBAction)registerService:(id)sender;
+- (IBAction)unregisterService:(id)sender;
 
-void reg_reply (
-                int            errorCode,
-                void           *context
-                )
+- (IBAction)addNewService:(id)sender;
+- (IBAction)removeSelected:(id)sender;
+
+@end
+
+void reg_reply
+    (
+    DNSServiceRef                       sdRef,
+    DNSServiceFlags                     flags,
+    DNSServiceErrorType                 errorCode,
+    const char                          *name,
+    const char                          *regtype,
+    const char                          *domain,
+    void                                *context
+    )
 {
     // registration reply
     printf("Got a reply from the server with error %d\n", errorCode);
     return;
 }
 
-void
-MyHandleMachMessage ( CFMachPortRef port, void * msg, CFIndex size, void * info )
-{
-    DNSServiceDiscovery_handleReply(msg);
-}
+static void myCFSocketCallBack(CFSocketRef cfs, CFSocketCallBackType CallBackType, CFDataRef address, const void *data, void *context)
+       {
+       DNSServiceProcessResult((DNSServiceRef)context);
+       }
+
+static void addDNSServiceRefToRunLoop(DNSServiceRef ref)
+       {
+       int s = DNSServiceRefSockFD(ref);
+       CFSocketContext myCFSocketContext = { 0, ref, NULL, NULL, NULL };
+       CFSocketRef c = CFSocketCreateWithNative(kCFAllocatorDefault, s, kCFSocketReadCallBack, myCFSocketCallBack, &myCFSocketContext);
+       CFRunLoopSourceRef rls = CFSocketCreateRunLoopSource(kCFAllocatorDefault, c, 0);
+       CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
+       CFRelease(rls);
+       }
+
 
 @implementation RegistrationController
 
@@ -55,7 +110,7 @@ MyHandleMachMessage ( CFMachPortRef port, void * msg, CFIndex size, void * info
     NSMutableDictionary *regDict = [NSMutableDictionary dictionary];
 
     NSArray *typeArray   = [NSArray arrayWithObjects:@"_ftp._tcp.",    @"_ssh._tcp.",  @"_tftp._tcp.",        @"_http._tcp.",      @"_printer._tcp.",  @"_afpovertcp._tcp.",         nil];
-    NSArray *nameArray   = [NSArray arrayWithObjects:@"My ftp Server", @"My Computer", @"Testing Boot Image", @"A Web Server",     @"SteveÕs Printer", @"Company AppleShare Server", nil];
+    NSArray *nameArray   = [NSArray arrayWithObjects:@"My ftp Server", @"My Computer", @"Testing Boot Image", @"A Web Server",     @"Steve's Printer", @"Company AppleShare Server", nil];
     NSArray *portArray   = [NSArray arrayWithObjects:@"21",            @"22",          @"69",                 @"80",               @"515",             @"548",                       nil];
     NSArray *domainArray = [NSArray arrayWithObjects:@"",              @"",            @"",                   @"",                 @"",                @"",                          nil];
     NSArray *textArray   = [NSArray arrayWithObjects:@"",              @"",            @"image=mybootimage",  @"path=/index.html", @"rn=lpt1",         @"Vol=Public",                nil];
@@ -100,53 +155,43 @@ MyHandleMachMessage ( CFMachPortRef port, void * msg, CFIndex size, void * info
  - (IBAction)registerService:(id)sender
 {
     int selectedRow = [serviceDisplayTable selectedRow];
-    CFRunLoopSourceRef rls;
-    uint16_t   registerPort;
-    CFMachPortRef           cfMachPort;
     CFMachPortContext       context;
-    Boolean                 shouldFreeInfo;
-    dns_service_discovery_ref  dns_client;
-    mach_port_t port;
+    DNSServiceRef              dns_client;
 
     if (selectedRow < 0) {
         return;
     }
 
+       NSString *key = [srvtypeKeys objectAtIndex:selectedRow];
+       if ([registeredDict objectForKey:key]) { printf("Already registered\n"); return; }
+
     context.version                 = 1;
     context.info                    = 0;
     context.retain                  = NULL;
     context.release                 = NULL;
     context.copyDescription        = NULL;
+    unsigned char txtbuffer[300];
+       strncpy(txtbuffer+1, [[srvtextKeys objectAtIndex:selectedRow] UTF8String], sizeof(txtbuffer)-1);
+       txtbuffer[0] = strlen(txtbuffer+1);
 
-    registerPort = [[srvportKeys objectAtIndex:selectedRow] intValue];
-    
-    dns_client = DNSServiceRegistrationCreate
+    DNSServiceErrorType err = DNSServiceRegister
         (
+               &dns_client, 0, 0,
             [[srvnameKeys objectAtIndex:selectedRow] UTF8String],
-            [[srvtypeKeys objectAtIndex:selectedRow] UTF8String],
+            [key UTF8String],
             [[srvdomainKeys objectAtIndex:selectedRow] UTF8String],
-            registerPort,
-            [[srvtextKeys objectAtIndex:selectedRow] UTF8String],
+            NULL, htons([[srvportKeys objectAtIndex:selectedRow] intValue]),
+            txtbuffer[0]+1, txtbuffer,
             reg_reply,
             nil
             );
-            
-    port = DNSServiceDiscoveryMachPort(dns_client);
-
-    if (port) {
-
-        //printf("port is %d\n", port);
-
-        cfMachPort = CFMachPortCreateWithPort ( kCFAllocatorDefault, port, ( CFMachPortCallBack ) MyHandleMachMessage,&context,&shouldFreeInfo );
-
-        rls = CFMachPortCreateRunLoopSource(NULL, cfMachPort, 0);
-        CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
-        CFRelease(rls);
-        [registeredDict setObject:[NSNumber numberWithUnsignedInt:(unsigned int)dns_client] forKey:[srvtypeKeys objectAtIndex:selectedRow]];
-    } else {
-        printf("Could not obtain client port\n");
-    }
-
+       if (err)
+               printf("DNSServiceRegister failed %d\n", err);
+       else
+       {
+               addDNSServiceRefToRunLoop(dns_client);
+               [registeredDict setObject:[NSNumber numberWithUnsignedInt:(unsigned int)dns_client] forKey:key];
+       }
 }
 
 - (IBAction)unregisterService:(id)sender
@@ -155,10 +200,10 @@ MyHandleMachMessage ( CFMachPortRef port, void * msg, CFIndex size, void * info
     NSString *key = [srvtypeKeys objectAtIndex:selectedRow];
 
     NSNumber *refPtr = [registeredDict objectForKey:key];
-    dns_service_discovery_ref ref = (dns_service_discovery_ref)[refPtr unsignedIntValue];
+    DNSServiceRef ref = (DNSServiceRef)[refPtr unsignedIntValue];
 
     if (ref) {
-        DNSServiceDiscoveryDeallocate(ref);
+        DNSServiceRefDeallocate(ref);
         [registeredDict removeObjectForKey:key];
     }
 }
@@ -242,6 +287,9 @@ MyHandleMachMessage ( CFMachPortRef port, void * msg, CFIndex size, void * info
 
 }
 
-
-
 @end
+
+int main(int argc, const char *argv[])
+{
+    return NSApplicationMain(argc, argv);
+}
diff --git a/Clients/Java/BrowserApp.java b/Clients/Java/BrowserApp.java
new file mode 100644 (file)
index 0000000..d3805ae
--- /dev/null
@@ -0,0 +1,394 @@
+/*
+ * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+
+$Log: BrowserApp.java,v $
+Revision 1.3  2004/05/26 01:41:58  cheshire
+Pass proper flags to DNSSD.enumerateDomains
+
+Revision 1.2  2004/04/30 21:53:34  rpantos
+Change line endings for CVS.
+
+Revision 1.1  2004/04/30 16:29:35  rpantos
+First checked in.
+
+       BrowserApp demonstrates how to use DNSSD to browse for and resolve services.
+
+       To do:
+       - display resolved TXTRecord
+ */
+
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+import java.text.*;
+import javax.swing.*;
+import javax.swing.event.*;
+
+import com.apple.dnssd.*;
+
+
+class  BrowserApp implements ListSelectionListener, ResolveListener
+{
+       static BrowserApp       app;
+       JFrame                          frame;
+       DomainListModel         domainList;
+       BrowserListModel        servicesList, serviceList;
+       JList                           domainPane, servicesPane, servicePane;
+       DNSSDService            servicesBrowser, serviceBrowser, domainBrowser;
+       JLabel                          hostLabel, portLabel;
+
+       public          BrowserApp()
+       {
+               frame = new JFrame("DNS-SD Service Browser");
+               frame.addWindowListener(new WindowAdapter() {
+                       public void windowClosing(WindowEvent e) {System.exit(0);}
+               });
+
+               domainList = new DomainListModel();
+               servicesList = new ServicesBrowserListModel();
+               serviceList = new BrowserListModel();
+
+               try {
+                       domainBrowser = DNSSD.enumerateDomains( DNSSD.BROWSE_DOMAINS, 0, domainList);
+
+                       servicesBrowser = DNSSD.browse( 0, 0, "_services._mdns._udp.", "", servicesList);
+                       serviceBrowser = null;
+               }
+               catch ( Exception ex) { terminateWithException( ex); }
+
+               this.setupSubPanes( frame.getContentPane());
+               frame.pack();
+               frame.setVisible(true);
+       }
+
+       protected void  setupSubPanes( Container parent)
+       {
+               parent.setLayout( new BoxLayout( parent, BoxLayout.Y_AXIS));
+
+               JPanel browserRow = new JPanel();
+               browserRow.setLayout( new BoxLayout( browserRow, BoxLayout.X_AXIS));
+               domainPane = new JList( domainList);
+               domainPane.addListSelectionListener( this);
+               JScrollPane domainScroller = new JScrollPane( domainPane, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
+               browserRow.add( domainScroller);
+               servicesPane = new JList( servicesList);
+               servicesPane.addListSelectionListener( this);
+               JScrollPane servicesScroller = new JScrollPane( servicesPane, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
+               browserRow.add( servicesScroller);
+               servicePane = new JList( serviceList);
+               servicePane.addListSelectionListener( this);
+               JScrollPane serviceScroller = new JScrollPane( servicePane, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
+               browserRow.add( serviceScroller);
+
+/*
+               JPanel buttonRow = new JPanel();
+               buttonRow.setLayout( new BoxLayout( buttonRow, BoxLayout.X_AXIS));
+               buttonRow.add( Box.createHorizontalGlue());
+               JButton connectButton = new JButton( "Don't Connect");
+               buttonRow.add( connectButton);
+               buttonRow.add( Box.createRigidArea( new Dimension( 16, 0)));
+*/
+
+               JPanel labelRow = new JPanel();
+               labelRow.setLayout( new BoxLayout( labelRow, BoxLayout.X_AXIS));
+               labelRow.add( new JLabel( "  Host: "));
+               hostLabel = new JLabel();
+               labelRow.add( hostLabel);
+               labelRow.add( Box.createRigidArea( new Dimension( 32, 0)));
+               labelRow.add( new JLabel( "Port: "));
+               portLabel = new JLabel();
+               labelRow.add( portLabel);
+               labelRow.add( Box.createHorizontalGlue());
+
+               parent.add( browserRow);
+               parent.add( Box.createRigidArea( new Dimension( 0, 8)));
+               parent.add( labelRow);
+//             parent.add( buttonRow);
+               parent.add( Box.createRigidArea( new Dimension( 0, 16)));
+       }
+
+       public void valueChanged( ListSelectionEvent e)
+       {
+               try {
+                       if ( e.getSource() == domainPane && !e.getValueIsAdjusting())
+                       {
+                               int             newSel = domainPane.getSelectedIndex();
+                               if ( -1 != newSel)
+                               {
+                                       if ( serviceBrowser != null)
+                                               serviceBrowser.stop();
+                                       serviceList.removeAllElements();
+                                       servicesBrowser = DNSSD.browse( 0, 0, "_services._mdns._udp.", "", servicesList);
+                               }
+                       }
+                       else if ( e.getSource() == servicesPane && !e.getValueIsAdjusting())
+                       {
+                               int             newSel = servicesPane.getSelectedIndex();
+                               if ( serviceBrowser != null)
+                                       serviceBrowser.stop();
+                               serviceList.removeAllElements();
+                               if ( -1 != newSel)
+                                       serviceBrowser = DNSSD.browse( 0, 0, servicesList.getNthRegType( newSel), "", serviceList);
+                       }
+                       else if ( e.getSource() == servicePane && !e.getValueIsAdjusting())
+                       {
+                               int             newSel = servicePane.getSelectedIndex();
+
+                               hostLabel.setText( "");
+                               portLabel.setText( "");
+
+                               if ( -1 != newSel)
+                               {
+                                       DNSSD.resolve( 0, serviceList.getNthInterface( newSel), 
+                                                                               serviceList.getNthServiceName( newSel), 
+                                                                               serviceList.getNthRegType( newSel), 
+                                                                               serviceList.getNthDomain( newSel), 
+                                                                               new SwingResolveListener( this));
+                               }
+                       }
+               }
+               catch ( Exception ex) { terminateWithException( ex); }
+       }
+
+       public void     serviceResolved( DNSSDService resolver, int flags, int ifIndex, String fullName, 
+                                                               String hostName, int port, TXTRecord txtRecord)
+       {
+               hostLabel.setText( hostName);
+               portLabel.setText( String.valueOf( port));
+       }
+
+       public void     operationFailed( DNSSDService service, int errorCode)
+       {
+               // handle failure here
+       }
+
+       protected static void   terminateWithException( Exception e)
+       {
+               e.printStackTrace();
+               System.exit( -1);
+       }
+
+    public static void main(String s[]) 
+    {
+               app = new BrowserApp();
+    }
+}
+
+
+class  BrowserListModel extends DefaultListModel implements BrowseListener, Runnable
+{
+       public          BrowserListModel()
+       {
+               addCache = new Vector();
+               removeCache = new Vector();
+       }
+
+       /* The Browser invokes this callback when a service is discovered. */
+       public void     serviceFound( DNSSDService browser, int flags, int ifIndex, 
+                                                       String serviceName, String regType, String domain)
+       {
+               addCache.add( new BrowserListElem( serviceName, domain, regType, ifIndex));
+               if ( ( flags & DNSSD.MORE_COMING) == 0)
+                       this.scheduleOnEventThread();
+       }
+
+       public void     serviceLost( DNSSDService browser, int flags, int ifIndex,
+                                                       String serviceName, String regType, String domain)
+       {
+               removeCache.add( serviceName);
+               if ( ( flags & DNSSD.MORE_COMING) == 0)
+                       this.scheduleOnEventThread();
+       }
+
+       public void     run()
+       {
+               while ( removeCache.size() > 0)
+               {
+                       String  serviceName = (String) removeCache.remove( removeCache.size() - 1);
+                       int             matchInd = this.findMatching( serviceName);     // probably doesn't handle near-duplicates well.
+                       if ( matchInd != -1)
+                               this.removeElementAt( matchInd);
+               }
+               while ( addCache.size() > 0)
+               {
+                       BrowserListElem elem = (BrowserListElem) addCache.remove( addCache.size() - 1);
+                       if ( -1 == this.findMatching( elem.fServiceName))       // probably doesn't handle near-duplicates well.
+                               this.addInSortOrder( elem);
+               }
+       }
+
+       public void     operationFailed( DNSSDService service, int errorCode)
+       {
+               // handle failure here
+       }
+
+       /* The list contains BrowserListElem's */
+       class   BrowserListElem
+       {
+               public  BrowserListElem( String serviceName, String domain, String type, int ifIndex)
+               { fServiceName = serviceName; fDomain = domain; fType = type; fInt = ifIndex; }
+               
+               public String   toString() { return fServiceName; }
+               
+               public String   fServiceName, fDomain, fType;
+               public int              fInt;
+       }
+
+       public String   getNthServiceName( int n)
+       {
+               BrowserListElem sel = (BrowserListElem) this.get( n);
+               return sel.fServiceName;
+       }
+
+       public String   getNthRegType( int n)
+       {
+               BrowserListElem sel = (BrowserListElem) this.get( n);
+               return sel.fType;
+       }
+
+       public String   getNthDomain( int n)
+       {
+               BrowserListElem sel = (BrowserListElem) this.get( n);
+               return sel.fDomain;
+       }
+
+       public int              getNthInterface( int n)
+       {
+               BrowserListElem sel = (BrowserListElem) this.get( n);
+               return sel.fInt;
+       }
+
+       protected void  addInSortOrder( Object obj)
+       {
+               int     i;
+               for ( i = 0; i < this.size(); i++)
+                       if ( sCollator.compare( obj.toString(), this.getElementAt( i).toString()) < 0)
+                               break;
+               this.add( i, obj);
+       }
+
+       protected int   findMatching( String match)
+       {
+               for ( int i = 0; i < this.size(); i++)
+                       if ( match.equals( this.getElementAt( i).toString()))
+                               return i;
+               return -1;
+       }
+
+       protected void  scheduleOnEventThread()
+       {
+               try {
+                       SwingUtilities.invokeAndWait( this);
+               }
+               catch ( Exception e)
+               {
+                       e.printStackTrace();
+               }
+       }               
+
+       protected Vector        removeCache;    // list of serviceNames to remove
+       protected Vector        addCache;               // list of BrowserListElem's to add
+
+       protected static Collator       sCollator;
+
+       static  // Initialize our static variables
+       {
+               sCollator = Collator.getInstance();
+               sCollator.setStrength( Collator.PRIMARY);
+       }
+}
+
+
+class  ServicesBrowserListModel extends BrowserListModel
+{
+       /* The Browser invokes this callback when a service is discovered. */
+       public void     serviceFound( DNSSDService browser, int flags, int ifIndex, 
+                                                       String serviceName, String regType, String domain)
+       // Overridden to stuff serviceName into regType and make serviceName human-readable.
+       {
+               regType = serviceName + ( regType.startsWith( "_udp.") ? "._udp." : "._tcp.");
+               super.serviceFound( browser, flags, ifIndex, this.mapTypeToName( serviceName), regType, domain);
+       }
+
+       public void     serviceLost( DNSSDService browser, int flags, int ifIndex, 
+                                                       String serviceName, String regType, String domain)
+       // Overridden to make serviceName human-readable.
+       {
+               super.serviceLost( browser, flags, ifIndex, this.mapTypeToName( serviceName), regType, domain);
+       }
+
+       protected String        mapTypeToName( String type)
+       // Convert a registration type into a human-readable string. Returns original string on no-match.
+       {
+               final String[]  namedServices = {
+                       "_afpovertcp",  "Apple File Sharing",
+                       "_http",                "World Wide Web servers",
+                       "_daap",                "Digital Audio Access",
+                       "_apple-sasl",  "Apple Password Servers",
+                       "_distcc",              "Distributed Compiler nodes",
+                       "_finger",              "Finger servers",
+                       "_ichat",               "iChat clients",
+                       "_presence",    "iChat AV clients",
+                       "_ssh",                 "SSH servers",
+                       "_telnet",              "Telnet servers",
+                       "_workstation", "Macintosh Manager clients",
+                       "_bootps",              "BootP servers",
+                       "_xserveraid",  "XServe RAID devices",
+                       "_eppc",                "Remote AppleEvents",
+                       "_ftp",                 "FTP services",
+                       "_tftp",                "TFTP services"
+               };
+
+               for ( int i = 0; i < namedServices.length; i+=2)
+                       if ( namedServices[i].equals( type))
+                               return namedServices[i + 1];
+               return type;
+       }
+}
+
+
+class  DomainListModel extends DefaultListModel implements DomainListener
+{
+       /* Called when a domain is discovered. */
+       public void     domainFound( DNSSDService domainEnum, int flags, int ifIndex, String domain)
+       {
+               if ( !this.contains( domain))
+                       this.addElement( domain);
+       }
+       
+       public void     domainLost( DNSSDService domainEnum, int flags, int ifIndex, String domain)
+       {
+               if ( this.contains( domain))
+                       this.removeElement( domain);
+       }
+
+       public void     operationFailed( DNSSDService service, int errorCode)
+       {
+               // handle failure here
+       }
+}
+
diff --git a/Clients/Java/DNSSDUnitTest.java b/Clients/Java/DNSSDUnitTest.java
new file mode 100644 (file)
index 0000000..e4523e1
--- /dev/null
@@ -0,0 +1,311 @@
+/*
+ * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+
+$Log: DNSSDUnitTest.java,v $
+Revision 1.3  2004/05/26 01:41:58  cheshire
+Pass proper flags to DNSSD.enumerateDomains
+
+Revision 1.2  2004/04/30 21:53:34  rpantos
+Change line endings for CVS.
+
+Revision 1.1  2004/04/30 16:29:35  rpantos
+First checked in.
+
+       DNSSDUnitTest is a simple program that exercises parts of the DNSSD API.
+ */
+
+import com.apple.dnssd.*;
+
+import java.net.*;
+import java.util.*;
+
+
+class  DNSSDUnitTest
+{
+       public static final String      TEST_TYPE = "_unittest._udp";
+       public static final String      WIRE_CHAR_SET = "ISO-8859-1";
+
+       public DNSSDUnitTest    fInstance = null;
+
+       public          DNSSDUnitTest() throws Exception
+       {
+               fStage = 0;
+               fInstance = this;
+               
+               Enumeration     en = NetworkInterface.getNetworkInterfaces();
+               while ( en.hasMoreElements())
+                       System.out.println( ((NetworkInterface) en.nextElement()).getName());
+       }
+
+       public void     testTxtRecord()
+       {
+               byte[]          src = { 6, 'a', 't', '=', 'X', 'Y', 'Z' };
+               TXTRecord       txtRecord = new TXTRecord( src);
+               String          a;
+               
+               txtRecord.set( "path", "~/names");
+               txtRecord.set( "ttl", "4");
+
+               byte[]  rawBytes = txtRecord.getRawBytes();
+               System.out.println( ( new String( rawBytes, 0, rawBytes.length)) + " has count " + 
+                                                               String.valueOf( txtRecord.size()));
+
+               boolean         ttlPresent = txtRecord.contains( "ttl");
+               System.out.println( "ttl is present: " + ( ttlPresent ? "true" : "false"));
+               boolean         timeoutPresent = txtRecord.contains( "timeout");
+               System.out.println( "timeout is present: " + ( timeoutPresent ? "true" : "false"));
+
+               for ( int i=0; null != ( a = txtRecord.getKey( i)); i++)
+                       System.out.println( "attr/val " + String.valueOf( i) + ": " + a + "," + txtRecord.getValueAsString( i));
+       }
+
+       public void     run() throws DNSSDException
+       {
+               System.out.println( "Running DNSSD unit test for " + System.getProperty( "user.name"));
+
+               this.testTxtRecord();
+
+               fRegTest = new RegTest();
+               new BrowseTest();
+               new DomainTest();
+               
+               this.waitForEnd();
+       }
+
+       protected int           fStage;
+       protected RegTest       fRegTest;
+
+       public synchronized void bumpStage()
+       {
+               fStage++;
+               this.notifyAll();
+       }
+
+       protected synchronized void waitForEnd()
+       {
+               int stage = fStage;
+               while ( stage == fStage)
+               {
+                       try {
+                               wait();
+                       } catch (InterruptedException e) {}
+               }
+       }
+
+    public static void main(String s[]) 
+    {
+       try {
+                       new DNSSDUnitTest().run();
+               }
+               catch ( Exception e) { terminateWithException( e); }
+    }
+
+       protected static void   terminateWithException( Exception e)
+       {
+               e.printStackTrace();
+               System.exit( -1);
+       }
+}
+
+class  TermReporter implements BaseListener
+{
+       public void     operationFailed( DNSSDService service, int errorCode)
+       {
+               System.out.println( this.getClass().getName() + " encountered error " + String.valueOf( errorCode));
+       }
+
+       protected void finalize() throws Throwable
+       {
+               System.out.println( "Instance of " + this.getClass().getName() + " has been destroyed");
+       }
+}
+
+class  RegTest extends TermReporter implements RegisterListener
+{
+       public static final int         TEST_PORT = 5678;
+
+       public          RegTest() throws DNSSDException
+       {
+               fReg = DNSSD.register( 0, 0, "Test service", DNSSDUnitTest.TEST_TYPE, "", "", TEST_PORT, null, this);
+       }
+
+       public void     serviceRegistered( DNSSDRegistration registration, int flags, String serviceName, 
+                                                               String regType, String domain)
+       {
+               String s = "RegTest result flags:" + String.valueOf( flags) + 
+                                       " serviceName:" + serviceName + " regType:" + regType + " domain:" + domain;
+               System.out.println( s);
+
+               try {
+                       new DupRegTest();
+                       
+                       byte[]  kResponsiblePerson = { 'c','o','o','k','i','e',' ','m','o','n','s','t','e','r' };
+                       fReg.addRecord( 0, 17 /*ns_t_rp*/, kResponsiblePerson, 3600);
+                       new QueryTest( 0, 0, "Test service", 17 /*ns_t_rp*/, 1);
+               } catch( Exception e) { e.printStackTrace(); }
+       }
+
+       protected DNSSDRegistration     fReg;
+}
+
+class  DupRegTest extends TermReporter implements RegisterListener
+{
+       public static final int         TEST_PORT = 5678;
+
+       public          DupRegTest() throws DNSSDException
+       {
+               DNSSD.register( DNSSD.NO_AUTO_RENAME | DNSSD.UNIQUE, 0, "Test service", DNSSDUnitTest.TEST_TYPE, "", "", TEST_PORT + 1, null, this);
+       }
+
+       public void     serviceRegistered( DNSSDRegistration registration, int flags, String serviceName, 
+                                                               String regType, String domain)
+       {
+               System.out.println( "Oik - registered a duplicate!");
+               String s = "DupRegTest result flags:" + String.valueOf( flags) + 
+                                       " serviceName:" + serviceName + " regType:" + regType + " domain:" + domain;
+               System.out.println( s);
+       }
+}
+
+class  BrowseTest extends TermReporter implements BrowseListener
+{
+       public          BrowseTest()
+       {
+               try {
+                       DNSSD.browse( 0, 0, DNSSDUnitTest.TEST_TYPE, "", this);
+               } catch( Exception e) { e.printStackTrace(); }
+       }
+
+       public void     serviceFound( DNSSDService browser, int flags, int ifIndex, 
+                                                       String serviceName, String regType, String domain)
+       {
+               String s = "BrowseTest found flags:" + String.valueOf( flags) + 
+                                       " ifIndex:" + String.valueOf( ifIndex) + 
+                                       " serviceName:" + serviceName + " regType:" + regType + " domain:" + domain;
+               System.out.println( s);
+               
+               System.out.println( "Resolving " + serviceName);
+               new ResolveTest( 0, ifIndex, serviceName, regType, domain);
+       }
+
+       public void     serviceLost( DNSSDService browser, int flags, int ifIndex,
+                                                       String serviceName, String regType, String domain)
+       {
+               String s = "BrowseTest lost flags:" + String.valueOf( flags) + 
+                                       " ifIndex:" + String.valueOf( ifIndex) + 
+                                       " serviceName:" + serviceName + " regType:" + regType + " domain:" + domain;
+               System.out.println( s);
+       }
+
+       public void     operationFailed( DNSSDService service, int errorCode)
+       {
+               System.out.println( "Browse failed " + String.valueOf( errorCode));
+       }
+}
+
+class  DomainTest extends TermReporter implements DomainListener
+{
+       public          DomainTest()
+       {
+               try {
+                       DNSSD.enumerateDomains( DNSSD.BROWSE_DOMAINS, 0, this);
+               } catch( Exception e) { e.printStackTrace(); }
+       }
+
+       public void     domainFound( DNSSDService enumerator, int flags, int ifIndex, String domain)
+       {
+               String s = "Domain found flags:" + String.valueOf( flags) + 
+                                       " ifIndex:" + String.valueOf( ifIndex) + 
+                                       " domain:" + domain;
+               System.out.println( s);
+       }
+
+       public void     domainLost( DNSSDService enumerator, int flags, int ifIndex, String domain)
+       {
+               String s = "Domain lost flags:" + String.valueOf( flags) + 
+                                       " ifIndex:" + String.valueOf( ifIndex) + 
+                                       " domain:" + domain;
+               System.out.println( s);
+       }
+
+       public void     operationFailed( DNSSDService service, int errorCode)
+       {
+               System.out.println( "Domain enum op failed " + String.valueOf( errorCode));
+       }
+}
+
+class  ResolveTest extends TermReporter implements ResolveListener
+{
+       public          ResolveTest( int flags, int ifIndex, String serviceName, String regType, 
+                                                       String domain)
+       {
+               try {
+                       DNSSD.resolve( flags, ifIndex, serviceName, regType, domain, this);
+               } catch( Exception e) { e.printStackTrace(); }
+       }
+
+       public void     serviceResolved( DNSSDService resolver, int flags, int ifIndex, String fullName, 
+                                                               String hostName, int port, TXTRecord txtRecord)
+       {
+               String a;
+               String s = "ResolveTest result flags:" + String.valueOf( flags) + 
+                                       " ifIndex:" + String.valueOf( ifIndex) + 
+                                       " fullName:" + fullName + " hostName:" + hostName + " port:" + String.valueOf( port);
+               for ( int i=0; null != ( a = txtRecord.getKey( i)); i++)
+                       s += " attr/val " + String.valueOf( i) + ": " + a + "," + txtRecord.getValueAsString( i);
+
+               System.out.println( s);
+
+               System.out.println( "Querying " + hostName);
+               new QueryTest( 0, ifIndex, hostName, 1 /* ns_t_a */, 1 /* ns_c_in */);
+       }
+}
+
+class  QueryTest extends TermReporter implements QueryListener
+{
+       public          QueryTest( int flags, int ifIndex, String serviceName, int rrtype, int rrclass)
+       {
+               try {
+                       DNSSD.queryRecord( flags, ifIndex, serviceName, rrtype, rrclass, this);
+               } catch( Exception e) { e.printStackTrace(); }
+       }
+
+       public void     queryAnswered( DNSSDService query, int flags, int ifIndex, String fullName, 
+                                                               int rrtype, int rrclass, byte[] rdata, int ttl)
+       {
+               String s = "QueryTest result flags:" + String.valueOf( flags) + 
+                                       " ifIndex:" + String.valueOf( ifIndex) + 
+                                       " fullName:" + fullName + " rrtype:" + String.valueOf( rrtype) + 
+                                       " rrclass:" + String.valueOf( rrclass) + " ttl:" + String.valueOf( ttl);
+               System.out.println( s);
+
+               try {
+                       String  dataTxt = new String( rdata, 0, rdata.length, DNSSDUnitTest.WIRE_CHAR_SET);
+                       System.out.println( "Query data is:" + dataTxt);
+               } catch( Exception e) { e.printStackTrace(); }
+       }
+}
+
diff --git a/Clients/Java/SimpleChat.java b/Clients/Java/SimpleChat.java
new file mode 100644 (file)
index 0000000..07f58d2
--- /dev/null
@@ -0,0 +1,338 @@
+/*
+ * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+
+$Log: SimpleChat.java,v $
+Revision 1.2  2004/04/30 21:53:35  rpantos
+Change line endings for CVS.
+
+Revision 1.1  2004/04/30 16:29:35  rpantos
+First checked in.
+
+       SimpleChat is a simple peer-to-peer chat program that demonstrates 
+       DNSSD registration, browsing, resolving and record-querying.
+
+       To do:
+       - remove TXTRecord tests
+       - remove diagnostic printf's
+       - implement better coloring algorithm
+ */
+
+
+import java.awt.*;
+import java.awt.event.*;
+import java.text.*;
+import java.net.*;
+import javax.swing.*;
+import javax.swing.event.*;
+import javax.swing.text.*;
+
+import com.apple.dnssd.*;
+
+
+class  SimpleChat implements   ResolveListener, RegisterListener, QueryListener, 
+                                                               ActionListener, ItemListener, Runnable
+{
+       Document                        textDoc;                        // Holds all the chat text
+       JTextField                      inputField;                     // Holds a pending chat response
+       String                          ourName;                        // name used to identify this user in chat
+       DNSSDService            browser;                        // object that actively browses for other chat clients
+       DNSSDService            resolver;                       // object that resolves other chat clients
+       DNSSDRegistration       registration;           // object that maintains our connection advertisement
+       JComboBox                       targetPicker;           // Indicates who we're talking to
+       TargetListModel         targetList;                     // and its list model
+       JButton                         sendButton;                     // Will send text in inputField to target
+       InetAddress                     buddyAddr;                      // and address
+       int                                     buddyPort;                      // and port
+       DatagramPacket          dataPacket;                     // Inbound data packet
+       DatagramSocket          outSocket;                      // Outbound data socket
+       SimpleAttributeSet      textAttribs;
+
+       static final String     kChatExampleRegType = "_p2pchat._udp";
+       static final String     kWireCharSet = "ISO-8859-1";
+
+       public          SimpleChat() throws Exception
+       {
+               JFrame frame = new JFrame("SimpleChat");
+               frame.addWindowListener(new WindowAdapter() {
+                       public void windowClosing(WindowEvent e) {System.exit(0);}
+               });
+
+       ourName = System.getProperty( "user.name");
+               targetList = new TargetListModel();
+               textAttribs = new SimpleAttributeSet();
+               DatagramSocket inSocket = new DatagramSocket();
+               dataPacket = new DatagramPacket( new byte[ 4096], 4096);
+               outSocket = new DatagramSocket();
+
+               this.setupSubPanes( frame.getContentPane(), frame.getRootPane());
+               frame.pack();
+               frame.setVisible(true);
+               inputField.requestFocusInWindow();
+
+               browser = DNSSD.browse( 0, 0, kChatExampleRegType, "", new SwingBrowseListener( targetList));
+
+       TXTRecord       tRec = new TXTRecord();
+       tRec.set( "name", "roger");
+       tRec.set( "color", "blue");
+
+               registration = DNSSD.register( 0, 0, ourName, kChatExampleRegType, "", "", inSocket.getLocalPort(), tRec, this);
+
+               new ListenerThread( this, inSocket, dataPacket).start();
+       }
+
+       protected void  setupSubPanes( Container parent, JRootPane rootPane)
+       {       
+               parent.setLayout( new BoxLayout( parent, BoxLayout.Y_AXIS));
+
+               JPanel textRow = new JPanel();
+               textRow.setLayout( new BoxLayout( textRow, BoxLayout.X_AXIS));
+               textRow.add( Box.createRigidArea( new Dimension( 16, 0)));
+               JEditorPane textPane = new JEditorPane( "text/html", "<BR>");
+               textPane.setPreferredSize( new Dimension( 400, 300));
+               textPane.setEditable( false);
+               JScrollPane textScroller = new JScrollPane( textPane);
+               textRow.add( textScroller);
+               textRow.add( Box.createRigidArea( new Dimension( 16, 0)));
+               textDoc = textPane.getDocument();
+
+               JPanel addressRow = new JPanel();
+               addressRow.setLayout( new BoxLayout( addressRow, BoxLayout.X_AXIS));
+               targetPicker = new JComboBox( targetList);
+               targetPicker.addItemListener( this);
+               addressRow.add( Box.createRigidArea( new Dimension( 16, 0)));
+               addressRow.add( new JLabel( "Talk to: "));
+               addressRow.add( targetPicker);
+               addressRow.add( Box.createHorizontalGlue());
+
+               JPanel buttonRow = new JPanel();
+               buttonRow.setLayout( new BoxLayout( buttonRow, BoxLayout.X_AXIS));
+               buttonRow.add( Box.createRigidArea( new Dimension( 16, 0)));
+               inputField = new JTextField();
+               // prevent inputField from hijacking <Enter> key
+               inputField.getKeymap().removeKeyStrokeBinding( KeyStroke.getKeyStroke( KeyEvent.VK_ENTER, 0));
+               buttonRow.add( inputField);
+               sendButton = new JButton( "Send");
+               buttonRow.add( Box.createRigidArea( new Dimension( 8, 0)));
+               buttonRow.add( sendButton);
+               buttonRow.add( Box.createRigidArea( new Dimension( 16, 0)));
+               rootPane.setDefaultButton( sendButton);
+               sendButton.addActionListener( this);
+               sendButton.setEnabled( false);
+
+               parent.add( Box.createRigidArea( new Dimension( 0, 16)));
+               parent.add( textRow);
+               parent.add( Box.createRigidArea( new Dimension( 0, 8)));
+               parent.add( addressRow);
+               parent.add( Box.createRigidArea( new Dimension( 0, 8)));
+               parent.add( buttonRow);
+               parent.add( Box.createRigidArea( new Dimension( 0, 16)));
+       }
+
+       public void     serviceRegistered( DNSSDRegistration registration, int flags, 
+                                                                       String serviceName, String regType, String domain)
+       {
+               ourName = serviceName;          // might have been renamed on collision
+System.out.println( "ServiceRegisterCallback() invoked as " + serviceName);
+       }
+
+       public void     operationFailed( DNSSDService service, int errorCode)
+       {
+               System.out.println( "Service reported error " + String.valueOf( errorCode));
+       }
+
+       public void     serviceResolved( DNSSDService resolver, int flags, int ifIndex, String fullName, 
+                                                                               String hostName, int port, TXTRecord txtRecord)
+       {
+String a;
+for ( int i=0; null != ( a = txtRecord.getKey( i)); i++)
+       System.out.println( "attr/val " + String.valueOf( i) + ": " + a + "," + txtRecord.getValueAsString( i));
+
+               buddyPort = port;
+               try {
+                       // Start a record query to obtain IP address from hostname
+                       DNSSD.queryRecord( 0, ifIndex, hostName, 1 /* ns_t_a */, 1 /* ns_c_in */, 
+                                                               new SwingQueryListener( this));
+               }
+               catch ( Exception e) { terminateWithException( e); }
+               resolver.stop();
+       }
+
+       public void     queryAnswered( DNSSDService query, int flags, int ifIndex, String fullName, 
+                                                                       int rrtype, int rrclass, byte[] rdata, int ttl)
+       {
+               try {
+                       buddyAddr = InetAddress.getByAddress( rdata);
+               }
+               catch ( Exception e) { terminateWithException( e); }
+               sendButton.setEnabled( true);
+       }
+
+       public void             actionPerformed( ActionEvent e)         // invoked when Send button is hit
+       {
+               try
+               {
+                       String  sendString = ourName + ": " + inputField.getText();
+                       byte[] sendData = sendString.getBytes( kWireCharSet);
+                       outSocket.send( new DatagramPacket( sendData, sendData.length, buddyAddr, buddyPort));
+                       StyleConstants.setForeground( textAttribs, Color.black);
+                       textDoc.insertString( textDoc.getLength(), inputField.getText() + "\n", textAttribs);
+                       inputField.setText( "");
+               }
+               catch ( Exception exception) { terminateWithException( exception); }
+       }
+
+       public void             itemStateChanged( ItemEvent e)  // invoked when Target selection changes
+       {
+               sendButton.setEnabled( false);
+               if ( e.getStateChange() == ItemEvent.SELECTED)
+               {
+                       try {
+                               TargetListElem  sel = (TargetListElem) targetList.getSelectedItem();
+                               resolver = DNSSD.resolve( 0, sel.fInt, sel.fServiceName, sel.fType, sel.fDomain, this);
+                       }
+                       catch ( Exception exception) { terminateWithException( exception); }
+               }
+       }
+
+       public void             run()           // invoked on event thread when inbound packet arrives
+       {
+               try
+               {
+                       String  inMessage = new String( dataPacket.getData(), 0, dataPacket.getLength(), kWireCharSet);
+                       StyleConstants.setForeground( textAttribs, this.getColorFor( dataPacket.getData(), dataPacket.getLength()));
+                       textDoc.insertString( textDoc.getLength(), inMessage + "\n", textAttribs);
+               }
+               catch ( Exception e) { terminateWithException( e); }
+       }
+
+       protected Color         getColorFor( byte[] chars, int length)
+       // Produce a mapping from a string to a color, suitable for text display
+       {
+               int             rgb = 0;
+               for ( int i=0; i < length && chars[i] != ':'; i++)
+                       rgb = rgb ^ ( (int) chars[i] << (i%3+2) * 8);
+               return new Color( rgb & 0x007F7FFF);    // mask off high bits so it is a dark color
+               
+//             for ( int i=0; i < length && chars[i] != ':'; i++)
+               
+       }
+
+       protected static void   terminateWithException( Exception e)
+       {
+               e.printStackTrace();
+               System.exit( -1);
+       }
+
+    public static void main(String s[]) 
+    {
+       try {
+                       new SimpleChat();
+               }
+               catch ( Exception e) { terminateWithException( e); }
+    }
+}
+
+
+
+class  TargetListElem
+{
+       public  TargetListElem( String serviceName, String domain, String type, int ifIndex)
+       { fServiceName = serviceName; fDomain = domain; fType = type; fInt = ifIndex; }
+       
+       public String   toString() { return fServiceName; }
+       
+       public String   fServiceName, fDomain, fType;
+       public int              fInt;
+}
+
+class          TargetListModel extends DefaultComboBoxModel implements BrowseListener
+{
+       /* The Browser invokes this callback when a service is discovered. */
+       public void     serviceFound( DNSSDService browser, int flags, int ifIndex, 
+                                                       String serviceName, String regType, String domain)
+       {
+               TargetListElem          match = this.findMatching( serviceName);        // probably doesn't handle near-duplicates well.
+
+               if ( match == null)
+                       this.addElement( new TargetListElem( serviceName, domain, regType, ifIndex));
+       }
+
+       /* The Browser invokes this callback when a service disappears. */
+       public void     serviceLost( DNSSDService browser, int flags, int ifIndex, 
+                                                       String serviceName, String regType, String domain)
+       {
+               TargetListElem          match = this.findMatching( serviceName);        // probably doesn't handle near-duplicates well.
+
+               if ( match != null)
+                       this.removeElement( match);
+       }
+
+       /* The Browser invokes this callback when a service disappears. */
+       public void     operationFailed( DNSSDService service, int errorCode)
+       {
+               System.out.println( "Service reported error " + String.valueOf( errorCode));
+       }
+
+       protected TargetListElem        findMatching( String match)
+       {
+               for ( int i = 0; i < this.getSize(); i++)
+                       if ( match.equals( this.getElementAt( i).toString()))
+                               return (TargetListElem) this.getElementAt( i);
+               return null;
+       }
+
+}
+
+
+// A ListenerThread runs its owner when datagram packet p appears on socket s.
+class  ListenerThread extends Thread
+{
+       public                  ListenerThread( Runnable owner, DatagramSocket s, DatagramPacket p) 
+       { fOwner = owner; fSocket = s; fPacket = p; }
+
+       public void             run()
+       {               
+               while ( true )
+               {
+                       try 
+                       {
+                               fSocket.receive( fPacket);
+                               SwingUtilities.invokeAndWait( fOwner);  // process data on main thread
+                       }
+                       catch( Exception e)
+                       {
+                               break;  // terminate thread
+                       }
+               }
+       }
+
+       protected Runnable                      fOwner;
+       protected DatagramSocket        fSocket;
+       protected DatagramPacket        fPacket;
+}
+
+
+
diff --git a/Clients/Java/SwingBrowseListener.java b/Clients/Java/SwingBrowseListener.java
new file mode 100644 (file)
index 0000000..4855dde
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+
+$Log: SwingBrowseListener.java,v $
+Revision 1.2  2004/04/30 21:53:35  rpantos
+Change line endings for CVS.
+
+Revision 1.1  2004/04/30 16:29:35  rpantos
+First checked in.
+
+ */
+
+
+import javax.swing.*;
+import com.apple.dnssd.*;
+
+
+/**    Use this to schedule BrowseListener callbacks via SwingUtilities.invokeAndWait(). */
+
+public class SwingBrowseListener implements Runnable, BrowseListener
+{
+       /** Create a listener for DNSSD that will call your listener on the Swing/AWT event thread. */
+       public  SwingBrowseListener( BrowseListener listener)
+       { fListener = listener; fErrorCode = 0; }
+
+       /** (Clients should not call this method directly.) */
+       public void     operationFailed( DNSSDService service, int errorCode)
+       {
+               fBrowser = service;
+               fErrorCode = errorCode;
+               this.schedule();
+       }
+
+       /** (Clients should not call this method directly.) */
+       public void     serviceFound( DNSSDService browser, int flags, int ifIndex, 
+                                                       String serviceName, String regType, String domain)
+
+       {
+               fBrowser = browser;
+               fIsAdd = true;
+               fFlags = flags;
+               fIndex = ifIndex;
+               fService = serviceName;
+               fRegType = regType;
+               fDomain = domain;
+               this.schedule();
+       }
+
+       /** (Clients should not call this method directly.) */
+       public void     serviceLost( DNSSDService browser, int flags, int ifIndex,
+                                                       String serviceName, String regType, String domain)
+       {
+               fBrowser = browser;
+               fIsAdd = false;
+               fFlags = flags;
+               fIndex = ifIndex;
+               fService = serviceName;
+               fRegType = regType;
+               fDomain = domain;
+               this.schedule();
+       }
+
+       /** (Clients should not call this method directly.) */
+       public void             run()
+       {
+               if ( fErrorCode != 0)
+                       fListener.operationFailed( fBrowser, fErrorCode);
+               else if ( fIsAdd)
+                       fListener.serviceFound( fBrowser, fFlags, fIndex, fService, fRegType, fDomain);
+               else
+                       fListener.serviceLost( fBrowser, fFlags, fIndex, fService, fRegType, fDomain);
+       }
+
+       protected void  schedule()
+       {               
+               try {
+                       SwingUtilities.invokeAndWait( this);
+               }
+               catch ( Exception e)
+               {
+                       e.printStackTrace();
+               }
+       }
+
+       protected BrowseListener        fListener;
+
+       protected boolean                       fIsAdd;
+       protected DNSSDService          fBrowser;
+       protected int                           fFlags;
+       protected int                           fIndex;
+       protected int                           fErrorCode;
+       protected String                        fService;
+       protected String                        fRegType;
+       protected String                        fDomain;
+}
+
diff --git a/Clients/Java/SwingDomainListener.java b/Clients/Java/SwingDomainListener.java
new file mode 100644 (file)
index 0000000..2c5840f
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+
+$Log: SwingDomainListener.java,v $
+Revision 1.2  2004/04/30 21:53:35  rpantos
+Change line endings for CVS.
+
+Revision 1.1  2004/04/30 16:29:35  rpantos
+First checked in.
+
+ */
+
+
+import javax.swing.*;
+import com.apple.dnssd.*;
+
+
+/**    Use this to schedule DomainListener callbacks via SwingUtilities.invokeAndWait(). */
+
+public class SwingDomainListener implements Runnable, DomainListener
+{
+       /** Create a listener for DNSSD that will call your listener on the Swing/AWT event thread. */
+       public  SwingDomainListener( DomainListener listener)
+       { fListener = listener; fErrorCode = 0; }
+
+       /** (Clients should not call this method directly.) */
+       public void     operationFailed( DNSSDService service, int errorCode)
+       {
+               fEnumerator = service;
+               fErrorCode = errorCode;
+               this.schedule();
+       }
+
+       /** (Clients should not call this method directly.) */
+       public void             domainFound( DNSSDService domainEnum, int flags, int ifIndex, String domain)
+
+       {
+               fEnumerator = domainEnum;
+               fIsAdd = true;
+               fFlags = flags;
+               fIndex = ifIndex;
+               fDomain = domain;
+               this.schedule();
+       }
+
+       /** (Clients should not call this method directly.) */
+       public void             domainLost( DNSSDService domainEnum, int flags, int ifIndex, String domain)
+       {
+               fEnumerator = domainEnum;
+               fIsAdd = false;
+               fFlags = flags;
+               fIndex = ifIndex;
+               fDomain = domain;
+               this.schedule();
+       }
+
+       /** (Clients should not call this method directly.) */
+       public void             run()
+       {
+               if ( fErrorCode != 0)
+                       fListener.operationFailed( fEnumerator, fErrorCode);
+               else if ( fIsAdd)
+                       fListener.domainFound( fEnumerator, fFlags, fIndex, fDomain);
+               else
+                       fListener.domainLost( fEnumerator, fFlags, fIndex, fDomain);
+       }
+
+       protected void  schedule()
+       {               
+               try {
+                       SwingUtilities.invokeAndWait( this);
+               }
+               catch ( Exception e)
+               {
+                       e.printStackTrace();
+               }
+       }
+
+       protected DomainListener        fListener;
+
+       protected boolean                       fIsAdd;
+       protected DNSSDService          fEnumerator;
+       protected int                           fFlags;
+       protected int                           fIndex;
+       protected int                           fErrorCode;
+       protected String                        fDomain;
+}
+
diff --git a/Clients/Java/SwingQueryListener.java b/Clients/Java/SwingQueryListener.java
new file mode 100644 (file)
index 0000000..4b58e67
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+
+$Log: SwingQueryListener.java,v $
+Revision 1.2  2004/04/30 21:53:35  rpantos
+Change line endings for CVS.
+
+Revision 1.1  2004/04/30 16:29:35  rpantos
+First checked in.
+
+ */
+
+
+import javax.swing.*;
+import com.apple.dnssd.*;
+
+
+/**    Use this to schedule QueryListener callbacks via SwingUtilities.invokeAndWait(). */
+
+public class SwingQueryListener implements Runnable, QueryListener
+{
+       /** Create a listener for DNSSD that will call your listener on the Swing/AWT event thread. */
+       public  SwingQueryListener( QueryListener listener)
+       { fListener = listener; }
+
+       public void     operationFailed( DNSSDService service, int errorCode)
+       {
+               fQuery = service;
+               fErrorCode = errorCode;
+               this.schedule();
+       }
+
+       /** (Clients should not call this method directly.) */
+       public void     queryAnswered( DNSSDService query, int flags, int ifIndex, String fullName, 
+                                                               int rrtype, int rrclass, byte[] rdata, int ttl)
+       {
+               fQuery = query;
+               fFlags = flags;
+               fIndex = ifIndex;
+               fFullName = fullName;
+               fType = rrtype;
+               fClass = rrclass;
+               fData = rdata;
+               fTTL = ttl;
+               this.schedule();
+       }
+
+       /** (Clients should not call this method directly.) */
+       public void             run()
+       {
+               if ( fErrorCode != 0)
+                       fListener.operationFailed( fQuery, fErrorCode);
+               else
+                       fListener.queryAnswered( fQuery, fFlags, fIndex, fFullName, fType, fClass, fData, fTTL);
+       }
+
+       protected void  schedule()
+       {
+               try {
+                       SwingUtilities.invokeAndWait( this);
+               }
+               catch ( Exception e)
+               {
+                       e.printStackTrace();
+               }
+       }
+
+       protected QueryListener         fListener;
+
+       protected DNSSDService          fQuery;
+       protected int                           fFlags;
+       protected int                           fIndex;
+       protected int                           fErrorCode;
+       protected String                        fFullName;
+       protected int                           fType;
+       protected int                           fClass;
+       protected byte[]                        fData;
+       protected int                           fTTL;
+}
+
diff --git a/Clients/Java/SwingResolveListener.java b/Clients/Java/SwingResolveListener.java
new file mode 100644 (file)
index 0000000..1422a6e
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+
+$Log: SwingResolveListener.java,v $
+Revision 1.2  2004/06/14 23:46:55  cheshire
+Recreate CVS state
+
+Revision 1.1  2004/06/14 23:46:26  cheshire
+First checkin
+
+ */
+
+
+import javax.swing.*;
+import com.apple.dnssd.*;
+
+
+/**    Use this to schedule ResolveListener callbacks via SwingUtilities.invokeAndWait(). */
+
+public class SwingResolveListener implements Runnable, ResolveListener
+{
+       /** Create a listener for DNSSD that will call your listener on the Swing/AWT event thread. */
+       public  SwingResolveListener( ResolveListener listener)
+       { fListener = listener; }
+
+       public void     operationFailed( DNSSDService service, int errorCode)
+       {
+               fResolver = service;
+               fErrorCode = errorCode;
+               this.schedule();
+       }
+
+       /** (Clients should not call this method directly.) */
+       public void     serviceResolved( DNSSDService resolver, int flags, int ifIndex, String fullName, 
+                                                               String hostName, int port, TXTRecord txtRecord)
+       {
+               fResolver = resolver;
+               fFlags = flags;
+               fIndex = ifIndex;
+               fFullName = fullName;
+               fHostName = hostName;
+               fPort = port;
+               fTXTRecord = txtRecord;
+               this.schedule();
+       }
+
+       /** (Clients should not call this method directly.) */
+       public void             run()
+       {
+               if ( fErrorCode != 0)
+                       fListener.operationFailed( fResolver, fErrorCode);
+               else
+                       fListener.serviceResolved( fResolver, fFlags, fIndex, fFullName, fHostName, fPort, fTXTRecord);
+       }
+
+       protected void  schedule()
+       {
+               try {
+                       SwingUtilities.invokeAndWait( this);
+               }
+               catch ( Exception e)
+               {
+                       e.printStackTrace();
+               }
+       }
+
+       protected ResolveListener       fListener;
+
+       protected DNSSDService          fResolver;
+       protected int                           fFlags;
+       protected int                           fIndex;
+       protected int                           fErrorCode;
+       protected String                        fFullName;
+       protected String                        fHostName;
+       protected int                           fPort;
+       protected TXTRecord                     fTXTRecord;
+}
+
diff --git a/Clients/Makefile b/Clients/Makefile
new file mode 100755 (executable)
index 0000000..11f4a83
--- /dev/null
@@ -0,0 +1,62 @@
+# Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+#
+# $Log: Makefile,v $
+# Revision 1.4  2004/05/21 17:25:56  cheshire
+# Fixes to make sample client work on Linux
+#
+# Revision 1.3  2004/03/12 08:05:32  cheshire
+# Add a "make clean" target
+#
+# Revision 1.2  2004/02/11 20:59:26  cheshire
+# Fix Makefile so it creates the "build" directory if necessary
+#
+# Revision 1.1  2004/02/06 03:19:09  cheshire
+# Check in code to make command-line "dns-sd" testing tool
+#
+#
+# Notes:
+# $@ means "The file name of the target of the rule"
+# $< means "The name of the first prerequisite"
+# $+ means "The names of all the prerequisites, with spaces between them, exactly as given"
+# For more magic automatic variables, see
+# <http://www.gnu.org/software/make/manual/html_chapter/make_10.html#SEC111>
+
+#############################################################################
+
+
+# If library /usr/lib/libmdns.* exists, then link it
+ifneq "$(wildcard /usr/lib/libmdns.*)" ""
+LIBS = -lmdns
+else
+LIBS =
+endif
+
+targets: build/dns-sd
+
+clean:
+       rm -rf build
+
+build:
+       mkdir build
+
+build/dns-sd: build dns-sd.c
+       cc $(filter %.c %.o, $+) $(LIBS) -o $@
diff --git a/Clients/ReadMe.txt b/Clients/ReadMe.txt
new file mode 100644 (file)
index 0000000..83dd242
--- /dev/null
@@ -0,0 +1,25 @@
+This directory contains a variety of clients that use the
+"/usr/include/dns_sd.h" APIs.
+
+Some of the clients are command-line oriented; some are graphical.
+
+Some of the clients, like the "dns-sd" command-line tool, can be built
+for a variety of platforms. Some of the clients only build for one
+platform, like "DNS Service Browser" and "DNS Service Registration",
+which use Objective C and Cocoa and only run on OS X 10.3 or later.
+
+Some of the clients can be built more than one way. For example, the
+"dns-sd" command-line tool can be built for OS X using both the XCode
+IDE, or using a simple command-line "make" command.
+
+What all clients have in common is that they all demonstrate how you
+can use the "/usr/include/dns_sd.h" APIs.
+
+The table below gives a summary of which clients build for which platforms.
+
+Client                    Type          OS X   OS X   Posix
+                                        XCode  Make   Make
+
+dns-sd                    Command-line   X      X      X
+DNS Service Browser       Graphical      X
+DNS Service Registration  Graphical      X
diff --git a/Clients/dns-sd.c b/Clients/dns-sd.c
new file mode 100644 (file)
index 0000000..1fb02d0
--- /dev/null
@@ -0,0 +1,455 @@
+/*
+ * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ *
+ * Formatting notes:
+ * This code follows the "Whitesmiths style" C indentation rules. Plenty of discussion
+ * on C indentation can be found on the web, such as <http://www.kafejo.com/komp/1tbs.htm>,
+ * but for the sake of brevity here I will say just this: Curly braces are not syntactially
+ * part of an "if" statement; they are the beginning and ending markers of a compound statement;
+ * therefore common sense dictates that if they are part of a compound statement then they
+ * should be indented to the same level as everything else in that compound statement.
+ * Indenting curly braces at the same level as the "if" implies that curly braces are
+ * part of the "if", which is false. (This is as misleading as people who write "char* x,y;"
+ * thinking that variables x and y are both of type "char*" -- and anyone who doesn't
+ * understand why variable y is not of type "char*" just proves the point that poor code
+ * layout leads people to unfortunate misunderstandings about how the C language really works.)
+
+   Change History (most recent first):
+
+$Log: dns-sd.c,v $
+Revision 1.7  2004/05/28 02:20:06  cheshire
+If we allow dot or empty string for domain when resolving a service,
+it should be a synonym for "local"
+
+Revision 1.6  2004/05/21 19:57:19  cheshire
+Add -Q option to exercise DNSServiceQueryRecord() API call
+
+Revision 1.5  2004/05/21 17:39:27  cheshire
+Include extra headers to fix Xcode build
+
+Revision 1.4  2004/05/21 17:25:56  cheshire
+Fixes to make sample client work on Linux
+
+Revision 1.3  2004/04/06 22:02:06  cheshire
+Also show interface id when showing browse add/remove events
+
+Revision 1.2  2004/03/25 05:40:56  cheshire
+Changes from Marc Krochmal: Fix inconsistent use of space/tab
+
+Revision 1.1  2004/02/06 03:19:09  cheshire
+Check in code to make command-line "dns-sd" testing tool
+
+*/
+
+#include <stdio.h>                     // For stdout, stderr
+#include <stdlib.h>                    // For exit()
+#include <strings.h>           // For strlen(), strcpy(), bzero()
+#include <unistd.h>         // For getopt() and optind
+#include <errno.h>          // For errno, EINTR
+#define BIND_8_COMPAT
+#include <arpa/nameser.h>      // For T_HINFO, etc.
+#include <sys/time.h>          // For struct timeval
+#include <dns_sd.h>
+
+//*************************************************************************************************************
+// Globals
+
+typedef union { unsigned char b[2]; unsigned short NotAnInteger; } Opaque16;
+
+static int operation;
+static DNSServiceRef client = NULL;
+static int num_printed;
+static char addtest = 0;
+static DNSRecordRef record = NULL;
+static char myhinfo9[11] = "\003Mac\006OS 9.2";
+static char myhinfoX[ 9] = "\003Mac\004OS X";
+static char updatetest[3] = "\002AA";
+static char bigNULL[4096];
+
+#define LONG_TIME 0x4000000
+static volatile int stopNow = 0;
+static volatile int timeOut = LONG_TIME;
+
+//*************************************************************************************************************
+// Supporting Utility Function
+
+//*************************************************************************************************************
+// Sample callback functions for each of the operation types
+
+static void printtimestamp(void)
+       {
+       struct timeval tv;
+       struct tm tm;
+       gettimeofday(&tv, NULL);
+       localtime_r((time_t*)&tv.tv_sec, &tm);
+       printf("%2d:%02d:%02d.%03d  ", tm.tm_hour, tm.tm_min, tm.tm_sec, tv.tv_usec/1000);
+       }
+
+#define DomainMsg(X) (((X) & kDNSServiceFlagsDefault) ? "(Default)" : \
+                      ((X) & kDNSServiceFlagsAdd)     ? "Added"     : "Removed")
+
+static void regdom_reply(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interface,
+       DNSServiceErrorType errorCode, const char *replyDomain, void *context)
+       {
+       (void)interface;    // Unused
+       (void)errorCode;    // Unused
+       (void)context;      // Unused
+       printtimestamp();
+       printf("Recommended Registration Domain %s %s", replyDomain, DomainMsg(flags));
+       if (flags) printf(" Flags: %X", flags);
+       printf("\n");
+       }
+
+static void browsedom_reply(DNSServiceRef client, DNSServiceFlags flags, uint32_t interface,
+       DNSServiceErrorType errorCode, const char *replyDomain, void *context)
+       {
+       (void)client;       // Unused
+       (void)interface;    // Unused
+       (void)errorCode;    // Unused
+       (void)context;      // Unused
+       printtimestamp();
+       printf("Recommended Browsing Domain %s %s", replyDomain, DomainMsg(flags));
+       if (flags) printf(" Flags: %X", flags);
+       printf("\n");
+       }
+
+static void browse_reply(DNSServiceRef client, DNSServiceFlags flags, uint32_t interface, DNSServiceErrorType errorCode,
+       const char *replyName, const char *replyType, const char *replyDomain, void *context)
+       {
+       char *op = (flags & kDNSServiceFlagsAdd) ? "Add" : "Rmv";
+       (void)client;       // Unused
+       (void)interface;    // Unused
+       (void)errorCode;    // Unused
+       (void)context;      // Unused
+       if (num_printed++ == 0) printf("Timestamp     A/R Flags if %-24s %-24s %s\n", "Domain", "Service Type", "Instance Name");
+       printtimestamp();
+       printf("%s%6X%3d %-24s %-24s %s\n", op, flags, interface, replyDomain, replyType, replyName);
+       }
+
+static void resolve_reply(DNSServiceRef client, DNSServiceFlags flags, uint32_t interface, DNSServiceErrorType errorCode,
+       const char *fullname, const char *hosttarget, uint16_t opaqueport, uint16_t txtLen, const char *txtRecord, void *context)
+       {
+       const char *src = txtRecord;
+       union { uint16_t s; u_char b[2]; } port = { opaqueport };
+       uint16_t PortAsNumber = ((uint16_t)port.b[0]) << 8 | port.b[1];
+
+       (void)client;       // Unused
+       (void)interface;    // Unused
+       (void)errorCode;    // Unused
+       (void)context;      // Unused
+
+       printtimestamp();
+       printf("%s can be reached at %s:%u", fullname, hosttarget, PortAsNumber);
+
+       if (flags) printf(" Flags: %X", flags);
+       if (*src)
+               {
+               char txtInfo[64];                               // Display at most first 64 characters of TXT record
+               char *dst = txtInfo;
+               const char *const lim = &txtInfo[sizeof(txtInfo)];
+               while (*src && dst < lim-1)
+                       {
+                       if (*src == '\\') *dst++ = '\\';            // '\' displays as "\\"
+                       if (*src >= ' ') *dst++ = *src++;           // Display normal characters as-is
+                       else
+                               {
+                               *dst++ = '\\';                          // Display a backslash
+                               if (*src ==    1) *dst++ = ' ';         // String boundary displayed as "\ "
+                               else                                    // Other chararacters displayed as "\0xHH"
+                                       {
+                                       static const char hexchars[16] = "0123456789ABCDEF";
+                                       *dst++ = '0';
+                                       *dst++ = 'x';
+                                       *dst++ = hexchars[*src >> 4];
+                                       *dst++ = hexchars[*src & 0xF];
+                                       }
+                               src++;
+                               }
+                       }
+               *dst++ = 0;
+               printf(" TXT %s", txtInfo);
+               }
+       printf("\n");
+       }
+
+static void myTimerCallBack(void)
+       {
+       DNSServiceErrorType err;
+
+       switch (operation)
+               {
+               case 'A':
+                       {
+                       switch (addtest)
+                               {
+                               case 0: printf("Adding Test HINFO record\n");
+                                               err = DNSServiceAddRecord(client, &record, 0, T_HINFO, sizeof(myhinfo9), &myhinfo9[0], 120);
+                                               addtest = 1;
+                                               break;
+                               case 1: printf("Updating Test HINFO record\n");
+                                               err = DNSServiceUpdateRecord(client, record, 0, sizeof(myhinfoX), &myhinfoX[0], 120);
+                                               addtest = 2;
+                                               break;
+                               case 2: printf("Removing Test HINFO record\n");
+                                               err = DNSServiceRemoveRecord(client, record, 0);
+                                               addtest = 0;
+                                               break;
+                               }
+                       }
+                       break;
+
+               case 'U':
+                       {
+                       if (updatetest[1] != 'Z') updatetest[1]++;
+                       else                      updatetest[1] = 'A';
+                       updatetest[0] = 3 - updatetest[0];
+                       updatetest[2] = updatetest[1];
+                       printf("Updating Test TXT record to %c\n", updatetest[1]);
+                       err = DNSServiceUpdateRecord(client, NULL, 0, 1+updatetest[0], &updatetest[0], 120);
+                       }
+                       break;
+
+               case 'N':
+                       {
+                       printf("Adding big NULL record\n");
+                       err = DNSServiceAddRecord(client, &record, 0, T_NULL, sizeof(bigNULL), &bigNULL[0], 120);
+                       timeOut = LONG_TIME;
+                       }
+                       break;
+               }
+
+       if (err != kDNSServiceErr_NoError)
+               {
+               fprintf(stderr, "DNSService call failed %ld\n", (long int)err);
+               stopNow = 1;
+               }
+       }
+
+static void reg_reply(DNSServiceRef client, DNSServiceFlags flags, DNSServiceErrorType errorCode,
+       const char *name, const char *regtype, const char *domain, void *context)
+       {
+       (void)client;   // Unused
+       (void)flags;    // Unused
+       (void)context;  // Unused
+
+       printf("Got a reply for %s.%s%s: ", name, regtype, domain);
+       switch (errorCode)
+               {
+               case kDNSServiceErr_NoError:      printf("Name now registered and active\n"); break;
+               case kDNSServiceErr_NameConflict: printf("Name in use, please choose another\n"); exit(-1);
+               default:                          printf("Error %d\n", errorCode); return;
+               }
+
+       if (operation == 'A' || operation == 'U' || operation == 'N') timeOut = 5;
+       }
+
+void qr_reply(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)
+       {
+       const unsigned char *rd = rdata;
+       char rdb[1000];
+       switch (rrtype)
+               {
+               case T_A: snprintf(rdb, sizeof(rdb), "%d.%d.%d.%d", rd[0], rd[1], rd[2], rd[3]); break;
+               default : snprintf(rdb, sizeof(rdb), "Unknown rdata: %d bytes", rdlen);          break;
+               }
+       printf("%-30s%4d%4d  %s\n", fullname, rrtype, rrclass, rdb);
+       }
+
+//*************************************************************************************************************
+// The main test function
+
+static void HandleEvents(void)
+       {
+       int dns_sd_fd = DNSServiceRefSockFD(client);
+       int nfds = dns_sd_fd + 1;
+       fd_set readfds;
+       struct timeval tv;
+       int result;
+
+       while (!stopNow)
+               {
+               // 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(&readfds);
+
+               // 2. Add the fd for our client(s) to the fd_set
+               FD_SET(dns_sd_fd, &readfds);
+
+               // 3. Set up the timeout.
+               tv.tv_sec = timeOut;
+               tv.tv_usec = 0;
+
+               result = select(nfds, &readfds, (fd_set*)NULL, (fd_set*)NULL, &tv);
+               if (result > 0)
+                       {
+                       if (FD_ISSET(dns_sd_fd, &readfds)) DNSServiceProcessResult(client);
+                       }
+               else if (result == 0)
+                       myTimerCallBack();
+               else
+                       {
+                       printf("select() returned %d errno %d %s\n", result, errno, strerror(errno));
+                       if (errno != EINTR) stopNow = 1;
+                       }
+               }
+       }
+
+int main(int argc, char **argv)
+       {
+       DNSServiceErrorType err;
+       char *dom;
+       setlinebuf(stdout);             // Want to see lines as they appear, not block buffered
+
+       if (argc < 2) goto Fail;        // Minimum command line is the command name and one argument
+       operation = getopt(argc, (char * const *)argv, "EFBLQRAUNTMI");
+       if (operation == -1) goto Fail;
+
+       switch (operation)
+               {
+               case 'E':       printf("Looking for recommended registration domains:\n");
+                                       err = DNSServiceEnumerateDomains(&client, kDNSServiceFlagsRegistrationDomains, 0, regdom_reply, NULL);
+                                       break;
+
+               case 'F':       printf("Looking for recommended browsing domains:\n");
+                                       err = DNSServiceEnumerateDomains(&client, kDNSServiceFlagsBrowseDomains, 0, browsedom_reply, NULL);
+                                       break;
+
+               case 'B':       if (argc < optind+1) goto Fail;
+                                       dom = (argc < optind+2) ? "" : argv[optind+1];
+                                       if (dom[0] == '.' && dom[1] == 0) dom[0] = 0;   // We allow '.' on the command line as a synonym for empty string
+                                       printf("Browsing for %s%s\n", argv[optind+0], dom);
+                                       err = DNSServiceBrowse(&client, 0, 0, argv[optind+0], dom, browse_reply, NULL);
+                                       break;
+
+               case 'L':       if (argc < optind+2) goto Fail;
+                                       dom = (argc < optind+3) ? "local" : argv[optind+2];
+                                       if (dom[0] == '.' && dom[1] == 0) dom = "local";   // We allow '.' on the command line as a synonym for "local"
+                                       printf("Lookup %s.%s.%s\n", argv[optind+0], argv[optind+1], dom);
+                                       err = DNSServiceResolve(&client, 0, 0, argv[optind+0], argv[optind+1], dom, resolve_reply, NULL);
+                                       break;
+
+               case 'R':       if (argc < optind+4) goto Fail;
+                                       {
+                                       char *nam = argv[optind+0];
+                                       char *typ = argv[optind+1];
+                                       char *dom = argv[optind+2];
+                                       uint16_t PortAsNumber = atoi(argv[optind+3]);
+                                       Opaque16 registerPort = { { PortAsNumber >> 8, PortAsNumber & 0xFF } };
+                                       char txt[2048];
+                                       char *ptr = txt;
+                                       int i;
+
+                                       if (nam[0] == '.' && nam[1] == 0) nam[0] = 0;   // We allow '.' on the command line as a synonym for empty string
+                                       if (dom[0] == '.' && dom[1] == 0) dom[0] = 0;   // We allow '.' on the command line as a synonym for empty string
+
+                                       for (i = optind+4; i < argc; i++)
+                                               {
+                                               char *len = ptr++;
+                                               *len = strlen(argv[i]);
+                                               strcpy(ptr, argv[i]);
+                                               ptr += *len;
+                                               }
+
+                                       printf("Registering Service %s.%s%s port %s %s\n", nam, typ, dom, argv[optind+3], txt);
+                                       err = DNSServiceRegister(&client, 0, 0, nam, typ, dom, NULL, registerPort.NotAnInteger, ptr-txt, txt, reg_reply, NULL);
+                                       break;
+                                       }
+
+               case 'Q':       {
+                                       if (argc < optind+1) goto Fail;
+                                       uint16_t rrtype  = (argc <= optind+1) ? T_A  : atoi(argv[optind+1]);
+                                       uint16_t rrclass = (argc <= optind+2) ? C_IN : atoi(argv[optind+2]);
+                                       err = DNSServiceQueryRecord(&client, 0, 0, argv[optind+0], rrtype, rrclass, qr_reply, NULL);
+                                       break;
+                                       }
+
+               case 'A':
+               case 'U':
+               case 'N':       {
+                                       Opaque16 registerPort = { { 0x12, 0x34 } };
+                                       static const char TXT[] = "\xC" "First String" "\xD" "Second String" "\xC" "Third String";
+                                       printf("Registering Service Test._testupdate._tcp.local.\n");
+                                       err = DNSServiceRegister(&client, 0, 0, "Test", "_testupdate._tcp.", "", NULL, registerPort.NotAnInteger, sizeof(TXT)-1, TXT, reg_reply, NULL);
+                                       break;
+                                       }
+
+               case 'T':       {
+                                       Opaque16 registerPort = { { 0x23, 0x45 } };
+                                       char TXT[1024];
+                                       unsigned int i;
+                                       for (i=0; i<sizeof(TXT); i++)
+                                               if ((i & 0x1F) == 0) TXT[i] = 0x1F; else TXT[i] = 'A' + (i >> 5);
+                                       printf("Registering Service Test._testlargetxt._tcp.local.\n");
+                                       err = DNSServiceRegister(&client, 0, 0, "Test", "_testlargetxt._tcp.", "", NULL, registerPort.NotAnInteger, sizeof(TXT), TXT, reg_reply, NULL);
+                                       break;
+                                       }
+
+               case 'M':       {
+                                       pid_t pid = getpid();
+                                       Opaque16 registerPort = { { pid >> 8, pid & 0xFF } };
+                                       static const char TXT1[] = "\xC" "First String"  "\xD" "Second String" "\xC" "Third String";
+                                       static const char TXT2[] = "\xD" "Fourth String" "\xC" "Fifth String"  "\xC" "Sixth String";
+                                       printf("Registering Service Test._testdualtxt._tcp.local.\n");
+                                       err = DNSServiceRegister(&client, 0, 0, "Test", "_testdualtxt._tcp.", "", NULL, registerPort.NotAnInteger, sizeof(TXT1)-1, TXT1, reg_reply, NULL);
+                                       if (!err) err = DNSServiceAddRecord(client, &record, 0, T_TXT, sizeof(TXT2)-1, TXT2, 120);
+                                       break;
+                                       }
+
+               case 'I':       {
+                                       pid_t pid = getpid();
+                                       Opaque16 registerPort = { { pid >> 8, pid & 0xFF } };
+                                       static const char TXT[] = "\x09" "Test Data";
+                                       printf("Registering Service Test._testtxt._tcp.local.\n");
+                                       err = DNSServiceRegister(&client, 0, 0, "Test", "_testtxt._tcp.", "", NULL, registerPort.NotAnInteger, 0, NULL, reg_reply, NULL);
+                                       if (!err) err = DNSServiceUpdateRecord(client, NULL, 0, sizeof(TXT)-1, TXT, 120);
+                                       break;
+                                       }
+
+               default: goto Fail;
+               }
+
+       if (!client || err != kDNSServiceErr_NoError) { fprintf(stderr, "DNSService call failed %ld\n", (long int)err); return (-1); }
+       HandleEvents();
+
+       // Be sure to deallocate the DNSServiceRef when you're finished
+       DNSServiceRefDeallocate(client);
+       return 0;
+
+Fail:
+       fprintf(stderr, "%s -E                  (Enumerate recommended registration domains)\n", argv[0]);
+       fprintf(stderr, "%s -F                      (Enumerate recommended browsing domains)\n", argv[0]);
+       fprintf(stderr, "%s -B        <Type> <Domain>        (Browse for services instances)\n", argv[0]);
+       fprintf(stderr, "%s -L <Name> <Type> <Domain>           (Look up a service instance)\n", argv[0]);
+       fprintf(stderr, "%s -R <Name> <Type> <Domain> <Port> [<TXT>...] (Register a service)\n", argv[0]);
+       fprintf(stderr, "%s -Q <FQDN> <rrtype> <rrclass> (Generic query for any record type)\n", argv[0]);
+       fprintf(stderr, "%s -A                      (Test Adding/Updating/Deleting a record)\n", argv[0]);
+       fprintf(stderr, "%s -U                                  (Test updating a TXT record)\n", argv[0]);
+       fprintf(stderr, "%s -N                             (Test adding a large NULL record)\n", argv[0]);
+       fprintf(stderr, "%s -T                            (Test creating a large TXT record)\n", argv[0]);
+       fprintf(stderr, "%s -M      (Test creating a registration with multiple TXT records)\n", argv[0]);
+       fprintf(stderr, "%s -I   (Test registering and then immediately updating TXT record)\n", argv[0]);
+       return 0;
+       }
index e6dbb7066402c7ecdefbc2730bddd63a7d401187..6535aa159e2034dce5c9d89257cfc14abdefc950 100644 (file)
--- a/Makefile
+++ b/Makefile
 
 include /Developer/Makefiles/pb_makefiles/platform.make
 
-MVERS = "mDNSResponder-58.8.1"
+MVERS = "mDNSResponder-66.3"
 
 install:
-       cd "$(SRCROOT)/mDNSMacOSX"; pbxbuild install     OBJROOT=$(OBJROOT) SYMROOT=$(SYMROOT) DSTROOT=$(DSTROOT) MVERS=$(MVERS)
+       cd "$(SRCROOT)/mDNSMacOSX"; xcodebuild install     OBJROOT=$(OBJROOT) SYMROOT=$(SYMROOT) DSTROOT=$(DSTROOT) MVERS=$(MVERS)
 
 installsrc:
        ditto . ${SRCROOT}
 
 installhdrs::
-       cd "$(SRCROOT)/mDNSMacOSX"; pbxbuild installhdrs OBJROOT=$(OBJROOT) SYMROOT=$(SYMROOT) DSTROOT=$(DSTROOT) MVERS=$(MVERS)
+       cd "$(SRCROOT)/mDNSMacOSX"; xcodebuild installhdrs OBJROOT=$(OBJROOT) SYMROOT=$(SYMROOT) DSTROOT=$(DSTROOT) MVERS=$(MVERS)
 
 clean::
        echo clean
index 60abf836f839f2faf4567624dc6f209aa8bc6c42..fa70ecf255e8b0f07420dc45775170e99267a3e4 100644 (file)
@@ -3,7 +3,7 @@ What is mDNSResponder?
 
 The mDNSResponder project is a component of Rendezvous,
 Apple's ease-of-use IP networking initiative:
-<http://developer.apple.com/macosx/rendezvous/index.html>
+<http://developer.apple.com/macosx/rendezvous/>
 
 Apple's Rendezvous software derives from the ongoing standardization
 work of the IETF Zero Configuration Networking Working Group:
@@ -92,16 +92,15 @@ the functions it needs --
 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 a "Platform Support" layer for OS X 10.2
-("Jaguar"), and a "Platform Support" layer for other Posix platforms
-(OS X 10.1, Linux, etc.) Other support layers for platforms like Windows,
-VxWorks, etc. are also planned.
+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.
 
-Note: Developers writing applications for OS X 10.2 ("Jaguar") do not
-need to incorporate this code into their applications, since OS X 10.2
-provides a system service to handle this for them. If every application
-developer were to link-in the mDNSResponder code into their application,
-then we would end up with a situation like the picture below:
+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
+handle this for them. If every application developer were to link-in the
+mDNSResponder code into their application, then we would end up with a
+situation like the picture below:
 
   +------------------+    +------------------+    +------------------+
   |   Application 1  |    |   Application 2  |    |   Application 3  |
@@ -111,13 +110,12 @@ then we would end up with a situation like the picture below:
   | Platform Support |    | Platform Support |    | Platform Support |
   +------------------+    +------------------+    +------------------+
 
-This would not be very efficient. Each separate application would be
-sending their own separate multicast UDP packets and maintaining their
-own list of answers. Because of this, OS X 10.2 provides a common system
-service which client software should access through the
-"DNSServiceDiscovery.h" APIs.
+This would not be very efficient. Each separate application would be sending
+their own separate multicast UDP packets and maintaining their own list of
+answers. Because of this, OS X provides a common system service which client
+software should access through the "/usr/include/dns_sd.h" APIs.
 
-The situation on OS X 10.2 looks more like the picture below:
+The situation on OS X looks more like the picture below:
 
                                    -------------------
                                   /                   \
@@ -129,7 +127,7 @@ The situation on OS X 10.2 looks more like the picture below:
                  | Platform Support |
                  +------------------+
 
-Applications on OS X 10.2 make calls to the single mDNSResponder daemon
+Applications on OS X make calls to the single mDNSResponder daemon
 which implements the mDNS and DNS-SD protocols. 
 
 Vendors of products such as printers, which are closed environments not
@@ -142,4 +140,4 @@ that platform should, where possible, make use of that system service
 instead of embedding their own mDNSResponder.
 
 See ReadMe.txt in the mDNSPosix directory for specific details of
-building an mDNSResponder on a Posix Operating System.
+building an mDNSResponder on a POSIX Operating System.
diff --git a/mDNSCore/DNSCommon.c b/mDNSCore/DNSCommon.c
new file mode 100644 (file)
index 0000000..6e317a9
--- /dev/null
@@ -0,0 +1,1684 @@
+/*
+ * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+
+$Log: DNSCommon.c,v $
+Revision 1.35  2004/06/05 00:14:44  cheshire
+Fix signed/unsigned and other compiler warnings
+
+Revision 1.34  2004/06/04 00:25:25  cheshire
+Fix misaligned write exception that occurs on some platforms
+
+Revision 1.33  2004/06/04 00:16:18  cheshire
+Remove non-portable use of 'inline'
+
+Revision 1.32  2004/06/03 03:09:58  ksekar
+<rdar://problem/3668626>: Garbage Collection for Dynamic Updates
+
+Revision 1.31  2004/05/28 23:42:36  ksekar
+<rdar://problem/3258021>: Feature: DNS server->client notification on record changes (#7805)
+
+Revision 1.30  2004/05/26 09:08:04  bradley
+Added cast to correct structure pointer when allocating domain name list element to fix C++ builds.
+
+Revision 1.29  2004/05/18 23:51:25  cheshire
+Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
+
+Revision 1.28  2004/05/13 04:54:20  ksekar
+Unified list copy/free code.  Added symetric list for
+
+Revision 1.27  2004/04/22 20:29:07  cheshire
+Log error message if no count field passed to PutResourceRecordTTL()
+
+Revision 1.26  2004/04/22 04:07:01  cheshire
+Fix from Bob Bradley: Don't try to do inline functions on compilers that don't support it
+
+Revision 1.25  2004/04/22 03:05:28  cheshire
+kDNSClass_ANY should be kDNSQClass_ANY
+
+Revision 1.24  2004/04/22 02:51:20  cheshire
+Use common code for HINFO/TXT and TSIG cases in putRData
+
+Revision 1.23  2004/04/15 00:51:28  bradley
+Minor tweaks for Windows and C++ builds. Added casts for signed/unsigned integers and 64-bit pointers.
+Prefix some functions with mDNS to avoid conflicts. Disable benign warnings on Microsoft compilers.
+
+Revision 1.22  2004/04/14 23:09:28  ksekar
+Support for TSIG signed dynamic updates.
+
+Revision 1.21  2004/04/09 16:47:28  cheshire
+<rdar://problem/3617655>: mDNSResponder escape handling inconsistent with BIND
+
+Revision 1.20  2004/04/09 16:37:15  cheshire
+Suggestion from Bob Bradley:
+Move NumCacheRecordsForInterfaceID() to DNSCommon.c so it's available to all platform layers
+
+Revision 1.19  2004/04/02 19:34:38  cheshire
+Fix broken comment
+
+Revision 1.18  2004/03/30 06:45:00  cheshire
+Compiler warning fixes from Don Woodward at Roku Labs
+
+Revision 1.17  2004/03/19 22:25:20  cheshire
+<rdar://problem/3579561>: Need to limit service types to fourteen characters
+Won't actually do this for now, but keep the code around just in case
+
+Revision 1.16  2004/03/08 02:45:35  cheshire
+Minor change to make a couple of the log messages a bit shorter
+
+Revision 1.15  2004/03/08 02:44:09  cheshire
+<rdar://problem/3579561>: Need to limit service types to fourteen characters
+
+Revision 1.14  2004/02/21 02:06:24  cheshire
+Can't use anonymous unions -- they're non-standard and don't work on all compilers
+
+Revision 1.13  2004/02/06 23:04:18  ksekar
+Basic Dynamic Update support via mDNS_Register (dissabled via
+UNICAST_REGISTRATION #define)
+
+Revision 1.12  2004/02/03 22:37:10  cheshire
+Delete unused (commented-out) code
+
+Revision 1.11  2004/02/03 22:35:34  cheshire
+<rdar://problem/3548256>: Should not allow empty string for resolve domain
+
+Revision 1.10  2004/02/03 19:47:36  ksekar
+Added an asyncronous state machine mechanism to uDNS.c, including
+calls to find the parent zone for a domain name.  Changes include code
+in repository previously dissabled via "#if 0 //incomplete".  Codepath
+is currently unused, and will be called to create update records, etc.
+
+Revision 1.9  2004/01/27 20:15:22  cheshire
+<rdar://problem/3541288>: Time to prune obsolete code for listening on port 53
+
+Revision 1.8  2004/01/24 23:24:36  cheshire
+Expanded out the list of local domains to reduce risk of mistakes in future
+
+Revision 1.7  2004/01/24 08:32:30  bradley
+Mask values with 0xFF before casting to avoid runtime truncation errors on Windows debug builds.
+Separated octal-escaped sequences preceding decimal digits to avoid errors with some compilers wanting
+to signal potentially hidden errors about the subsequent digit not being part of the octal sequence.
+
+Revision 1.6  2004/01/24 04:59:15  cheshire
+Fixes so that Posix/Linux, OS9, Windows, and VxWorks targets build again
+
+Revision 1.5  2004/01/23 23:23:14  ksekar
+Added TCP support for truncated unicast messages.
+
+Revision 1.4  2004/01/22 02:15:33  cheshire
+<rdar://problem/3536597>: Link-local reverse-mapping domains need to be resolved using link-local multicast
+
+Revision 1.3  2004/01/21 21:16:29  cheshire
+Minor tidy-up: Deleted a bunch of blank lines, trailing spaces, tabs, etc.
+
+Revision 1.2  2003/12/13 05:47:48  bradley
+Made local ptr const to fix error when assigning from const structure. Disable benign conditional
+expression is constant warning when building with Microsoft compilers.
+
+Revision 1.1  2003/12/13 03:05:27  ksekar
+<rdar://problem/3192548>: DynDNS: Unicast query of service records
+
+ */
+
+// Set mDNS_InstantiateInlines to tell mDNSClientAPI.h to instantiate inline functions, if necessary
+#define mDNS_InstantiateInlines 1
+#include "DNSCommon.h"
+
+// Disable certain benign warnings with Microsoft compilers
+#if (defined(_MSC_VER))
+       // Disable "conditional expression is constant" warning for debug macros.
+       // Otherwise, this generates warnings for the perfectly natural construct "while(1)"
+       // If someone knows a variant way of writing "while(1)" that doesn't generate warning messages, please let us know
+       #pragma warning(disable:4127)
+#endif
+
+// ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - DNameList copy/deallocation routines
+#endif
+
+mDNSexport DNameListElem *mDNS_CopyDNameList(const DNameListElem *orig)
+       {
+       DNameListElem *copy = mDNSNULL, *newelem;
+       const DNameListElem *ptr;
+
+       for (ptr = orig; ptr; ptr = ptr->next)
+               {
+               newelem = (DNameListElem*)mDNSPlatformMemAllocate(sizeof(DNameListElem));
+               if (!newelem) { LogMsg("ERROR: malloc"); return mDNSNULL; }
+               mDNSPlatformStrCopy(ptr->name.c, newelem->name.c);
+               newelem->next = copy;
+               copy = newelem;
+               }
+       return copy;
+       }
+
+mDNSexport void mDNS_FreeDNameList(DNameListElem *list)
+       {
+       DNameListElem *fptr;
+
+       while (list)
+               {
+               fptr = list;
+               list = list->next;
+               mDNSPlatformMemFree(fptr);
+               }
+       }
+
+// ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - General Utility Functions
+#endif
+
+mDNSexport const NetworkInterfaceInfo *GetFirstActiveInterface(const NetworkInterfaceInfo *intf)
+       {
+       while (intf && !intf->InterfaceActive) intf = intf->next;
+       return(intf);
+       }
+
+mDNSexport mDNSInterfaceID GetNextActiveInterfaceID(const NetworkInterfaceInfo *intf)
+       {
+       const NetworkInterfaceInfo *next = GetFirstActiveInterface(intf->next);
+       if (next) return(next->InterfaceID); else return(mDNSNULL);
+       }
+
+mDNSexport mDNSu32 NumCacheRecordsForInterfaceID(const mDNS *const m, mDNSInterfaceID id)
+       {
+       mDNSu32 slot, used = 0;
+       CacheRecord *rr;
+       for (slot = 0; slot < CACHE_HASH_SLOTS; slot++)
+               for (rr = m->rrcache_hash[slot]; rr; rr=rr->next)
+                       if (rr->resrec.InterfaceID == id) used++;
+       return(used);
+       }
+
+mDNSexport char *DNSTypeName(mDNSu16 rrtype)
+       {
+       switch (rrtype)
+               {
+               case kDNSType_A:    return("Addr");
+               case kDNSType_CNAME:return("CNAME");
+               case kDNSType_NULL: return("NULL");
+               case kDNSType_PTR:  return("PTR");
+               case kDNSType_HINFO:return("HINFO");
+               case kDNSType_TXT:  return("TXT");
+               case kDNSType_AAAA: return("AAAA");
+               case kDNSType_SRV:  return("SRV");
+               case kDNSQType_ANY: return("ANY");
+               default:                        {
+                                                       static char buffer[16];
+                                                       mDNS_snprintf(buffer, sizeof(buffer), "(%d)", rrtype);
+                                                       return(buffer);
+                                                       }
+               }
+       }
+
+mDNSexport char *GetRRDisplayString_rdb(mDNS *const m, const ResourceRecord *rr, RDataBody *rd)
+       {
+       char *ptr = m->MsgBuffer;
+       mDNSu32 length = mDNS_snprintf(m->MsgBuffer, 79, "%4d %##s %s ", rr->rdlength, rr->name.c, DNSTypeName(rr->rrtype));
+       switch (rr->rrtype)
+               {
+               case kDNSType_A:        mDNS_snprintf(m->MsgBuffer+length, 79-length, "%.4a", &rd->ip);         break;
+               case kDNSType_CNAME:// Same as PTR
+               case kDNSType_PTR:      mDNS_snprintf(m->MsgBuffer+length, 79-length, "%##s", &rd->name);       break;
+               case kDNSType_HINFO:// Display this the same as TXT (just show first string)
+               case kDNSType_TXT:  mDNS_snprintf(m->MsgBuffer+length, 79-length, "%#s", rd->txt.c);        break;
+               case kDNSType_AAAA:     mDNS_snprintf(m->MsgBuffer+length, 79-length, "%.16a", &rd->ipv6);      break;
+               case kDNSType_SRV:      mDNS_snprintf(m->MsgBuffer+length, 79-length, "%##s", &rd->srv.target); break;
+               default:                        mDNS_snprintf(m->MsgBuffer+length, 79-length, "RDLen %d: %s",
+                                                               rr->rdlength, rd->data);  break;
+               }
+       for (ptr = m->MsgBuffer; *ptr; ptr++) if (*ptr < ' ') *ptr='.';
+       return(m->MsgBuffer);
+       }
+
+mDNSexport mDNSu32 mDNSRandom(mDNSu32 max)
+       {
+       static mDNSu32 seed = 0;
+       mDNSu32 mask = 1;
+
+       if (!seed) seed = (mDNSu32)mDNSPlatformTimeNow();
+       while (mask < max) mask = (mask << 1) | 1;
+       do seed = seed * 21 + 1; while ((seed & mask) > max);
+       return (seed & mask);
+       }
+
+mDNSexport mDNSBool mDNSSameAddress(const mDNSAddr *ip1, const mDNSAddr *ip2)
+       {
+       if (ip1->type == ip2->type)
+               {
+               switch (ip1->type)
+                       {
+                       case mDNSAddrType_IPv4 : return(mDNSBool)(mDNSSameIPv4Address(ip1->ip.v4, ip2->ip.v4));
+                       case mDNSAddrType_IPv6 : return(mDNSBool)(mDNSSameIPv6Address(ip1->ip.v6, ip2->ip.v6));
+                       }
+               }
+       return(mDNSfalse);
+       }
+
+mDNSexport mDNSBool mDNSAddrIsDNSMulticast(const mDNSAddr *ip)
+       {
+       switch(ip->type)
+               {
+               case mDNSAddrType_IPv4: return(mDNSBool)(ip->ip.v4.NotAnInteger == AllDNSLinkGroup.NotAnInteger);
+               case mDNSAddrType_IPv6: return(mDNSBool)(ip->ip.v6.l[0] == AllDNSLinkGroupv6.l[0] &&
+                                                                                                ip->ip.v6.l[1] == AllDNSLinkGroupv6.l[1] &&
+                                                                                                ip->ip.v6.l[2] == AllDNSLinkGroupv6.l[2] &&
+                                                                                                ip->ip.v6.l[3] == AllDNSLinkGroupv6.l[3] );
+               default: return(mDNSfalse);
+               }
+       }
+
+// ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - Domain Name Utility Functions
+#endif
+
+mDNSexport mDNSBool SameDomainLabel(const mDNSu8 *a, const mDNSu8 *b)
+       {
+       int i;
+       const int len = *a++;
+
+       if (len > MAX_DOMAIN_LABEL)
+               { debugf("Malformed label (too long)"); return(mDNSfalse); }
+
+       if (len != *b++) return(mDNSfalse);
+       for (i=0; i<len; i++)
+               {
+               mDNSu8 ac = *a++;
+               mDNSu8 bc = *b++;
+               if (mDNSIsUpperCase(ac)) ac += 'a' - 'A';
+               if (mDNSIsUpperCase(bc)) bc += 'a' - 'A';
+               if (ac != bc) return(mDNSfalse);
+               }
+       return(mDNStrue);
+       }
+
+mDNSexport mDNSBool SameDomainName(const domainname *const d1, const domainname *const d2)
+       {
+       const mDNSu8 *      a   = d1->c;
+       const mDNSu8 *      b   = d2->c;
+       const mDNSu8 *const max = d1->c + MAX_DOMAIN_NAME;                      // Maximum that's valid
+
+       while (*a || *b)
+               {
+               if (a + 1 + *a >= max)
+                       { debugf("Malformed domain name (more than 255 characters)"); return(mDNSfalse); }
+               if (!SameDomainLabel(a, b)) return(mDNSfalse);
+               a += 1 + *a;
+               b += 1 + *b;
+               }
+
+       return(mDNStrue);
+       }
+
+mDNSexport mDNSBool IsLocalDomain(const domainname *d)
+       {
+       // Domains that are defined to be resolved via link-local multicast are:
+       // local., 254.169.in-addr.arpa., and 0.8.E.F.ip6.arpa.
+       static const domainname *n0 = (domainname*)"\x5" "local";
+       static const domainname *n1 = (domainname*)"\x3" "254" "\x3" "169"                     "\x7" "in-addr" "\x4" "arpa";
+       static const domainname *n2 = (domainname*)"\x1" "0"   "\x1" "8"   "\x1" "e" "\x1" "f" "\x3" "ip6"     "\x4" "arpa";
+
+       const domainname *d1, *d2, *d3, *d4, *d5, *d6;  // Top-level domain, second-level domain, etc.
+       d1 = d2 = d3 = d4 = d5 = d6 = mDNSNULL;
+       while (d->c[0])
+               {
+               d6 = d5; d5 = d4; d4 = d3; d3 = d2; d2 = d1; d1 = d;
+               d = (domainname*)(d->c + 1 + d->c[0]);
+               }
+
+       if (d1 && SameDomainName(d1, n0)) return(mDNStrue);
+       if (d4 && SameDomainName(d4, n1)) return(mDNStrue);
+       if (d6 && SameDomainName(d6, n2)) return(mDNStrue);
+       return(mDNSfalse);
+       }
+
+// Returns length of a domain name INCLUDING the byte for the final null label
+// i.e. for the root label "." it returns one
+// For the FQDN "com." it returns 5 (length byte, three data bytes, final zero)
+// Legal results are 1 (just root label) to 255 (MAX_DOMAIN_NAME)
+// If the given domainname is invalid, result is 256
+mDNSexport mDNSu16 DomainNameLength(const domainname *const name)
+       {
+       const mDNSu8 *src = name->c;
+       while (*src)
+               {
+               if (*src > MAX_DOMAIN_LABEL) return(MAX_DOMAIN_NAME+1);
+               src += 1 + *src;
+               if (src - name->c >= MAX_DOMAIN_NAME) return(MAX_DOMAIN_NAME+1);
+               }
+       return((mDNSu16)(src - name->c + 1));
+       }
+
+// CompressedDomainNameLength returns the length of a domain name INCLUDING the byte
+// for the final null label i.e. for the root label "." it returns one.
+// E.g. for the FQDN "foo.com." it returns 9
+// (length, three data bytes, length, three more data bytes, final zero).
+// In the case where a parent domain name is provided, and the given name is a child
+// of that parent, CompressedDomainNameLength returns the length of the prefix portion
+// of the child name, plus TWO bytes for the compression pointer.
+// E.g. for the name "foo.com." with parent "com.", it returns 6
+// (length, three data bytes, two-byte compression pointer).
+mDNSexport mDNSu16 CompressedDomainNameLength(const domainname *const name, const domainname *parent)
+       {
+       const mDNSu8 *src = name->c;
+       if (parent && parent->c[0] == 0) parent = mDNSNULL;
+       while (*src)
+               {
+               if (*src > MAX_DOMAIN_LABEL) return(MAX_DOMAIN_NAME+1);
+               if (parent && SameDomainName((domainname *)src, parent)) return((mDNSu16)(src - name->c + 2));
+               src += 1 + *src;
+               if (src - name->c >= MAX_DOMAIN_NAME) return(MAX_DOMAIN_NAME+1);
+               }
+       return((mDNSu16)(src - name->c + 1));
+       }
+
+// AppendLiteralLabelString appends a single label to an existing (possibly empty) domainname.
+// The C string contains the label as-is, with no escaping, etc.
+// Any dots in the name are literal dots, not label separators
+// If successful, AppendLiteralLabelString returns a pointer to the next unused byte
+// in the domainname bufer (i.e., the next byte after the terminating zero).
+// If unable to construct a legal domain name (i.e. label more than 63 bytes, or total more than 255 bytes)
+// AppendLiteralLabelString returns mDNSNULL.
+mDNSexport mDNSu8 *AppendLiteralLabelString(domainname *const name, const char *cstr)
+       {
+       mDNSu8       *      ptr  = name->c + DomainNameLength(name) - 1;        // Find end of current name
+       const mDNSu8 *const lim1 = name->c + MAX_DOMAIN_NAME - 1;                       // Limit of how much we can add (not counting final zero)
+       const mDNSu8 *const lim2 = ptr + 1 + MAX_DOMAIN_LABEL;
+       const mDNSu8 *const lim  = (lim1 < lim2) ? lim1 : lim2;
+       mDNSu8       *lengthbyte = ptr++;                                                                       // Record where the length is going to go
+
+       while (*cstr && ptr < lim) *ptr++ = (mDNSu8)*cstr++;    // Copy the data
+       *lengthbyte = (mDNSu8)(ptr - lengthbyte - 1);                   // Fill in the length byte
+       *ptr++ = 0;                                                                                             // Put the null root label on the end
+       if (*cstr) return(mDNSNULL);                                                    // Failure: We didn't successfully consume all input
+       else return(ptr);                                                                               // Success: return new value of ptr
+       }
+
+// AppendDNSNameString appends zero or more labels to an existing (possibly empty) domainname.
+// The C string is in conventional DNS syntax:
+// Textual labels, escaped as necessary using the usual DNS '\' notation, separated by dots.
+// If successful, AppendDNSNameString returns a pointer to the next unused byte
+// in the domainname bufer (i.e., the next byte after the terminating zero).
+// If unable to construct a legal domain name (i.e. label more than 63 bytes, or total more than 255 bytes)
+// AppendDNSNameString returns mDNSNULL.
+mDNSexport mDNSu8 *AppendDNSNameString(domainname *const name, const char *cstr)
+       {
+       mDNSu8       *      ptr = name->c + DomainNameLength(name) - 1; // Find end of current name
+       const mDNSu8 *const lim = name->c + MAX_DOMAIN_NAME - 1;                // Limit of how much we can add (not counting final zero)
+       while (*cstr && ptr < lim)                                                                              // While more characters, and space to put them...
+               {
+               mDNSu8 *lengthbyte = ptr++;                                                                     // Record where the length is going to go
+               while (*cstr && *cstr != '.' && ptr < lim)                                      // While we have characters in the label...
+                       {
+                       mDNSu8 c = (mDNSu8)*cstr++;                                                             // Read the character
+                       if (c == '\\')                                                                                  // If escape character, check next character
+                               {
+                               c = (mDNSu8)*cstr++;                                                            // Assume we'll just take the next character
+                               if (mdnsIsDigit(cstr[-1]) && mdnsIsDigit(cstr[0]) && mdnsIsDigit(cstr[1]))
+                                       {                                                                                               // If three decimal digits,
+                                       int v0 = cstr[-1] - '0';                                                // then interpret as three-digit decimal
+                                       int v1 = cstr[ 0] - '0';
+                                       int v2 = cstr[ 1] - '0';
+                                       int val = v0 * 100 + v1 * 10 + v2;
+                                       if (val <= 255) { c = (mDNSu8)val; cstr += 2; } // If valid three-digit decimal value, use it
+                                       }
+                               }
+                       *ptr++ = c;                                                                                             // Write the character
+                       }
+               if (*cstr) cstr++;                                                                                      // Skip over the trailing dot (if present)
+               if (ptr - lengthbyte - 1 > MAX_DOMAIN_LABEL)                            // If illegal label, abort
+                       return(mDNSNULL);
+               *lengthbyte = (mDNSu8)(ptr - lengthbyte - 1);                           // Fill in the length byte
+               }
+
+       *ptr++ = 0;                                                                                                             // Put the null root label on the end
+       if (*cstr) return(mDNSNULL);                                                                    // Failure: We didn't successfully consume all input
+       else return(ptr);                                                                                               // Success: return new value of ptr
+       }
+
+// AppendDomainLabel appends a single label to a name.
+// If successful, AppendDomainLabel returns a pointer to the next unused byte
+// in the domainname bufer (i.e., the next byte after the terminating zero).
+// If unable to construct a legal domain name (i.e. label more than 63 bytes, or total more than 255 bytes)
+// AppendDomainLabel returns mDNSNULL.
+mDNSexport mDNSu8 *AppendDomainLabel(domainname *const name, const domainlabel *const label)
+       {
+       int i;
+       mDNSu8 *ptr = name->c + DomainNameLength(name) - 1;
+
+       // Check label is legal
+       if (label->c[0] > MAX_DOMAIN_LABEL) return(mDNSNULL);
+
+       // Check that ptr + length byte + data bytes + final zero does not exceed our limit
+       if (ptr + 1 + label->c[0] + 1 > name->c + MAX_DOMAIN_NAME) return(mDNSNULL);
+
+       for (i=0; i<=label->c[0]; i++) *ptr++ = label->c[i];    // Copy the label data
+       *ptr++ = 0;                                                             // Put the null root label on the end
+       return(ptr);
+       }
+
+mDNSexport mDNSu8 *AppendDomainName(domainname *const name, const domainname *const append)
+       {
+       mDNSu8       *      ptr = name->c + DomainNameLength(name) - 1; // Find end of current name
+       const mDNSu8 *const lim = name->c + MAX_DOMAIN_NAME - 1;                // Limit of how much we can add (not counting final zero)
+       const mDNSu8 *      src = append->c;
+       while(src[0])
+               {
+               int i;
+               if (ptr + 1 + src[0] > lim) return(mDNSNULL);
+               for (i=0; i<=src[0]; i++) *ptr++ = src[i];
+               *ptr = 0;       // Put the null root label on the end
+               src += i;
+               }
+       return(ptr);
+       }
+
+// MakeDomainLabelFromLiteralString makes a single domain label from a single literal C string (with no escaping).
+// If successful, MakeDomainLabelFromLiteralString returns mDNStrue.
+// If unable to convert the whole string to a legal domain label (i.e. because length is more than 63 bytes) then
+// MakeDomainLabelFromLiteralString makes a legal domain label from the first 63 bytes of the string and returns mDNSfalse.
+// In some cases silently truncated oversized names to 63 bytes is acceptable, so the return result may be ignored.
+// In other cases silent truncation may not be acceptable, so in those cases the calling function needs to check the return result.
+mDNSexport mDNSBool MakeDomainLabelFromLiteralString(domainlabel *const label, const char *cstr)
+       {
+       mDNSu8       *      ptr   = label->c + 1;                                               // Where we're putting it
+       const mDNSu8 *const limit = label->c + 1 + MAX_DOMAIN_LABEL;    // The maximum we can put
+       while (*cstr && ptr < limit) *ptr++ = (mDNSu8)*cstr++;                  // Copy the label
+       label->c[0] = (mDNSu8)(ptr - label->c - 1);                                             // Set the length byte
+       return(*cstr == 0);                                                                                             // Return mDNStrue if we successfully consumed all input
+       }
+
+// MakeDomainNameFromDNSNameString makes a native DNS-format domainname from a C string.
+// The C string is in conventional DNS syntax:
+// Textual labels, escaped as necessary using the usual DNS '\' notation, separated by dots.
+// If successful, MakeDomainNameFromDNSNameString returns a pointer to the next unused byte
+// in the domainname bufer (i.e., the next byte after the terminating zero).
+// If unable to construct a legal domain name (i.e. label more than 63 bytes, or total more than 255 bytes)
+// MakeDomainNameFromDNSNameString returns mDNSNULL.
+mDNSexport mDNSu8 *MakeDomainNameFromDNSNameString(domainname *const name, const char *cstr)
+       {
+       name->c[0] = 0;                                                                 // Make an empty domain name
+       return(AppendDNSNameString(name, cstr));                // And then add this string to it
+       }
+
+mDNSexport char *ConvertDomainLabelToCString_withescape(const domainlabel *const label, char *ptr, char esc)
+       {
+       const mDNSu8 *      src = label->c;                                                     // Domain label we're reading
+       const mDNSu8        len = *src++;                                                       // Read length of this (non-null) label
+       const mDNSu8 *const end = src + len;                                            // Work out where the label ends
+       if (len > MAX_DOMAIN_LABEL) return(mDNSNULL);                           // If illegal label, abort
+       while (src < end)                                                                                       // While we have characters in the label
+               {
+               mDNSu8 c = *src++;
+               if (esc)
+                       {
+                       if (c == '.' || c == esc)                                                       // If character is a dot or the escape character
+                               *ptr++ = esc;                                                                   // Output escape character
+                       else if (c <= ' ')                                                                      // If non-printing ascii,
+                               {                                                                                               // Output decimal escape sequence
+                               *ptr++ = esc;
+                               *ptr++ = (char)  ('0' + (c / 100)     );
+                               *ptr++ = (char)  ('0' + (c /  10) % 10);
+                               c      = (mDNSu8)('0' + (c      ) % 10);
+                               }
+                       }
+               *ptr++ = (char)c;                                                                               // Copy the character
+               }
+       *ptr = 0;                                                                                                       // Null-terminate the string
+       return(ptr);                                                                                            // and return
+       }
+
+// Note: To guarantee that there will be no possible overrun, cstr must be at least MAX_ESCAPED_DOMAIN_NAME (1005 bytes)
+mDNSexport char *ConvertDomainNameToCString_withescape(const domainname *const name, char *ptr, char esc)
+       {
+       const mDNSu8 *src         = name->c;                                                            // Domain name we're reading
+       const mDNSu8 *const max   = name->c + MAX_DOMAIN_NAME;                  // Maximum that's valid
+
+       if (*src == 0) *ptr++ = '.';                                                                    // Special case: For root, just write a dot
+
+       while (*src)                                                                                                    // While more characters in the domain name
+               {
+               if (src + 1 + *src >= max) return(mDNSNULL);
+               ptr = ConvertDomainLabelToCString_withescape((const domainlabel *)src, ptr, esc);
+               if (!ptr) return(mDNSNULL);
+               src += 1 + *src;
+               *ptr++ = '.';                                                                                           // Write the dot after the label
+               }
+
+       *ptr++ = 0;                                                                                                             // Null-terminate the string
+       return(ptr);                                                                                                    // and return
+       }
+
+// RFC 1034 rules:
+// Host names must start with a letter, end with a letter or digit,
+// and have as interior characters only letters, digits, and hyphen.
+// This was subsequently modified in RFC 1123 to allow the first character to be either a letter or a digit
+
+mDNSexport void ConvertUTF8PstringToRFC1034HostLabel(const mDNSu8 UTF8Name[], domainlabel *const hostlabel)
+       {
+       const mDNSu8 *      src  = &UTF8Name[1];
+       const mDNSu8 *const end  = &UTF8Name[1] + UTF8Name[0];
+             mDNSu8 *      ptr  = &hostlabel->c[1];
+       const mDNSu8 *const lim  = &hostlabel->c[1] + MAX_DOMAIN_LABEL;
+       while (src < end)
+               {
+               // Delete apostrophes from source name
+               if (src[0] == '\'') { src++; continue; }                // Standard straight single quote
+               if (src + 2 < end && src[0] == 0xE2 && src[1] == 0x80 && src[2] == 0x99)
+                       { src += 3; continue; } // Unicode curly apostrophe
+               if (ptr < lim)
+                       {
+                       if (mdnsValidHostChar(*src, (ptr > &hostlabel->c[1]), (src < end-1))) *ptr++ = *src;
+                       else if (ptr > &hostlabel->c[1] && ptr[-1] != '-') *ptr++ = '-';
+                       }
+               src++;
+               }
+       while (ptr > &hostlabel->c[1] && ptr[-1] == '-') ptr--; // Truncate trailing '-' marks
+       hostlabel->c[0] = (mDNSu8)(ptr - &hostlabel->c[1]);
+       }
+
+#if MDNS_ENFORCE_SERVICE_TYPE_LENGTH
+mDNSlocal mDNSBool AllowedServiceNameException(const mDNSu8 *const src)
+       {
+       if (SameDomainLabel(src, (mDNSu8*)"\x12_MacOSXDupSuppress")) return(mDNStrue);
+       LogMsg("Application protocol name %#s too long; see <http://www.dns-sd.org/ServiceTypes.html>", src);
+       return(mDNSfalse);
+       }
+#endif
+
+mDNSexport mDNSu8 *ConstructServiceName(domainname *const fqdn,
+       const domainlabel *name, const domainname *type, const domainname *const domain)
+       {
+       int i, len;
+       mDNSu8 *dst = fqdn->c;
+       const mDNSu8 *src;
+       const char *errormsg;
+
+       // 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)
+               {
+               const mDNSu8 *s2 = type->c + 1 + type->c[0];
+               if (type->c[0]  > 0 && type->c[0]  < 0x40 &&
+                       s2[0]       > 0 && s2[0]       < 0x40 &&
+                       s2[1+s2[0]] > 0 && s2[1+s2[0]] < 0x40)
+                       {
+                       name = (domainlabel *)type;
+                       type = (domainname  *)s2;
+                       }
+               }
+
+       if (name && name->c[0])
+               {
+               src = name->c;                                                                  // Put the service name into the domain name
+               len = *src;
+               if (len >= 0x40) { errormsg="Service instance name too long"; goto fail; }
+               for (i=0; i<=len; i++) *dst++ = *src++;
+               }
+       else
+               name = (domainlabel*)"";        // Set this up to be non-null, to avoid errors if we have to call LogMsg() below
+
+       src = type->c;                                                                          // Put the service type into the domain name
+       len = *src;
+#if MDNS_ENFORCE_SERVICE_TYPE_LENGTH
+       if (len < 2 || len > 15)
+               if (!AllowedServiceNameException(src))                  // If length not legal, check our grandfather-exceptions list
+                       { errormsg="Application protocol name must be underscore plus 1-14 characters"; goto fail; }
+#else
+       if (len < 2 || len >= 0x40) { errormsg="Application protocol name should be underscore plus 1-14 characters"; goto fail; }
+#endif
+       if (src[1] != '_') { errormsg="Application protocol name must begin with underscore"; goto fail; }
+       for (i=2; i<=len; i++)
+               if (!mdnsIsLetter(src[i]) && !mdnsIsDigit(src[i]) && src[i] != '-' && src[i] != '_')
+                       { errormsg="Application protocol name must contain only letters, digits, and hyphens"; goto fail; }
+       for (i=0; i<=len; i++) *dst++ = *src++;
+
+       len = *src;
+       if (!(len == 4 && src[1] == '_' &&
+               (((src[2] | 0x20) == 'u' && (src[3] | 0x20) == 'd') || ((src[2] | 0x20) == 't' && (src[3] | 0x20) == 'c')) &&
+               (src[4] | 0x20) == 'p'))
+               { errormsg="Service transport protocol name must be _udp or _tcp"; goto fail; }
+       for (i=0; i<=len; i++) *dst++ = *src++;
+
+       if (*src) { errormsg="Service type must have only two labels"; goto fail; }
+
+       *dst = 0;
+       if (!domain->c[0]) { errormsg="Service domain must be non-empty"; goto fail; }
+       dst = AppendDomainName(fqdn, domain);
+       if (!dst) { errormsg="Service domain too long"; goto fail; }
+       return(dst);
+
+fail:
+       LogMsg("ConstructServiceName: %s: %#s.%##s%##s", errormsg, name->c, type->c, domain->c);
+       return(mDNSNULL);
+       }
+
+mDNSexport mDNSBool DeconstructServiceName(const domainname *const fqdn,
+       domainlabel *const name, domainname *const type, domainname *const domain)
+       {
+       int i, len;
+       const mDNSu8 *src = fqdn->c;
+       const mDNSu8 *max = fqdn->c + MAX_DOMAIN_NAME;
+       mDNSu8 *dst;
+
+       dst = name->c;                                                                          // Extract the service name from the domain name
+       len = *src;
+       if (len >= 0x40) { debugf("DeconstructServiceName: service name too long"); return(mDNSfalse); }
+       for (i=0; i<=len; i++) *dst++ = *src++;
+
+       dst = type->c;                                                                          // Extract the service type from the domain name
+       len = *src;
+       if (len >= 0x40) { debugf("DeconstructServiceName: service type too long"); return(mDNSfalse); }
+       for (i=0; i<=len; i++) *dst++ = *src++;
+
+       len = *src;
+       if (len >= 0x40) { debugf("DeconstructServiceName: service type too long"); return(mDNSfalse); }
+       for (i=0; i<=len; i++) *dst++ = *src++;
+       *dst++ = 0;             // Put the null root label on the end of the service type
+
+       dst = domain->c;                                                                        // Extract the service domain from the domain name
+       while (*src)
+               {
+               len = *src;
+               if (len >= 0x40)
+                       { debugf("DeconstructServiceName: service domain label too long"); return(mDNSfalse); }
+               if (src + 1 + len + 1 >= max)
+                       { debugf("DeconstructServiceName: service domain too long"); return(mDNSfalse); }
+               for (i=0; i<=len; i++) *dst++ = *src++;
+               }
+       *dst++ = 0;             // Put the null root label on the end
+
+       return(mDNStrue);
+       }
+
+// Returns true if a rich text label ends in " (nnn)", or if an RFC 1034
+// name ends in "-nnn", where n is some decimal number.
+mDNSexport mDNSBool LabelContainsSuffix(const domainlabel *const name, const mDNSBool RichText)
+       {
+       mDNSu16 l = name->c[0];
+
+       if (RichText)
+               {
+               if (l < 4) return mDNSfalse;                                                    // Need at least " (2)"
+               if (name->c[l--] != ')') return mDNSfalse;                              // Last char must be ')'
+               if (!mdnsIsDigit(name->c[l])) return mDNSfalse;                 // Preceeded by a digit
+               l--;
+               while (l > 2 && mdnsIsDigit(name->c[l])) l--;                   // Strip off digits
+               return (name->c[l] == '(' && name->c[l - 1] == ' ');
+               }
+       else
+               {
+               if (l < 2) return mDNSfalse;                                                    // Need at least "-2"
+               if (!mdnsIsDigit(name->c[l])) return mDNSfalse;                 // Last char must be a digit
+               l--;
+               while (l > 2 && mdnsIsDigit(name->c[l])) l--;                   // Strip off digits
+               return (name->c[l] == '-');
+               }
+       }
+
+// removes an auto-generated suffix (appended on a name collision) from a label.  caller is
+// responsible for ensuring that the label does indeed contain a suffix.  returns the number
+// from the suffix that was removed.
+mDNSexport mDNSu32 RemoveLabelSuffix(domainlabel *name, mDNSBool RichText)
+       {
+       mDNSu32 val = 0, multiplier = 1;
+
+       // Chop closing parentheses from RichText suffix
+       if (RichText && name->c[0] >= 1 && name->c[name->c[0]] == ')') name->c[0]--;
+
+       // Get any existing numerical suffix off the name
+       while (mdnsIsDigit(name->c[name->c[0]]))
+               { val += (name->c[name->c[0]] - '0') * multiplier; multiplier *= 10; name->c[0]--; }
+
+       // Chop opening parentheses or dash from suffix
+       if (RichText)
+               {
+               if (name->c[0] >= 2 && name->c[name->c[0]] == '(' && name->c[name->c[0]-1] == ' ') name->c[0] -= 2;
+               }
+       else
+               {
+               if (name->c[0] >= 1 && name->c[name->c[0]] == '-') name->c[0] -= 1;
+               }
+
+       return(val);
+       }
+
+// appends a numerical suffix to a label, with the number following a whitespace and enclosed
+// in parentheses (rich text) or following two consecutive hyphens (RFC 1034 domain label).
+mDNSexport void AppendLabelSuffix(domainlabel *name, mDNSu32 val, mDNSBool RichText)
+       {
+       mDNSu32 divisor = 1, chars = 2; // Shortest possible RFC1034 name suffix is 2 characters ("-2")
+       if (RichText) chars = 4;                // Shortest possible RichText suffix is 4 characters (" (2)")
+
+       // Truncate trailing spaces from RichText names
+       if (RichText) while (name->c[name->c[0]] == ' ') name->c[0]--;
+
+       while (val >= divisor * 10) { divisor *= 10; chars++; }
+
+       if (name->c[0] > (mDNSu8)(MAX_DOMAIN_LABEL - chars))
+               {
+               name->c[0] = (mDNSu8)(MAX_DOMAIN_LABEL - chars);
+               // If the following character is a UTF-8 continuation character,
+               // we just chopped a multi-byte UTF-8 character in the middle, so strip back to a safe truncation point
+               while (name->c[0] > 0 && (name->c[name->c[0]+1] & 0xC0) == 0x80) name->c[0]--;
+               }
+
+       if (RichText) { name->c[++name->c[0]] = ' '; name->c[++name->c[0]] = '('; }
+       else          { name->c[++name->c[0]] = '-'; }
+
+       while (divisor)
+               {
+               name->c[++name->c[0]] = (mDNSu8)('0' + val / divisor);
+               val     %= divisor;
+               divisor /= 10;
+               }
+
+       if (RichText) name->c[++name->c[0]] = ')';
+       }
+
+mDNSexport void IncrementLabelSuffix(domainlabel *name, mDNSBool RichText)
+       {
+       mDNSu32 val = 0;
+
+       if (LabelContainsSuffix(name, RichText))
+               val = RemoveLabelSuffix(name, RichText);
+
+       // If no existing suffix, start by renaming "Foo" as "Foo (2)" or "Foo-2" as appropriate.
+       // If existing suffix in the range 2-9, increment it.
+       // If we've had ten conflicts already, there are probably too many hosts trying to use the same name,
+       // so add a random increment to improve the chances of finding an available name next time.
+       if      (val == 0) val = 2;
+       else if (val < 10) val++;
+       else               val += 1 + mDNSRandom(99);
+
+       AppendLabelSuffix(name, val, RichText);
+       }
+
+// ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - Resource Record Utility Functions
+#endif
+
+mDNSexport mDNSu32 RDataHashValue(mDNSu16 const rdlength, const RDataBody *const rdb)
+       {
+       mDNSu32 sum = 0;
+       int i;
+       for (i=0; i+1 < rdlength; i+=2)
+               {
+               sum += (((mDNSu32)(rdb->data[i])) << 8) | rdb->data[i+1];
+               sum = (sum<<3) | (sum>>29);
+               }
+       if (i < rdlength)
+               {
+               sum += ((mDNSu32)(rdb->data[i])) << 8;
+               }
+       return(sum);
+       }
+
+mDNSexport mDNSBool SameRData(const ResourceRecord *const r1, const ResourceRecord *const r2)
+       {
+       if (r1->rrtype     != r2->rrtype)   return(mDNSfalse);
+       if (r1->rdlength   != r2->rdlength) return(mDNSfalse);
+       if (r1->rdatahash  != r2->rdatahash) return(mDNSfalse);
+       if (r1->rdnamehash != r2->rdnamehash) return(mDNSfalse);
+       switch(r1->rrtype)
+               {
+               case kDNSType_CNAME:// Same as PTR
+               case kDNSType_PTR:      return(SameDomainName(&r1->rdata->u.name, &r2->rdata->u.name));
+
+               case kDNSType_SRV:      return(mDNSBool)(       r1->rdata->u.srv.priority          == r2->rdata->u.srv.priority          &&
+                                                                                               r1->rdata->u.srv.weight            == r2->rdata->u.srv.weight            &&
+                                                                                               r1->rdata->u.srv.port.NotAnInteger == r2->rdata->u.srv.port.NotAnInteger &&
+                                                                                               SameDomainName(&r1->rdata->u.srv.target, &r2->rdata->u.srv.target)       );
+
+               default:                        return(mDNSPlatformMemSame(r1->rdata->u.data, r2->rdata->u.data, r1->rdlength));
+               }
+       }
+
+mDNSexport mDNSBool ResourceRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q)
+       {
+       if (rr->InterfaceID &&
+               q ->InterfaceID &&
+               rr->InterfaceID != q->InterfaceID) return(mDNSfalse);
+
+       // RR type CNAME matches any query type. QTYPE ANY matches any RR type. QCLASS ANY matches any RR class.
+       if (rr->rrtype != kDNSType_CNAME && rr->rrtype  != q->qtype  && q->qtype  != kDNSQType_ANY ) return(mDNSfalse);
+       if (                                rr->rrclass != q->qclass && q->qclass != kDNSQClass_ANY) return(mDNSfalse);
+       return(rr->namehash == q->qnamehash && SameDomainName(&rr->name, &q->qname));
+       }
+
+mDNSexport mDNSu16 GetRDLength(const ResourceRecord *const rr, mDNSBool estimate)
+       {
+       RDataBody *rd = &rr->rdata->u;
+       const domainname *const name = estimate ? &rr->name : mDNSNULL;
+       switch (rr->rrtype)
+               {
+               case kDNSType_A:        return(sizeof(rd->ip));
+               case kDNSType_CNAME:// Same as PTR
+               case kDNSType_NS:   // Same as PTR
+               case kDNSType_PTR:      return(CompressedDomainNameLength(&rd->name, name));
+               case kDNSType_HINFO:return(mDNSu16)(2 + (int)rd->data[0] + (int)rd->data[1 + (int)rd->data[0]]);
+               case kDNSType_NULL:     // Same as TXT -- not self-describing, so have to just trust rdlength
+               case kDNSType_TXT:  return(rr->rdlength); // TXT is not self-describing, so have to just trust rdlength
+               case kDNSType_AAAA:     return(sizeof(rd->ipv6));
+               case kDNSType_SRV:      return(mDNSu16)(6 + CompressedDomainNameLength(&rd->srv.target, name));
+               case kDNSType_SOA:  return (mDNSu16)(CompressedDomainNameLength(&rd->soa.mname, name) +
+                                                                                       CompressedDomainNameLength(&rd->soa.rname, name) +
+                                                                                       5 * sizeof(mDNSOpaque32));
+               case kDNSType_OPT:  return(rr->rdlength);
+               default:                        debugf("Warning! Don't know how to get length of resource type %d", rr->rrtype);
+                                                       return(rr->rdlength);
+               }
+       }
+
+mDNSexport mDNSBool ValidateRData(const mDNSu16 rrtype, const mDNSu16 rdlength, const RData *const rd)
+       {
+       mDNSu16 len;
+       switch(rrtype)
+               {
+               case kDNSType_A:        return(rdlength == sizeof(mDNSv4Addr));
+
+               case kDNSType_NS:       // Same as PTR
+               case kDNSType_MD:       // Same as PTR
+               case kDNSType_MF:       // Same as PTR
+               case kDNSType_CNAME:// Same as PTR
+               //case kDNSType_SOA not checked
+               case kDNSType_MB:       // Same as PTR
+               case kDNSType_MG:       // Same as PTR
+               case kDNSType_MR:       // Same as PTR
+               //case kDNSType_NULL not checked (no specified format, so always valid)
+               //case kDNSType_WKS not checked
+               case kDNSType_PTR:      len = DomainNameLength(&rd->u.name);
+                                                       return(len <= MAX_DOMAIN_NAME && rdlength == len);
+
+               case kDNSType_HINFO:// Same as TXT (roughly)
+               case kDNSType_MINFO:// Same as TXT (roughly)
+               case kDNSType_TXT:  {
+                                                       const mDNSu8 *ptr = rd->u.txt.c;
+                                                       const mDNSu8 *end = rd->u.txt.c + rdlength;
+                                                       while (ptr < end) ptr += 1 + ptr[0];
+                                                       return (ptr == end);
+                                                       }
+
+               case kDNSType_AAAA:     return(rdlength == sizeof(mDNSv6Addr));
+
+               case kDNSType_MX:   len = DomainNameLength(&rd->u.mx.exchange);
+                                                       return(len <= MAX_DOMAIN_NAME && rdlength == 2+len);
+
+               case kDNSType_SRV:      len = DomainNameLength(&rd->u.srv.target);
+                                                       return(len <= MAX_DOMAIN_NAME && rdlength == 6+len);
+
+               default:                        return(mDNStrue);       // Allow all other types without checking
+               }
+       }
+
+// ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark -
+#pragma mark - DNS Message Creation Functions
+#endif
+
+mDNSexport void InitializeDNSMessage(DNSMessageHeader *h, mDNSOpaque16 id, mDNSOpaque16 flags)
+       {
+       h->id             = id;
+       h->flags          = flags;
+       h->numQuestions   = 0;
+       h->numAnswers     = 0;
+       h->numAuthorities = 0;
+       h->numAdditionals = 0;
+       }
+
+mDNSexport const mDNSu8 *FindCompressionPointer(const mDNSu8 *const base, const mDNSu8 *const end, const mDNSu8 *const domname)
+       {
+       const mDNSu8 *result = end - *domname - 1;
+
+       if (*domname == 0) return(mDNSNULL);    // There's no point trying to match just the root label
+
+       // This loop examines each possible starting position in packet, starting end of the packet and working backwards
+       while (result >= base)
+               {
+               // If the length byte and first character of the label match, then check further to see
+               // if this location in the packet will yield a useful name compression pointer.
+               if (result[0] == domname[0] && result[1] == domname[1])
+                       {
+                       const mDNSu8 *name = domname;
+                       const mDNSu8 *targ = result;
+                       while (targ + *name < end)
+                               {
+                               // First see if this label matches
+                               int i;
+                               const mDNSu8 *pointertarget;
+                               for (i=0; i <= *name; i++) if (targ[i] != name[i]) break;
+                               if (i <= *name) break;                                                  // If label did not match, bail out
+                               targ += 1 + *name;                                                              // Else, did match, so advance target pointer
+                               name += 1 + *name;                                                              // and proceed to check next label
+                               if (*name == 0 && *targ == 0) return(result);   // If no more labels, we found a match!
+                               if (*name == 0) break;                                                  // If no more labels to match, we failed, so bail out
+
+                               // The label matched, so now follow the pointer (if appropriate) and then see if the next label matches
+                               if (targ[0] < 0x40) continue;                                   // If length value, continue to check next label
+                               if (targ[0] < 0xC0) break;                                              // If 40-BF, not valid
+                               if (targ+1 >= end) break;                                               // Second byte not present!
+                               pointertarget = base + (((mDNSu16)(targ[0] & 0x3F)) << 8) + targ[1];
+                               if (targ < pointertarget) break;                                // Pointertarget must point *backwards* in the packet
+                               if (pointertarget[0] >= 0x40) break;                    // Pointertarget must point to a valid length byte
+                               targ = pointertarget;
+                               }
+                       }
+               result--;       // We failed to match at this search position, so back up the tentative result pointer and try again
+               }
+       return(mDNSNULL);
+       }
+
+// Put a string of dot-separated labels as length-prefixed labels
+// domainname is a fully-qualified name (i.e. assumed to be ending in a dot, even if it doesn't)
+// msg points to the message we're building (pass mDNSNULL if we don't want to use compression pointers)
+// end points to the end of the message so far
+// ptr points to where we want to put the name
+// limit points to one byte past the end of the buffer that we must not overrun
+// domainname is the name to put
+mDNSexport mDNSu8 *putDomainNameAsLabels(const DNSMessage *const msg,
+       mDNSu8 *ptr, const mDNSu8 *const limit, const domainname *const name)
+       {
+       const mDNSu8 *const base        = (const mDNSu8 *)msg;
+       const mDNSu8 *      np          = name->c;
+       const mDNSu8 *const max         = name->c + MAX_DOMAIN_NAME;    // Maximum that's valid
+       const mDNSu8 *      pointer     = mDNSNULL;
+       const mDNSu8 *const searchlimit = ptr;
+
+       while (*np && ptr < limit-1)            // While we've got characters in the name, and space to write them in the message...
+               {
+               if (*np > MAX_DOMAIN_LABEL)
+                       { LogMsg("Malformed domain name %##s (label more than 63 bytes)", name->c); return(mDNSNULL); }
+
+               // This check correctly allows for the final trailing root label:
+               // e.g.
+               // Suppose our domain name is exactly 255 bytes long, including the final trailing root label.
+               // Suppose np is now at name->c[248], and we're about to write our last non-null label ("local").
+               // We know that max will be at name->c[255]
+               // That means that np + 1 + 5 == max - 1, so we (just) pass the "if" test below, write our
+               // six bytes, then exit the loop, write the final terminating root label, and the domain
+               // name we've written is exactly 255 bytes long, exactly at the correct legal limit.
+               // If the name is one byte longer, then we fail the "if" test below, and correctly bail out.
+               if (np + 1 + *np >= max)
+                       { LogMsg("Malformed domain name %##s (more than 255 bytes)", name->c); return(mDNSNULL); }
+
+               if (base) pointer = FindCompressionPointer(base, searchlimit, np);
+               if (pointer)                                    // Use a compression pointer if we can
+                       {
+                       mDNSu16 offset = (mDNSu16)(pointer - base);
+                       *ptr++ = (mDNSu8)(0xC0 | (offset >> 8));
+                       *ptr++ = (mDNSu8)(        offset &  0xFF);
+                       return(ptr);
+                       }
+               else                                                    // Else copy one label and try again
+                       {
+                       int i;
+                       mDNSu8 len = *np++;
+                       if (ptr + 1 + len >= limit) return(mDNSNULL);
+                       *ptr++ = len;
+                       for (i=0; i<len; i++) *ptr++ = *np++;
+                       }
+               }
+
+       if (ptr < limit)                                                                                                // If we didn't run out of space
+               {
+               *ptr++ = 0;                                                                                                     // Put the final root label
+               return(ptr);                                                                                            // and return
+               }
+
+       return(mDNSNULL);
+       }
+
+mDNSlocal mDNSu8 *putVal16(mDNSu8 *ptr, mDNSu16 val)
+       {
+       ptr[0] = (mDNSu8)((val >> 8 ) & 0xFF);
+       ptr[1] = (mDNSu8)((val      ) & 0xFF);
+       return ptr + sizeof(mDNSOpaque16);
+       }
+
+mDNSlocal mDNSu8 *putOptRData(mDNSu8 *ptr, const mDNSu8 *limit, ResourceRecord *rr)
+       {
+       int nput = 0;
+       rdataOpt *opt;
+       
+       while (nput < rr->rdlength)
+               {
+               // check if space for opt/optlen
+               if (ptr + (2 * sizeof(mDNSu16)) > limit) goto space_err;
+               (mDNSu8 *)opt = rr->rdata->u.data + nput;
+               ptr = putVal16(ptr, opt->opt);
+               ptr = putVal16(ptr, opt->optlen);
+               nput += 2 * sizeof(mDNSu16);
+               if (opt->opt == kDNSOpt_LLQ)
+                       {
+                       if (ptr + sizeof(LLQOptData) > limit) goto space_err;
+                       ptr = putVal16(ptr, opt->OptData.llq.vers);
+                       ptr = putVal16(ptr, opt->OptData.llq.llqOp);
+                       ptr = putVal16(ptr, opt->OptData.llq.err);
+                       mDNSPlatformMemCopy(opt->OptData.llq.id, ptr, 8);  // 8-byte id
+                       ptr += 8;
+                       *(mDNSOpaque32 *)ptr = mDNSOpaque32fromIntVal(opt->OptData.llq.lease);
+                       ptr += sizeof(mDNSOpaque32);
+                       nput += sizeof(LLQOptData);
+                       }
+               else if (opt->opt == kDNSOpt_Lease)
+                       {
+                       if (ptr + sizeof(mDNSs32) > limit) goto space_err;
+                       *(mDNSOpaque32 *)ptr = mDNSOpaque32fromIntVal(opt->OptData.lease);
+                       ptr += sizeof(mDNSs32);
+                       nput += sizeof(mDNSs32);
+                       }
+               else { LogMsg("putOptRData - unknown option %d", opt->opt); return mDNSNULL; }
+               }
+       
+       return ptr;
+
+       space_err:
+       LogMsg("ERROR: putOptRData - out of space");
+       return mDNSNULL;
+       }
+
+mDNSlocal mDNSu16 getVal16(const mDNSu8 **ptr)
+       {
+       mDNSu16 val = (mDNSu16)(((mDNSu16)(*ptr)[0]) << 8 | (*ptr)[1]);
+       *ptr += sizeof(mDNSOpaque16);
+       return val;
+       }
+
+mDNSlocal const mDNSu8 *getOptRdata(const mDNSu8 *ptr, const mDNSu8 *limit, ResourceRecord *rr, mDNSu16 pktRDLen)
+       {
+       int nread = 0;
+       rdataOpt *opt;
+       
+       while (nread < pktRDLen)
+               {
+               opt = (rdataOpt *)(rr->rdata->u.data + nread);
+               // space for opt + optlen
+               if (nread + (2 * sizeof(mDNSu16)) > rr->rdata->MaxRDLength) goto space_err;
+               opt->opt = getVal16(&ptr);
+               opt->optlen = getVal16(&ptr);
+               nread += 2 * sizeof(mDNSu16);
+               if (opt->opt == kDNSOpt_LLQ)
+                       {
+                       if ((unsigned)(limit - ptr) < sizeof(LLQOptData)) goto space_err;
+                       opt->OptData.llq.vers = getVal16(&ptr);
+                       opt->OptData.llq.llqOp = getVal16(&ptr);
+                       opt->OptData.llq.err = getVal16(&ptr);
+                       mDNSPlatformMemCopy(ptr, opt->OptData.llq.id, 8);
+                       ptr += 8;
+                       opt->OptData.llq.lease = (mDNSu32) ((mDNSu32)ptr[0] << 24 | (mDNSu32)ptr[1] << 16 | (mDNSu32)ptr[2] << 8 | ptr[3]);
+                       if (opt->OptData.llq.lease > 0x70000000UL / mDNSPlatformOneSecond)
+                               opt->OptData.llq.lease = 0x70000000UL / mDNSPlatformOneSecond;
+                       ptr += sizeof(mDNSOpaque32);
+                       nread += sizeof(LLQOptData);
+                       }
+               else if (opt->opt == kDNSOpt_Lease)
+                       {
+                       if ((unsigned)(limit - ptr) < sizeof(mDNSs32)) goto space_err;
+
+                       opt->OptData.lease = (mDNSu32) ((mDNSu32)ptr[0] << 24 | (mDNSu32)ptr[1] << 16 | (mDNSu32)ptr[2] << 8 | ptr[3]);
+                       if (opt->OptData.lease > 0x70000000UL / mDNSPlatformOneSecond)
+                               opt->OptData.lease = 0x70000000UL / mDNSPlatformOneSecond;
+                       ptr += sizeof(mDNSs32);
+                       nread += sizeof(mDNSs32);
+                       }
+               else { LogMsg("ERROR: getOptRdata - unknown opt %d", opt->opt); return mDNSNULL; }
+               }
+       
+       rr->rdlength = pktRDLen;
+       return ptr;
+
+       space_err:
+       LogMsg("ERROR: getLLQRdata - out of space");
+       return mDNSNULL;
+       }
+
+mDNSexport mDNSu8 *putRData(const DNSMessage *const msg, mDNSu8 *ptr, const mDNSu8 *const limit, ResourceRecord *rr)
+       {
+       switch (rr->rrtype)
+               {
+               case kDNSType_A:        if (rr->rdlength != 4)
+                                                               {
+                                                               debugf("putRData: Illegal length %d for kDNSType_A", rr->rdlength);
+                                                               return(mDNSNULL);
+                                                               }
+                                                       if (ptr + 4 > limit) return(mDNSNULL);
+                                                       *ptr++ = rr->rdata->u.ip.b[0];
+                                                       *ptr++ = rr->rdata->u.ip.b[1];
+                                                       *ptr++ = rr->rdata->u.ip.b[2];
+                                                       *ptr++ = rr->rdata->u.ip.b[3];
+                                                       return(ptr);
+
+               case kDNSType_CNAME:// Same as PTR
+               case kDNSType_PTR:      return(putDomainNameAsLabels(msg, ptr, limit, &rr->rdata->u.name));
+
+               case kDNSType_AAAA:     if (rr->rdlength != sizeof(rr->rdata->u.ipv6))
+                                                               {
+                                                               debugf("putRData: Illegal length %d for kDNSType_AAAA", rr->rdlength);
+                                                               return(mDNSNULL);
+                                                               }
+                                                       if (ptr + sizeof(rr->rdata->u.ipv6) > limit) return(mDNSNULL);
+                                                       mDNSPlatformMemCopy(&rr->rdata->u.ipv6, ptr, sizeof(rr->rdata->u.ipv6));
+                                                       return(ptr + sizeof(rr->rdata->u.ipv6));
+
+               case kDNSType_SRV:      if (ptr + 6 > limit) return(mDNSNULL);
+                                                       *ptr++ = (mDNSu8)(rr->rdata->u.srv.priority >> 8);
+                                                       *ptr++ = (mDNSu8)(rr->rdata->u.srv.priority &  0xFF);
+                                                       *ptr++ = (mDNSu8)(rr->rdata->u.srv.weight   >> 8);
+                                                       *ptr++ = (mDNSu8)(rr->rdata->u.srv.weight   &  0xFF);
+                                                       *ptr++ = rr->rdata->u.srv.port.b[0];
+                                                       *ptr++ = rr->rdata->u.srv.port.b[1];
+                                                       return(putDomainNameAsLabels(msg, ptr, limit, &rr->rdata->u.srv.target));
+               case kDNSType_OPT:      return putOptRData(ptr, limit, rr);
+                                                       
+               default:                        debugf("putRData: Warning! Writing unknown resource type %d as raw data", rr->rrtype);
+                                                       // Fall through to common code below
+               case kDNSType_HINFO:
+               case kDNSType_TXT:
+               case kDNSType_TSIG:     if (ptr + rr->rdlength > limit) return(mDNSNULL);
+                                                       mDNSPlatformMemCopy(rr->rdata->u.data, ptr, rr->rdlength);
+                                                       return(ptr + rr->rdlength);
+               }
+       }
+
+mDNSexport mDNSu8 *PutResourceRecordTTL(DNSMessage *const msg, mDNSu8 *ptr, mDNSu16 *count, ResourceRecord *rr, mDNSu32 ttl)
+       {
+       mDNSu8 *endofrdata;
+       mDNSu16 actualLength;
+       const mDNSu8 *limit = msg->data + AbsoluteMaxDNSMessageData;
+
+       // If we have a single large record to put in the packet, then we allow the packet to be up to 9K bytes,
+       // but in the normal case we try to keep the packets below 1500 to avoid IP fragmentation on standard Ethernet
+       if (msg->h.numAnswers || msg->h.numAuthorities || msg->h.numAdditionals)
+               limit = msg->data + NormalMaxDNSMessageData;
+
+       if (rr->RecordType == kDNSRecordTypeUnregistered)
+               {
+               LogMsg("PutResourceRecord ERROR! Attempt to put kDNSRecordTypeUnregistered %##s (%s)", rr->name.c, DNSTypeName(rr->rrtype));
+               return(ptr);
+               }
+
+       ptr = putDomainNameAsLabels(msg, ptr, limit, &rr->name);
+       if (!ptr || ptr + 10 >= limit) return(mDNSNULL);        // If we're out-of-space, return mDNSNULL
+       ptr[0] = (mDNSu8)(rr->rrtype  >> 8);
+       ptr[1] = (mDNSu8)(rr->rrtype  &  0xFF);
+       ptr[2] = (mDNSu8)(rr->rrclass >> 8);
+       ptr[3] = (mDNSu8)(rr->rrclass &  0xFF);
+       ptr[4] = (mDNSu8)((ttl >> 24) &  0xFF);
+       ptr[5] = (mDNSu8)((ttl >> 16) &  0xFF);
+       ptr[6] = (mDNSu8)((ttl >>  8) &  0xFF);
+       ptr[7] = (mDNSu8)( ttl        &  0xFF);
+       endofrdata = putRData(msg, ptr+10, limit, rr);
+       if (!endofrdata) { verbosedebugf("Ran out of space in PutResourceRecord for %##s (%s)", rr->name.c, DNSTypeName(rr->rrtype)); return(mDNSNULL); }
+
+       // Go back and fill in the actual number of data bytes we wrote
+       // (actualLength can be less than rdlength when domain name compression is used)
+       actualLength = (mDNSu16)(endofrdata - ptr - 10);
+       ptr[8] = (mDNSu8)(actualLength >> 8);
+       ptr[9] = (mDNSu8)(actualLength &  0xFF);
+
+       if (count) (*count)++;
+       else LogMsg("PutResourceRecordTTL: ERROR: No target count to update for %##s (%s)", rr->name.c, DNSTypeName(rr->rrtype));
+       return(endofrdata);
+       }
+
+mDNSexport mDNSu8 *PutResourceRecordCappedTTL(DNSMessage *const msg, mDNSu8 *ptr, mDNSu16 *count, ResourceRecord *rr, mDNSu32
+                                                                                          maxttl)
+       {
+       if (maxttl > rr->rroriginalttl) maxttl = rr->rroriginalttl;
+       return(PutResourceRecordTTL(msg, ptr, count, rr, maxttl));
+       }
+
+mDNSexport mDNSu8 *putEmptyResourceRecord(DNSMessage *const msg, mDNSu8 *ptr, const mDNSu8 *const limit,
+       mDNSu16 *count, const AuthRecord *rr)
+       {
+       ptr = putDomainNameAsLabels(msg, ptr, limit, &rr->resrec.name);
+       if (!ptr || ptr + 10 > limit) return(mDNSNULL);         // If we're out-of-space, return mDNSNULL
+       ptr[0] = (mDNSu8)(rr->resrec.rrtype  >> 8);                             // Put type
+       ptr[1] = (mDNSu8)(rr->resrec.rrtype  &  0xFF);
+       ptr[2] = (mDNSu8)(rr->resrec.rrclass >> 8);                             // Put class
+       ptr[3] = (mDNSu8)(rr->resrec.rrclass &  0xFF);
+       ptr[4] = ptr[5] = ptr[6] = ptr[7] = 0;                          // TTL is zero
+       ptr[8] = ptr[9] = 0;                                                            // RDATA length is zero
+       (*count)++;
+       return(ptr + 10);
+       }
+
+mDNSexport mDNSu8 *putQuestion(DNSMessage *const msg, mDNSu8 *ptr, const mDNSu8 *const limit, const domainname *const name, mDNSu16 rrtype, mDNSu16 rrclass)
+       {
+       ptr = putDomainNameAsLabels(msg, ptr, limit, name);
+       if (!ptr || ptr+4 >= limit) return(mDNSNULL);                   // If we're out-of-space, return mDNSNULL
+       ptr[0] = (mDNSu8)(rrtype  >> 8);
+       ptr[1] = (mDNSu8)(rrtype  &  0xFF);
+       ptr[2] = (mDNSu8)(rrclass >> 8);
+       ptr[3] = (mDNSu8)(rrclass &  0xFF);
+       msg->h.numQuestions++;
+       return(ptr+4);
+       }
+
+// ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - DNS Message Parsing Functions
+#endif
+
+mDNSexport mDNSu32 DomainNameHashValue(const domainname *const name)
+       {
+       mDNSu32 sum = 0;
+       const mDNSu8 *c;
+
+       for (c = name->c; c[0] != 0 && c[1] != 0; c += 2)
+               {
+               sum += ((mDNSIsUpperCase(c[0]) ? c[0] + 'a' - 'A' : c[0]) << 8) |
+                               (mDNSIsUpperCase(c[1]) ? c[1] + 'a' - 'A' : c[1]);
+               sum = (sum<<3) | (sum>>29);
+               }
+       if (c[0]) sum += ((mDNSIsUpperCase(c[0]) ? c[0] + 'a' - 'A' : c[0]) << 8);
+       return(sum);
+       }
+
+mDNSexport void SetNewRData(ResourceRecord *const rr, RData *NewRData, mDNSu16 rdlength)
+       {
+       domainname *target;
+       if (NewRData)
+               {
+               rr->rdata    = NewRData;
+               rr->rdlength = rdlength;
+               }
+       // Must not try to get target pointer until after updating rr->rdata
+       target = GetRRDomainNameTarget(rr);
+       rr->rdlength   = GetRDLength(rr, mDNSfalse);
+       rr->rdestimate = GetRDLength(rr, mDNStrue);
+       rr->rdatahash  = RDataHashValue(rr->rdlength, &rr->rdata->u);
+       rr->rdnamehash = target ? DomainNameHashValue(target) : 0;
+       }
+
+mDNSexport const mDNSu8 *skipDomainName(const DNSMessage *const msg, const mDNSu8 *ptr, const mDNSu8 *const end)
+       {
+       mDNSu16 total = 0;
+
+       if (ptr < (mDNSu8*)msg || ptr >= end)
+               { debugf("skipDomainName: Illegal ptr not within packet boundaries"); return(mDNSNULL); }
+
+       while (1)                                               // Read sequence of labels
+               {
+               const mDNSu8 len = *ptr++;      // Read length of this label
+               if (len == 0) return(ptr);      // If length is zero, that means this name is complete
+               switch (len & 0xC0)
+                       {
+                       case 0x00:      if (ptr + len >= end)                                   // Remember: expect at least one more byte for the root label
+                                                       { debugf("skipDomainName: Malformed domain name (overruns packet end)"); return(mDNSNULL); }
+                                               if (total + 1 + len >= MAX_DOMAIN_NAME) // Remember: expect at least one more byte for the root label
+                                                       { debugf("skipDomainName: Malformed domain name (more than 255 characters)"); return(mDNSNULL); }
+                                               ptr += len;
+                                               total += 1 + len;
+                                               break;
+
+                       case 0x40:      debugf("skipDomainName: Extended EDNS0 label types 0x%X not supported", len); return(mDNSNULL);
+                       case 0x80:      debugf("skipDomainName: Illegal label length 0x%X", len); return(mDNSNULL);
+                       case 0xC0:      return(ptr+1);
+                       }
+               }
+       }
+
+// Routine to fetch an FQDN from the DNS message, following compression pointers if necessary.
+mDNSexport const mDNSu8 *getDomainName(const DNSMessage *const msg, const mDNSu8 *ptr, const mDNSu8 *const end,
+       domainname *const name)
+       {
+       const mDNSu8 *nextbyte = mDNSNULL;                                      // Record where we got to before we started following pointers
+       mDNSu8       *np = name->c;                                                     // Name pointer
+       const mDNSu8 *const limit = np + MAX_DOMAIN_NAME;       // Limit so we don't overrun buffer
+
+       if (ptr < (mDNSu8*)msg || ptr >= end)
+               { debugf("getDomainName: Illegal ptr not within packet boundaries"); return(mDNSNULL); }
+
+       *np = 0;                                                // Tentatively place the root label here (may be overwritten if we have more labels)
+
+       while (1)                                               // Read sequence of labels
+               {
+               const mDNSu8 len = *ptr++;      // Read length of this label
+               if (len == 0) break;            // If length is zero, that means this name is complete
+               switch (len & 0xC0)
+                       {
+                       int i;
+                       mDNSu16 offset;
+
+                       case 0x00:      if (ptr + len >= end)           // Remember: expect at least one more byte for the root label
+                                                       { debugf("getDomainName: Malformed domain name (overruns packet end)"); return(mDNSNULL); }
+                                               if (np + 1 + len >= limit)      // Remember: expect at least one more byte for the root label
+                                                       { debugf("getDomainName: Malformed domain name (more than 255 characters)"); return(mDNSNULL); }
+                                               *np++ = len;
+                                               for (i=0; i<len; i++) *np++ = *ptr++;
+                                               *np = 0;        // Tentatively place the root label here (may be overwritten if we have more labels)
+                                               break;
+
+                       case 0x40:      debugf("getDomainName: Extended EDNS0 label types 0x%X not supported in name %##s", len, name->c);
+                                               return(mDNSNULL);
+
+                       case 0x80:      debugf("getDomainName: Illegal label length 0x%X in domain name %##s", len, name->c); return(mDNSNULL);
+
+                       case 0xC0:      offset = (mDNSu16)((((mDNSu16)(len & 0x3F)) << 8) | *ptr++);
+                                               if (!nextbyte) nextbyte = ptr;  // Record where we got to before we started following pointers
+                                               ptr = (mDNSu8 *)msg + offset;
+                                               if (ptr < (mDNSu8*)msg || ptr >= end)
+                                                       { debugf("getDomainName: Illegal compression pointer not within packet boundaries"); return(mDNSNULL); }
+                                               if (*ptr & 0xC0)
+                                                       { debugf("getDomainName: Compression pointer must point to real label"); return(mDNSNULL); }
+                                               break;
+                       }
+               }
+
+       if (nextbyte) return(nextbyte);
+       else return(ptr);
+       }
+
+mDNSexport const mDNSu8 *skipResourceRecord(const DNSMessage *msg, const mDNSu8 *ptr, const mDNSu8 *end)
+       {
+       mDNSu16 pktrdlength;
+
+       ptr = skipDomainName(msg, ptr, end);
+       if (!ptr) { debugf("skipResourceRecord: Malformed RR name"); return(mDNSNULL); }
+
+       if (ptr + 10 > end) { debugf("skipResourceRecord: Malformed RR -- no type/class/ttl/len!"); return(mDNSNULL); }
+       pktrdlength = (mDNSu16)((mDNSu16)ptr[8] <<  8 | ptr[9]);
+       ptr += 10;
+       if (ptr + pktrdlength > end) { debugf("skipResourceRecord: RDATA exceeds end of packet"); return(mDNSNULL); }
+
+       return(ptr + pktrdlength);
+       }
+
+mDNSexport const mDNSu8 *GetResourceRecord(mDNS *const m, const DNSMessage * const msg, const mDNSu8 *ptr,
+    const mDNSu8 * const end, const mDNSInterfaceID InterfaceID, mDNSu8 RecordType, CacheRecord *rr, RData *RDataStorage)
+       {
+       mDNSu16 pktrdlength;
+
+       rr->next              = mDNSNULL;
+       rr->resrec.RecordType = RecordType;
+
+       rr->NextInKAList      = mDNSNULL;
+       rr->TimeRcvd          = m->timenow;
+       rr->NextRequiredQuery = m->timenow;             // Will be updated to the real value when we call SetNextCacheCheckTime()
+       rr->LastUsed          = m->timenow;
+       rr->UseCount          = 0;
+       rr->CRActiveQuestion  = mDNSNULL;
+       rr->UnansweredQueries = 0;
+       rr->LastUnansweredTime= 0;
+       rr->MPUnansweredQ     = 0;
+       rr->MPLastUnansweredQT= 0;
+       rr->MPUnansweredKA    = 0;
+       rr->MPExpectingKA     = mDNSfalse;
+       rr->NextInCFList      = mDNSNULL;
+
+       rr->resrec.InterfaceID       = InterfaceID;
+       ptr = getDomainName(msg, ptr, end, &rr->resrec.name);
+       if (!ptr) { debugf("GetResourceRecord: Malformed RR name"); return(mDNSNULL); }
+
+       if (ptr + 10 > end) { debugf("GetResourceRecord: Malformed RR -- no type/class/ttl/len!"); return(mDNSNULL); }
+
+       rr->resrec.rrtype            = (mDNSu16) ((mDNSu16)ptr[0] <<  8 | ptr[1]);
+       rr->resrec.rrclass           = (mDNSu16)(((mDNSu16)ptr[2] <<  8 | ptr[3]) & kDNSClass_Mask);
+       rr->resrec.rroriginalttl     = (mDNSu32) ((mDNSu32)ptr[4] << 24 | (mDNSu32)ptr[5] << 16 | (mDNSu32)ptr[6] << 8 | ptr[7]);
+       if (rr->resrec.rroriginalttl > 0x70000000UL / mDNSPlatformOneSecond && (mDNSs32)rr->resrec.rroriginalttl != -1)
+               rr->resrec.rroriginalttl = 0x70000000UL / mDNSPlatformOneSecond;
+       // Note: We don't have to adjust m->NextCacheCheck here -- this is just getting a record into memory for
+       // us to look at. If we decide to copy it into the cache, then we'll update m->NextCacheCheck accordingly.
+       pktrdlength           = (mDNSu16)((mDNSu16)ptr[8] <<  8 | ptr[9]);
+       if (ptr[2] & (kDNSClass_UniqueRRSet >> 8))
+               rr->resrec.RecordType |= kDNSRecordTypePacketUniqueMask;
+       ptr += 10;
+       if (ptr + pktrdlength > end) { debugf("GetResourceRecord: RDATA exceeds end of packet"); return(mDNSNULL); }
+
+       if (RDataStorage)
+               rr->resrec.rdata = RDataStorage;
+       else
+               {
+               rr->resrec.rdata = (RData*)&rr->rdatastorage;
+               rr->resrec.rdata->MaxRDLength = sizeof(RDataBody);
+               }
+
+       switch (rr->resrec.rrtype)
+               {
+               case kDNSType_A:        rr->resrec.rdata->u.ip.b[0] = ptr[0];
+                                                       rr->resrec.rdata->u.ip.b[1] = ptr[1];
+                                                       rr->resrec.rdata->u.ip.b[2] = ptr[2];
+                                                       rr->resrec.rdata->u.ip.b[3] = ptr[3];
+                                                       break;
+
+               case kDNSType_CNAME:// Same as PTR
+               case kDNSType_NS:
+               case kDNSType_PTR:      if (!getDomainName(msg, ptr, end, &rr->resrec.rdata->u.name))
+                                                               { debugf("GetResourceRecord: Malformed CNAME/PTR RDATA name"); return(mDNSNULL); }
+                                                       //debugf("%##s PTR %##s rdlen %d", rr->resrec.name.c, rr->resrec.rdata->u.name.c, pktrdlength);
+                                                       break;
+
+               case kDNSType_NULL:     //Same as TXT
+               case kDNSType_HINFO://Same as TXT
+               case kDNSType_TXT:  if (pktrdlength > rr->resrec.rdata->MaxRDLength)
+                                                               {
+                                                               debugf("GetResourceRecord: %s rdata size (%d) exceeds storage (%d)",
+                                                                       DNSTypeName(rr->resrec.rrtype), pktrdlength, rr->resrec.rdata->MaxRDLength);
+                                                               return(mDNSNULL);
+                                                               }
+                                                       rr->resrec.rdlength = pktrdlength;
+                                                       mDNSPlatformMemCopy(ptr, rr->resrec.rdata->u.data, pktrdlength);
+                                                       break;
+
+               case kDNSType_AAAA:     mDNSPlatformMemCopy(ptr, &rr->resrec.rdata->u.ipv6, sizeof(rr->resrec.rdata->u.ipv6));
+                                                       break;
+
+               case kDNSType_SRV:      rr->resrec.rdata->u.srv.priority = (mDNSu16)((mDNSu16)ptr[0] <<  8 | ptr[1]);
+                                                       rr->resrec.rdata->u.srv.weight   = (mDNSu16)((mDNSu16)ptr[2] <<  8 | ptr[3]);
+                                                       rr->resrec.rdata->u.srv.port.b[0] = ptr[4];
+                                                       rr->resrec.rdata->u.srv.port.b[1] = ptr[5];
+                                                       if (!getDomainName(msg, ptr+6, end, &rr->resrec.rdata->u.srv.target))
+                                                               { debugf("GetResourceRecord: Malformed SRV RDATA name"); return(mDNSNULL); }
+                                                       //debugf("%##s SRV %##s rdlen %d", rr->resrec.name.c, rr->resrec.rdata->u.srv.target.c, pktrdlength);
+                                                       break;
+
+               case kDNSType_SOA:  if (!getDomainName(msg, ptr, end, &rr->resrec.rdata->u.soa.mname) ||
+                                                          !getDomainName(msg, ptr, end, &rr->resrec.rdata->u.soa.rname))
+                                          { debugf("GetResourceRecord: Malformed SOA RDATA mname/rname"); return mDNSNULL; }
+                                       if ((unsigned)(end - ptr) < 5 * sizeof(mDNSOpaque32))
+                                                               { debugf("GetResourceRecord: Malformed SOA RDATA"); return mDNSNULL; }
+                                       rr->resrec.rdata->u.soa.serial.NotAnInteger = ((mDNSOpaque32 *)ptr)->NotAnInteger;   ptr += 4;
+                                       rr->resrec.rdata->u.soa.refresh.NotAnInteger = ((mDNSOpaque32 *)ptr)->NotAnInteger;  ptr += 4;
+                                       rr->resrec.rdata->u.soa.retry.NotAnInteger = ((mDNSOpaque32 *)ptr)->NotAnInteger;    ptr += 4;
+                                       rr->resrec.rdata->u.soa.expire.NotAnInteger = ((mDNSOpaque32 *)ptr)->NotAnInteger;   ptr += 4;
+                                       rr->resrec.rdata->u.soa.min.NotAnInteger = ((mDNSOpaque32 *)ptr)->NotAnInteger;
+                                       break;
+
+               case kDNSType_OPT:  getOptRdata(ptr, end, &rr->resrec, pktrdlength); break;
+
+               default:                        if (pktrdlength > rr->resrec.rdata->MaxRDLength)
+                                                               {
+                                                               debugf("GetResourceRecord: rdata %d (%s) size (%d) exceeds storage (%d)",
+                                                                       rr->resrec.rrtype, DNSTypeName(rr->resrec.rrtype), pktrdlength, rr->resrec.rdata->MaxRDLength);
+                                                               return(mDNSNULL);
+                                                               }
+                                                       debugf("GetResourceRecord: Warning! Reading resource type %d (%s) as opaque data",
+                                                               rr->resrec.rrtype, DNSTypeName(rr->resrec.rrtype));
+                                                       // Note: Just because we don't understand the record type, that doesn't
+                                                       // mean we fail. The DNS protocol specifies rdlength, so we can
+                                                       // safely skip over unknown records and ignore them.
+                                                       // We also grab a binary copy of the rdata anyway, since the caller
+                                                       // might know how to interpret it even if we don't.
+                                                       rr->resrec.rdlength = pktrdlength;
+                                                       mDNSPlatformMemCopy(ptr, rr->resrec.rdata->u.data, pktrdlength);
+                                                       break;
+               }
+
+       rr->resrec.namehash = DomainNameHashValue(&rr->resrec.name);
+       SetNewRData(&rr->resrec, mDNSNULL, 0);
+
+       return(ptr + pktrdlength);
+       }
+
+mDNSexport const mDNSu8 *skipQuestion(const DNSMessage *msg, const mDNSu8 *ptr, const mDNSu8 *end)
+       {
+       ptr = skipDomainName(msg, ptr, end);
+       if (!ptr) { debugf("skipQuestion: Malformed domain name in DNS question section"); return(mDNSNULL); }
+       if (ptr+4 > end) { debugf("skipQuestion: Malformed DNS question section -- no query type and class!"); return(mDNSNULL); }
+       return(ptr+4);
+       }
+
+mDNSexport const mDNSu8 *getQuestion(const DNSMessage *msg, const mDNSu8 *ptr, const mDNSu8 *end, const mDNSInterfaceID InterfaceID,
+       DNSQuestion *question)
+       {
+       question->InterfaceID = InterfaceID;
+       ptr = getDomainName(msg, ptr, end, &question->qname);
+       if (!ptr) { debugf("Malformed domain name in DNS question section"); return(mDNSNULL); }
+       if (ptr+4 > end) { debugf("Malformed DNS question section -- no query type and class!"); return(mDNSNULL); }
+
+       question->qnamehash = DomainNameHashValue(&question->qname);
+       question->qtype  = (mDNSu16)((mDNSu16)ptr[0] << 8 | ptr[1]);                    // Get type
+       question->qclass = (mDNSu16)((mDNSu16)ptr[2] << 8 | ptr[3]);                    // and class
+       return(ptr+4);
+       }
+
+mDNSexport const mDNSu8 *LocateAnswers(const DNSMessage *const msg, const mDNSu8 *const end)
+       {
+       int i;
+       const mDNSu8 *ptr = msg->data;
+       for (i = 0; i < msg->h.numQuestions && ptr; i++) ptr = skipQuestion(msg, ptr, end);
+       return(ptr);
+       }
+
+mDNSexport const mDNSu8 *LocateAuthorities(const DNSMessage *const msg, const mDNSu8 *const end)
+       {
+       int i;
+       const mDNSu8 *ptr = LocateAnswers(msg, end);
+       for (i = 0; i < msg->h.numAnswers && ptr; i++) ptr = skipResourceRecord(msg, ptr, end);
+       return(ptr);
+       }
+
+mDNSexport const mDNSu8 *LocateAdditionals(const DNSMessage *const msg, const mDNSu8 *const end)
+       {
+       int i;
+       const mDNSu8 *ptr = LocateAuthorities(msg, end);
+       for (i = 0; i < msg->h.numAuthorities; i++) ptr = skipResourceRecord(msg, ptr, end);
+       return (ptr);
+       }
+
+// ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark -
+#pragma mark - Packet Sending Functions
+#endif
+
+mDNSlocal mStatus sendDNSMessage(const mDNS *const m, DNSMessage *const msg, mDNSu8 *end,
+    mDNSInterfaceID InterfaceID, const mDNSAddr *dst, mDNSIPPort dstport, int sd, uDNS_AuthInfo *authInfo)
+       {
+       mStatus status;
+       int nsent;
+       mDNSs32 msglen;
+       mDNSu8 lenbuf[2];
+       mDNSu16 numQuestions   = msg->h.numQuestions;
+       mDNSu16 numAnswers     = msg->h.numAnswers;
+       mDNSu16 numAuthorities = msg->h.numAuthorities;
+       mDNSu16 numAdditionals = msg->h.numAdditionals;
+       mDNSu8 *ptr = (mDNSu8 *)&msg->h.numQuestions;
+
+       // Put all the integer values in IETF byte-order (MSB first, LSB second)
+       *ptr++ = (mDNSu8)(numQuestions   >> 8);
+       *ptr++ = (mDNSu8)(numQuestions   &  0xFF);
+       *ptr++ = (mDNSu8)(numAnswers     >> 8);
+       *ptr++ = (mDNSu8)(numAnswers     &  0xFF);
+       *ptr++ = (mDNSu8)(numAuthorities >> 8);
+       *ptr++ = (mDNSu8)(numAuthorities &  0xFF);
+       *ptr++ = (mDNSu8)(numAdditionals >> 8);
+       *ptr++ = (mDNSu8)(numAdditionals &  0xFF);
+
+       if (authInfo)
+               {
+               end = DNSDigest_SignMessage(msg, &end, &numAdditionals, authInfo);
+               if (!end) return mStatus_UnknownErr;
+               }
+
+       // Send the packet on the wire
+
+       if (sd >= 0)
+               {
+               msglen = (mDNSu16)(end - (mDNSu8 *)msg);
+               lenbuf[0] = (mDNSu8)(msglen >> 8);  // host->network byte conversion
+               lenbuf[1] = (mDNSu8)(msglen &  0xFF);
+               nsent = mDNSPlatformWriteTCP(sd, (char*)lenbuf, 2);
+               //!!!KRS make sure kernel is sending these as 1 packet!
+               if (nsent != 2) goto tcp_error;
+               nsent = mDNSPlatformWriteTCP(sd, (char *)msg, msglen);
+               if (nsent != msglen) goto tcp_error;
+               status = mStatus_NoError;
+               }
+       else
+               {
+               status = mDNSPlatformSendUDP(m, msg, end, InterfaceID, dst, dstport);
+               }
+
+       // Put all the integer values back the way they were before we return
+       msg->h.numQuestions   = numQuestions;
+       msg->h.numAnswers     = numAnswers;
+       msg->h.numAuthorities = numAuthorities;
+       msg->h.numAdditionals = (mDNSu16)(authInfo ? numAdditionals - 1 : numAdditionals);
+
+       return(status);
+
+       tcp_error:
+       LogMsg("sendDNSMessage: error sending message over tcp");
+       return mStatus_UnknownErr;
+
+       }
+
+mDNSexport mStatus mDNSSendDNSMessage_tcp(const mDNS *const m, DNSMessage *const msg, mDNSu8 * end, int sd)
+       {
+       if (sd < 0) { LogMsg("mDNSSendDNSMessage_tcp: invalid desciptor %d", sd); return mStatus_UnknownErr; }
+       return sendDNSMessage(m, msg, end, mDNSInterface_Any, &zeroAddr, zeroIPPort, sd, mDNSNULL);
+       }
+
+mDNSexport mStatus mDNSSendDNSMessage(const mDNS *const m, DNSMessage *const msg, mDNSu8 * end,
+       mDNSInterfaceID InterfaceID, const mDNSAddr *dst, mDNSIPPort dstport)
+       {
+       return sendDNSMessage(m, msg, end, InterfaceID, dst, dstport, -1, mDNSNULL);
+       }
+
+mDNSexport mStatus mDNSSendSignedDNSMessage(const mDNS *const m, DNSMessage *const msg, mDNSu8 * end,
+    mDNSInterfaceID InterfaceID, const mDNSAddr *dst, mDNSIPPort dstport, uDNS_AuthInfo *authInfo)
+       {
+       return sendDNSMessage(m, msg, end, InterfaceID, dst, dstport, -1, authInfo);
+       }
+
+mDNSexport mStatus mDNSSendSignedDNSMessage_tcp(const mDNS *const m, DNSMessage *const msg, mDNSu8 * end, int sd, uDNS_AuthInfo *authInfo)
+       {
+       if (sd < 0) { LogMsg("mDNSSendDNSMessage_tcp: invalid desciptor %d", sd); return mStatus_UnknownErr; }
+       return sendDNSMessage(m, msg, end, mDNSInterface_Any, &zeroAddr, zeroIPPort, sd, authInfo);
+       }
diff --git a/mDNSCore/DNSCommon.h b/mDNSCore/DNSCommon.h
new file mode 100644 (file)
index 0000000..674bb7a
--- /dev/null
@@ -0,0 +1,287 @@
+/*
+ * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+
+$Log: DNSCommon.h,v $
+Revision 1.14  2004/05/28 23:42:36  ksekar
+<rdar://problem/3258021>: Feature: DNS server->client notification on record changes (#7805)
+
+Revision 1.13  2004/05/18 23:51:25  cheshire
+Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
+
+Revision 1.12  2004/04/22 04:03:59  cheshire
+Headers should use "extern" declarations, not "mDNSexport"
+
+Revision 1.11  2004/04/14 23:09:28  ksekar
+Support for TSIG signed dynamic updates.
+
+Revision 1.10  2004/03/13 01:57:33  ksekar
+<rdar://problem/3192546>: DynDNS: Dynamic update of service records
+
+Revision 1.9  2004/02/21 08:56:58  bradley
+Wrap prototypes with extern "C" for C++ builds.
+
+Revision 1.8  2004/02/06 23:04:18  ksekar
+Basic Dynamic Update support via mDNS_Register (dissabled via
+UNICAST_REGISTRATION #define)
+
+Revision 1.7  2004/02/03 19:47:36  ksekar
+Added an asyncronous state machine mechanism to uDNS.c, including
+calls to find the parent zone for a domain name.  Changes include code
+in repository previously dissabled via "#if 0 //incomplete".  Codepath
+is currently unused, and will be called to create update records, etc.
+
+Revision 1.6  2004/01/27 20:15:22  cheshire
+<rdar://problem/3541288>: Time to prune obsolete code for listening on port 53
+
+Revision 1.5  2004/01/24 03:40:56  cheshire
+Move mDNSAddrIsDNSMulticast() from DNSCommon.h to mDNSClientAPI.h so clients can use it
+
+Revision 1.4  2004/01/24 03:38:27  cheshire
+Fix minor syntactic error: Headers should use "extern" declarations, not "mDNSexport"
+
+Revision 1.3  2004/01/23 23:23:14  ksekar
+Added TCP support for truncated unicast messages.
+
+Revision 1.2  2004/01/21 21:12:23  cheshire
+Add missing newline at end of file to make Unix tools happier
+
+Revision 1.1  2003/12/13 03:05:27  ksekar
+<rdar://problem/3192548>: DynDNS: Unicast query of service records
+
+ */
+
+#ifndef __DNSCOMMON_H_
+#define __DNSCOMMON_H_
+
+#include "mDNSClientAPI.h"
+
+#ifdef __cplusplus
+       extern "C" {
+#endif
+
+// ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark - DNS Protocol Constants
+#endif
+
+typedef enum
+       {
+       kDNSFlag0_QR_Mask     = 0x80,           // Query or response?
+       kDNSFlag0_QR_Query    = 0x00,
+       kDNSFlag0_QR_Response = 0x80,
+       
+       kDNSFlag0_OP_Mask     = 0x78,           // Operation type
+       kDNSFlag0_OP_StdQuery = 0x00,
+       kDNSFlag0_OP_Iquery   = 0x08,
+       kDNSFlag0_OP_Status   = 0x10,
+       kDNSFlag0_OP_Unused3  = 0x18,
+       kDNSFlag0_OP_Notify   = 0x20,
+       kDNSFlag0_OP_Update   = 0x28,
+       
+       kDNSFlag0_QROP_Mask   = kDNSFlag0_QR_Mask | kDNSFlag0_OP_Mask,
+       
+       kDNSFlag0_AA          = 0x04,           // Authoritative Answer?
+       kDNSFlag0_TC          = 0x02,           // Truncated?
+       kDNSFlag0_RD          = 0x01,           // Recursion Desired?
+       kDNSFlag1_RA          = 0x80,           // Recursion Available?
+       
+       kDNSFlag1_Zero        = 0x40,           // Reserved; must be zero
+       kDNSFlag1_AD          = 0x20,           // Authentic Data [RFC 2535]
+       kDNSFlag1_CD          = 0x10,           // Checking Disabled [RFC 2535]
+
+       kDNSFlag1_RC          = 0x0F,           // Response code
+       kDNSFlag1_RC_NoErr    = 0x00,
+       kDNSFlag1_RC_FmtErr   = 0x01,
+       kDNSFlag1_RC_SrvErr   = 0x02,
+       kDNSFlag1_RC_NXDomain = 0x03,
+       kDNSFlag1_RC_NotImpl  = 0x04,
+       kDNSFlag1_RC_Refused  = 0x05,
+       kDNSFlag1_RC_YXDomain = 0x06,
+       kDNSFlag1_RC_YXRRSet  = 0x07,
+       kDNSFlag1_RC_NXRRSet  = 0x08,
+       kDNSFlag1_RC_NotAuth  = 0x09,
+       kDNSFlag1_RC_NotZone  = 0x0A
+       } DNS_Flags;
+
+// ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - General Utility Functions
+#endif
+
+extern const NetworkInterfaceInfo *GetFirstActiveInterface(const NetworkInterfaceInfo *intf);
+extern mDNSInterfaceID GetNextActiveInterfaceID(const NetworkInterfaceInfo *intf);
+
+extern mDNSu32 mDNSRandom(mDNSu32 max);
+
+#define mDNSSameIPv4Address(A,B) ((A).NotAnInteger == (B).NotAnInteger)
+#define mDNSSameIPv6Address(A,B) ((A).l[0] == (B).l[0] && (A).l[1] == (B).l[1] && (A).l[2] == (B).l[2] && (A).l[3] == (B).l[3])
+
+#define mDNSIPv4AddressIsZero(A) mDNSSameIPv4Address((A), zeroIPAddr)
+#define mDNSIPv6AddressIsZero(A) mDNSSameIPv6Address((A), zerov6Addr)
+
+#define mDNSIPv4AddressIsOnes(A) mDNSSameIPv4Address((A), onesIPv4Addr)
+#define mDNSIPv6AddressIsOnes(A) mDNSSameIPv6Address((A), onesIPv6Addr)
+
+#define mDNSAddressIsZero(X) (                                              \
+       ((X)->type == mDNSAddrType_IPv4 && mDNSIPv4AddressIsZero((X)->ip.v4)) || \
+       ((X)->type == mDNSAddrType_IPv6 && mDNSIPv6AddressIsZero((X)->ip.v6))    )
+
+#define mDNSAddressIsOnes(X) (                                              \
+       ((X)->type == mDNSAddrType_IPv4 && mDNSIPv4AddressIsOnes((X)->ip.v4)) || \
+       ((X)->type == mDNSAddrType_IPv6 && mDNSIPv6AddressIsOnes((X)->ip.v6))    )
+
+#define mDNSAddressIsValid(X) (                                                                                             \
+       ((X)->type == mDNSAddrType_IPv4) ? !(mDNSIPv4AddressIsZero((X)->ip.v4) || mDNSIPv4AddressIsOnes((X)->ip.v4)) :          \
+       ((X)->type == mDNSAddrType_IPv6) ? !(mDNSIPv6AddressIsZero((X)->ip.v6) || mDNSIPv6AddressIsOnes((X)->ip.v6)) : mDNSfalse)
+
+
+
+// ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - Domain Name Utility Functions
+#endif
+
+#define mdnsIsDigit(X)     ((X) >= '0' && (X) <= '9')
+#define mDNSIsUpperCase(X) ((X) >= 'A' && (X) <= 'Z')
+#define mDNSIsLowerCase(X) ((X) >= 'a' && (X) <= 'z')
+#define mdnsIsLetter(X)    (mDNSIsUpperCase(X) || mDNSIsLowerCase(X))
+
+
+#define mdnsValidHostChar(X, notfirst, notlast) (mdnsIsLetter(X) || mdnsIsDigit(X) || ((notfirst) && (notlast) && (X) == '-') )
+
+extern mDNSu16 CompressedDomainNameLength(const domainname *const name, const domainname *parent);
+
+extern mDNSBool LabelContainsSuffix(const domainlabel *const name, const mDNSBool RichText);
+extern mDNSu32 RemoveLabelSuffix(domainlabel *name, mDNSBool RichText);
+extern void AppendLabelSuffix(domainlabel *name, mDNSu32 val, mDNSBool RichText);
+extern void mDNS_HostNameCallback(mDNS *const m, AuthRecord *const rr, mStatus result);
+#define ValidateDomainName(N) (DomainNameLength(N) <= MAX_DOMAIN_NAME)
+
+
+// ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - Resource Record Utility Functions
+#endif
+
+extern mDNSu32 RDataHashValue(mDNSu16 const rdlength, const RDataBody *const rdb);
+
+extern mDNSBool SameRData(const ResourceRecord *const r1, const ResourceRecord *const r2);
+
+extern mDNSBool ResourceRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q);
+
+
+extern mDNSu16 GetRDLength(const ResourceRecord *const rr, mDNSBool estimate);
+
+#define GetRRDomainNameTarget(RR) (                                                                          \
+       ((RR)->rrtype == kDNSType_CNAME || (RR)->rrtype == kDNSType_PTR || (RR)->rrtype == kDNSType_NS)          \
+                                                                        ? &(RR)->rdata->u.name       :          \
+       ((RR)->rrtype == kDNSType_SRV                                  ) ? &(RR)->rdata->u.srv.target : mDNSNULL )
+
+extern mDNSBool ValidateRData(const mDNSu16 rrtype, const mDNSu16 rdlength, const RData *const rd);
+
+
+// ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark -
+#pragma mark - DNS Message Creation Functions
+#endif
+
+extern void InitializeDNSMessage(DNSMessageHeader *h, mDNSOpaque16 id, mDNSOpaque16 flags);
+extern const mDNSu8 *FindCompressionPointer(const mDNSu8 *const base, const mDNSu8 *const end, const mDNSu8 *const domname);
+
+extern mDNSu8 *putDomainNameAsLabels(const DNSMessage *const msg, mDNSu8 *ptr, const mDNSu8 *const limit, const domainname *const name);
+       
+extern mDNSu8 *putRData(const DNSMessage *const msg, mDNSu8 *ptr, const mDNSu8 *const limit, ResourceRecord *rr);
+
+extern mDNSu8 *PutResourceRecordTTL(DNSMessage *const msg, mDNSu8 *ptr, mDNSu16 *count, ResourceRecord *rr, mDNSu32 ttl);
+
+extern mDNSu8 *PutResourceRecordCappedTTL(DNSMessage *const msg, mDNSu8 *ptr, mDNSu16 *count, ResourceRecord *rr, mDNSu32 maxttl);
+
+extern mDNSu8 *putEmptyResourceRecord(DNSMessage *const msg, mDNSu8 *ptr, const mDNSu8 *const limit, mDNSu16 *count, const AuthRecord *rr);
+
+extern mDNSu8 *putQuestion(DNSMessage *const msg, mDNSu8 *ptr, const mDNSu8 *const limit, const domainname *const name, mDNSu16 rrtype, mDNSu16 rrclass);
+       
+#define PutResourceRecord(MSG, P, C, RR) PutResourceRecordTTL((MSG), (P), (C), (RR), (RR)->rroriginalttl)
+
+
+// ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - DNS Message Parsing Functions
+#endif
+
+extern mDNSu32 DomainNameHashValue(const domainname *const name);
+
+extern void SetNewRData(ResourceRecord *const rr, RData *NewRData, mDNSu16 rdlength);
+
+
+extern const mDNSu8 *skipDomainName(const DNSMessage *const msg, const mDNSu8 *ptr, const mDNSu8 *const end);
+
+extern const mDNSu8 *getDomainName(const DNSMessage *const msg, const mDNSu8 *ptr, const mDNSu8 *const end,
+       domainname *const name);
+       
+extern const mDNSu8 *skipResourceRecord(const DNSMessage *msg, const mDNSu8 *ptr, const mDNSu8 *end);
+
+extern const mDNSu8 *GetResourceRecord(mDNS *const m, const DNSMessage * const msg, const mDNSu8 *ptr, 
+    const mDNSu8 * const end, const mDNSInterfaceID InterfaceID, mDNSu8 RecordType, CacheRecord *rr, RData *RDataStorage);
+
+extern const mDNSu8 *skipQuestion(const DNSMessage *msg, const mDNSu8 *ptr, const mDNSu8 *end);
+
+extern const mDNSu8 *getQuestion(const DNSMessage *msg, const mDNSu8 *ptr, const mDNSu8 *end, const mDNSInterfaceID InterfaceID,
+       DNSQuestion *question);
+       
+extern const mDNSu8 *LocateAnswers(const DNSMessage *const msg, const mDNSu8 *const end);
+
+extern const mDNSu8 *LocateAuthorities(const DNSMessage *const msg, const mDNSu8 *const end);
+
+extern const mDNSu8 *LocateAdditionals(const DNSMessage *const msg, const mDNSu8 *const end);
+
+#define GetLargeResourceRecord(m, msg, p, e, i, t, L) \
+       (((L)->r.rdatastorage.MaxRDLength = MaximumRDSize), GetResourceRecord((m), (msg), (p), (e), (i), (t), &(L)->r, (RData*)&(L)->r.rdatastorage))
+
+// ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark -
+#pragma mark - Packet Sending Functions
+#endif
+
+extern mStatus mDNSSendDNSMessage(const mDNS *const m, DNSMessage *const msg, mDNSu8 * end, mDNSInterfaceID InterfaceID, const mDNSAddr *dst, mDNSIPPort dstport);
+extern mStatus mDNSSendDNSMessage_tcp(const mDNS *const m, DNSMessage *const msg, mDNSu8 * end, int sd);
+extern mStatus mDNSSendSignedDNSMessage(const mDNS *const m, DNSMessage *const msg, mDNSu8 *end,
+    mDNSInterfaceID InterfaceID, const mDNSAddr *dst, mDNSIPPort dstport, uDNS_AuthInfo *authInfo);
+extern mStatus mDNSSendSignedDNSMessage_tcp(const mDNS *const m, DNSMessage *const msg, mDNSu8 * end, int sd, uDNS_AuthInfo *authInfo);
+       
+#ifdef __cplusplus
+       }
+#endif
+
+#endif // __DNSCOMMON_H_
diff --git a/mDNSCore/DNSDigest.c b/mDNSCore/DNSDigest.c
new file mode 100644 (file)
index 0000000..370e706
--- /dev/null
@@ -0,0 +1,1440 @@
+/*
+ * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+
+$Log: DNSDigest.c,v $
+Revision 1.6  2004/06/02 00:17:46  ksekar
+Referenced original OpenSSL license headers in source file description.
+
+Revision 1.5  2004/05/20 18:37:37  cheshire
+Fix compiler warnings
+
+Revision 1.4  2004/04/22 20:28:20  cheshire
+Use existing facility of PutResourceRecordTTL() to update count field for us
+
+Revision 1.3  2004/04/22 03:05:28  cheshire
+kDNSClass_ANY should be kDNSQClass_ANY
+
+Revision 1.2  2004/04/15 00:51:28  bradley
+Minor tweaks for Windows and C++ builds. Added casts for signed/unsigned integers and 64-bit pointers.
+Prefix some functions with mDNS to avoid conflicts. Disable benign warnings on Microsoft compilers.
+
+Revision 1.1  2004/04/14 23:09:28  ksekar
+Support for TSIG signed dynamic updates.
+
+
+
+*/
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "mDNSClientAPI.h"
+#include "DNSCommon.h"
+
+// Disable certain benign warnings with Microsoft compilers
+#if(defined(_MSC_VER))
+       // Disable "conditional expression is constant" warning for debug macros.
+       // Otherwise, this generates warnings for the perfectly natural construct "while(1)"
+       // If someone knows a variant way of writing "while(1)" that doesn't generate warning messages, please let us know
+       #pragma warning(disable:4127)
+#endif
+
+ // ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark - MD5 Hash Functions
+#endif
+
+
+/* The source for the has is derived CommonCrypto files CommonDigest.h, md32_common.h, md5_locl.h, md5_locl.h, and openssl/md5.h.
+ * The following changes have been made to the original sources:
+ *    replaced CC_LONG w/ mDNSu32
+ *    replaced CC_MD5* with MD5*
+ *    replaced CC_LONG w/ mDNSu32, removed conditional #defines from md5.h
+ *    removed extern decls for MD5_Init/Update/Final from CommonDigest.h
+ *    removed APPLE_COMMON_DIGEST specific #defines from md5_locl.h
+ *
+ * Note: machine archetecure specific conditionals from the original sources are turned off, but are left in the code
+ * to aid in platform-specific optimizations and debugging.
+ * Sources originally distributed under the following license headers:
+ * CommonDigest.c - APSL
+ * 
+ * md32_Common.h
+ * ====================================================================
+ * Copyright (c) 1999-2002 The OpenSSL 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. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    licensing@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED 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 OpenSSL PROJECT 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.
+ *
+ *
+ * md5_dgst.c, md5_locl.h
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ * 
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ * 
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ * 
+ * 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 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. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from 
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ * 
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 AUTHOR 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.
+ * 
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ *
+ */
+
+//from CommonDigest.h
+
+#define MD5_DIGEST_LENGTH      16                      /* digest length in bytes */
+#define MD5_BLOCK_BYTES                64                      /* block size in bytes */
+#define MD5_BLOCK_LONG       (MD5_BLOCK_BYTES / sizeof(mDNSu32))
+
+typedef struct MD5state_st
+{
+       mDNSu32 A,B,C,D;
+       mDNSu32 Nl,Nh;
+       mDNSu32 data[MD5_BLOCK_LONG];
+       int num;
+} MD5_CTX;
+
+
+// from openssl/md5.h
+
+#define MD5_CBLOCK     64
+#define MD5_LBLOCK     (MD5_CBLOCK/4)
+#define MD5_DIGEST_LENGTH 16
+
+int MD5_Init(MD5_CTX *c);
+int MD5_Update(MD5_CTX *c, const void *data, unsigned long len);
+int MD5_Final(unsigned char *md, MD5_CTX *c);
+void MD5_Transform(MD5_CTX *c, const unsigned char *b);
+
+// From md5_locl.h
+
+#ifndef MD5_LONG_LOG2
+#define MD5_LONG_LOG2 2 /* default to 32 bits */
+#endif
+
+#ifdef MD5_ASM
+# if defined(__i386) || defined(__i386__) || defined(_M_IX86) || defined(__INTEL__)
+#  define md5_block_host_order md5_block_asm_host_order
+# elif defined(__sparc) && defined(OPENSSL_SYS_ULTRASPARC)
+   void md5_block_asm_data_order_aligned (MD5_CTX *c, const mDNSu32 *p,int num);
+#  define HASH_BLOCK_DATA_ORDER_ALIGNED md5_block_asm_data_order_aligned
+# endif
+#endif
+
+void md5_block_host_order (MD5_CTX *c, const void *p,int num);
+void md5_block_data_order (MD5_CTX *c, const void *p,int num);
+
+#if defined(__i386) || defined(__i386__) || defined(_M_IX86) || defined(__INTEL__)
+/*
+ * *_block_host_order is expected to handle aligned data while
+ * *_block_data_order - unaligned. As algorithm and host (x86)
+ * are in this case of the same "endianness" these two are
+ * otherwise indistinguishable. But normally you don't want to
+ * call the same function because unaligned access in places
+ * where alignment is expected is usually a "Bad Thing". Indeed,
+ * on RISCs you get punished with BUS ERROR signal or *severe*
+ * performance degradation. Intel CPUs are in turn perfectly
+ * capable of loading unaligned data without such drastic side
+ * effect. Yes, they say it's slower than aligned load, but no
+ * exception is generated and therefore performance degradation
+ * is *incomparable* with RISCs. What we should weight here is
+ * costs of unaligned access against costs of aligning data.
+ * According to my measurements allowing unaligned access results
+ * in ~9% performance improvement on Pentium II operating at
+ * 266MHz. I won't be surprised if the difference will be higher
+ * on faster systems:-)
+ *
+ *                             <appro@fy.chalmers.se>
+ */
+#define md5_block_data_order md5_block_host_order
+#endif
+
+#define DATA_ORDER_IS_LITTLE_ENDIAN
+
+#define HASH_LONG              mDNSu32
+#define HASH_LONG_LOG2 MD5_LONG_LOG2
+#define HASH_CTX               MD5_CTX
+#define HASH_CBLOCK            MD5_CBLOCK
+#define HASH_LBLOCK            MD5_LBLOCK
+
+#define HASH_UPDATE            MD5_Update
+#define HASH_TRANSFORM MD5_Transform
+#define HASH_FINAL             MD5_Final
+
+#define        HASH_MAKE_STRING(c,s)   do {    \
+       unsigned long ll;               \
+       ll=(c)->A; HOST_l2c(ll,(s));    \
+       ll=(c)->B; HOST_l2c(ll,(s));    \
+       ll=(c)->C; HOST_l2c(ll,(s));    \
+       ll=(c)->D; HOST_l2c(ll,(s));    \
+       } while (0)
+#define HASH_BLOCK_HOST_ORDER  md5_block_host_order
+#if !defined(L_ENDIAN) || defined(md5_block_data_order)
+#define        HASH_BLOCK_DATA_ORDER   md5_block_data_order
+/*
+ * Little-endians (Intel and Alpha) feel better without this.
+ * It looks like memcpy does better job than generic
+ * md5_block_data_order on copying-n-aligning input data.
+ * But frankly speaking I didn't expect such result on Alpha.
+ * On the other hand I've got this with egcs-1.0.2 and if
+ * program is compiled with another (better?) compiler it
+ * might turn out other way around.
+ *
+ *                             <appro@fy.chalmers.se>
+ */
+#endif
+
+
+// from md32_common.h
+
+/*
+ * This is a generic 32 bit "collector" for message digest algorithms.
+ * Whenever needed it collects input character stream into chunks of
+ * 32 bit values and invokes a block function that performs actual hash
+ * calculations.
+ *
+ * Porting guide.
+ *
+ * Obligatory macros:
+ *
+ * DATA_ORDER_IS_BIG_ENDIAN or DATA_ORDER_IS_LITTLE_ENDIAN
+ *     this macro defines byte order of input stream.
+ * HASH_CBLOCK
+ *     size of a unit chunk HASH_BLOCK operates on.
+ * HASH_LONG
+ *     has to be at lest 32 bit wide, if it's wider, then
+ *     HASH_LONG_LOG2 *has to* be defined along
+ * HASH_CTX
+ *     context structure that at least contains following
+ *     members:
+ *             typedef struct {
+ *                     ...
+ *                     HASH_LONG       Nl,Nh;
+ *                     HASH_LONG       data[HASH_LBLOCK];
+ *                     int             num;
+ *                     ...
+ *                     } HASH_CTX;
+ * HASH_UPDATE
+ *     name of "Update" function, implemented here.
+ * HASH_TRANSFORM
+ *     name of "Transform" function, implemented here.
+ * HASH_FINAL
+ *     name of "Final" function, implemented here.
+ * HASH_BLOCK_HOST_ORDER
+ *     name of "block" function treating *aligned* input message
+ *     in host byte order, implemented externally.
+ * HASH_BLOCK_DATA_ORDER
+ *     name of "block" function treating *unaligned* input message
+ *     in original (data) byte order, implemented externally (it
+ *     actually is optional if data and host are of the same
+ *     "endianess").
+ * HASH_MAKE_STRING
+ *     macro convering context variables to an ASCII hash string.
+ *
+ * Optional macros:
+ *
+ * B_ENDIAN or L_ENDIAN
+ *     defines host byte-order.
+ * HASH_LONG_LOG2
+ *     defaults to 2 if not states otherwise.
+ * HASH_LBLOCK
+ *     assumed to be HASH_CBLOCK/4 if not stated otherwise.
+ * HASH_BLOCK_DATA_ORDER_ALIGNED
+ *     alternative "block" function capable of treating
+ *     aligned input message in original (data) order,
+ *     implemented externally.
+ *
+ * MD5 example:
+ *
+ *     #define DATA_ORDER_IS_LITTLE_ENDIAN
+ *
+ *     #define HASH_LONG               mDNSu32
+ *     #define HASH_LONG_LOG2  mDNSu32_LOG2
+ *     #define HASH_CTX                MD5_CTX
+ *     #define HASH_CBLOCK             MD5_CBLOCK
+ *     #define HASH_LBLOCK             MD5_LBLOCK
+ *     #define HASH_UPDATE             MD5_Update
+ *     #define HASH_TRANSFORM          MD5_Transform
+ *     #define HASH_FINAL              MD5_Final
+ *     #define HASH_BLOCK_HOST_ORDER   md5_block_host_order
+ *     #define HASH_BLOCK_DATA_ORDER   md5_block_data_order
+ *
+ *                                     <appro@fy.chalmers.se>
+ */
+
+#if !defined(DATA_ORDER_IS_BIG_ENDIAN) && !defined(DATA_ORDER_IS_LITTLE_ENDIAN)
+#error "DATA_ORDER must be defined!"
+#endif
+
+#ifndef HASH_CBLOCK
+#error "HASH_CBLOCK must be defined!"
+#endif
+#ifndef HASH_LONG
+#error "HASH_LONG must be defined!"
+#endif
+#ifndef HASH_CTX
+#error "HASH_CTX must be defined!"
+#endif
+
+#ifndef HASH_UPDATE
+#error "HASH_UPDATE must be defined!"
+#endif
+#ifndef HASH_TRANSFORM
+#error "HASH_TRANSFORM must be defined!"
+#endif
+#ifndef HASH_FINAL
+#error "HASH_FINAL must be defined!"
+#endif
+
+#ifndef HASH_BLOCK_HOST_ORDER
+#error "HASH_BLOCK_HOST_ORDER must be defined!"
+#endif
+
+#if 0
+/*
+ * Moved below as it's required only if HASH_BLOCK_DATA_ORDER_ALIGNED
+ * isn't defined.
+ */
+#ifndef HASH_BLOCK_DATA_ORDER
+#error "HASH_BLOCK_DATA_ORDER must be defined!"
+#endif
+#endif
+
+#ifndef HASH_LBLOCK
+#define HASH_LBLOCK    (HASH_CBLOCK/4)
+#endif
+
+#ifndef HASH_LONG_LOG2
+#define HASH_LONG_LOG2 2
+#endif
+
+/*
+ * Engage compiler specific rotate intrinsic function if available.
+ */
+#undef ROTATE
+#ifndef PEDANTIC
+# if 0 /* defined(_MSC_VER) */
+#  define ROTATE(a,n)  _lrotl(a,n)
+# elif defined(__MWERKS__)
+#  if defined(__POWERPC__)
+#   define ROTATE(a,n) (unsigned MD32_REG_T)__rlwinm((int)a,n,0,31)
+#  elif defined(__MC68K__)
+    /* Motorola specific tweak. <appro@fy.chalmers.se> */
+#   define ROTATE(a,n) ( n<24 ? __rol(a,n) : __ror(a,32-n) )
+#  else
+#   define ROTATE(a,n) __rol(a,n)
+#  endif
+# elif defined(__GNUC__) && __GNUC__>=2 && !defined(OPENSSL_NO_ASM) && !defined(OPENSSL_NO_INLINE_ASM)
+  /*
+   * Some GNU C inline assembler templates. Note that these are
+   * rotates by *constant* number of bits! But that's exactly
+   * what we need here...
+   *
+   *                                   <appro@fy.chalmers.se>
+   */
+#  if defined(__i386) || defined(__i386__) || defined(__x86_64) || defined(__x86_64__)
+#   define ROTATE(a,n) ({ register unsigned int ret;   \
+                               asm (                   \
+                               "roll %1,%0"            \
+                               : "=r"(ret)             \
+                               : "I"(n), "0"(a)        \
+                               : "cc");                \
+                          ret;                         \
+                       })
+#  elif defined(__powerpc) || defined(__ppc)
+#   define ROTATE(a,n) ({ register unsigned int ret;   \
+                               asm (                   \
+                               "rlwinm %0,%1,%2,0,31"  \
+                               : "=r"(ret)             \
+                               : "r"(a), "I"(n));      \
+                          ret;                         \
+                       })
+#  endif
+# endif
+
+/*
+ * Engage compiler specific "fetch in reverse byte order"
+ * intrinsic function if available.
+ */
+# if defined(__GNUC__) && __GNUC__>=2 && !defined(OPENSSL_NO_ASM) && !defined(OPENSSL_NO_INLINE_ASM)
+  /* some GNU C inline assembler templates by <appro@fy.chalmers.se> */
+#  if (defined(__i386) || defined(__i386__) || defined(__x86_64) || defined(__x86_64__)) && !defined(I386_ONLY)
+#   define BE_FETCH32(a)       ({ register unsigned int l=(a);\
+                               asm (                   \
+                               "bswapl %0"             \
+                               : "=r"(l) : "0"(l));    \
+                         l;                            \
+                       })
+#  elif defined(__powerpc)
+#   define LE_FETCH32(a)       ({ register unsigned int l;     \
+                               asm (                   \
+                               "lwbrx %0,0,%1"         \
+                               : "=r"(l)               \
+                               : "r"(a));              \
+                          l;                           \
+                       })
+
+#  elif defined(__sparc) && defined(OPENSSL_SYS_ULTRASPARC)
+#  define LE_FETCH32(a)        ({ register unsigned int l;             \
+                               asm (                           \
+                               "lda [%1]#ASI_PRIMARY_LITTLE,%0"\
+                               : "=r"(l)                       \
+                               : "r"(a));                      \
+                          l;                                   \
+                       })
+#  endif
+# endif
+#endif /* PEDANTIC */
+
+#if HASH_LONG_LOG2==2  /* Engage only if sizeof(HASH_LONG)== 4 */
+/* A nice byte order reversal from Wei Dai <weidai@eskimo.com> */
+#ifdef ROTATE
+/* 5 instructions with rotate instruction, else 9 */
+#define REVERSE_FETCH32(a,l)   (                                       \
+               l=*(const HASH_LONG *)(a),                              \
+               ((ROTATE(l,8)&0x00FF00FF)|(ROTATE((l&0x00FF00FF),24)))  \
+                               )
+#else
+/* 6 instructions with rotate instruction, else 8 */
+#define REVERSE_FETCH32(a,l)   (                               \
+               l=*(const HASH_LONG *)(a),                      \
+               l=(((l>>8)&0x00FF00FF)|((l&0x00FF00FF)<<8)),    \
+               ROTATE(l,16)                                    \
+                               )
+/*
+ * Originally the middle line started with l=(((l&0xFF00FF00)>>8)|...
+ * It's rewritten as above for two reasons:
+ *     - RISCs aren't good at long constants and have to explicitely
+ *       compose 'em with several (well, usually 2) instructions in a
+ *       register before performing the actual operation and (as you
+ *       already realized:-) having same constant should inspire the
+ *       compiler to permanently allocate the only register for it;
+ *     - most modern CPUs have two ALUs, but usually only one has
+ *       circuitry for shifts:-( this minor tweak inspires compiler
+ *       to schedule shift instructions in a better way...
+ *
+ *                             <appro@fy.chalmers.se>
+ */
+#endif
+#endif
+
+#ifndef ROTATE
+#define ROTATE(a,n)     (((a)<<(n))|(((a)&0xffffffff)>>(32-(n))))
+#endif
+
+/*
+ * Make some obvious choices. E.g., HASH_BLOCK_DATA_ORDER_ALIGNED
+ * and HASH_BLOCK_HOST_ORDER ought to be the same if input data
+ * and host are of the same "endianess". It's possible to mask
+ * this with blank #define HASH_BLOCK_DATA_ORDER though...
+ *
+ *                             <appro@fy.chalmers.se>
+ */
+#if defined(B_ENDIAN)
+#  if defined(DATA_ORDER_IS_BIG_ENDIAN)
+#    if !defined(HASH_BLOCK_DATA_ORDER_ALIGNED) && HASH_LONG_LOG2==2
+#      define HASH_BLOCK_DATA_ORDER_ALIGNED    HASH_BLOCK_HOST_ORDER
+#    endif
+#  elif defined(DATA_ORDER_IS_LITTLE_ENDIAN)
+#    ifndef HOST_FETCH32
+#      ifdef LE_FETCH32
+#        define HOST_FETCH32(p,l)      LE_FETCH32(p)
+#      elif defined(REVERSE_FETCH32)
+#        define HOST_FETCH32(p,l)      REVERSE_FETCH32(p,l)
+#      endif
+#    endif
+#  endif
+#elif defined(L_ENDIAN)
+#  if defined(DATA_ORDER_IS_LITTLE_ENDIAN)
+#    if !defined(HASH_BLOCK_DATA_ORDER_ALIGNED) && HASH_LONG_LOG2==2
+#      define HASH_BLOCK_DATA_ORDER_ALIGNED    HASH_BLOCK_HOST_ORDER
+#    endif
+#  elif defined(DATA_ORDER_IS_BIG_ENDIAN)
+#    ifndef HOST_FETCH32
+#      ifdef BE_FETCH32
+#        define HOST_FETCH32(p,l)      BE_FETCH32(p)
+#      elif defined(REVERSE_FETCH32)
+#        define HOST_FETCH32(p,l)      REVERSE_FETCH32(p,l)
+#      endif
+#    endif
+#  endif
+#endif
+
+#if !defined(HASH_BLOCK_DATA_ORDER_ALIGNED)
+#ifndef HASH_BLOCK_DATA_ORDER
+#error "HASH_BLOCK_DATA_ORDER must be defined!"
+#endif
+#endif
+
+#if defined(DATA_ORDER_IS_BIG_ENDIAN)
+
+#define HOST_c2l(c,l)  (l =(((unsigned long)(*((c)++)))<<24),          \
+                        l|=(((unsigned long)(*((c)++)))<<16),          \
+                        l|=(((unsigned long)(*((c)++)))<< 8),          \
+                        l|=(((unsigned long)(*((c)++)))    ),          \
+                        l)
+#define HOST_p_c2l(c,l,n)      {                                       \
+                       switch (n) {                                    \
+                       case 0: l =((unsigned long)(*((c)++)))<<24;     \
+                       case 1: l|=((unsigned long)(*((c)++)))<<16;     \
+                       case 2: l|=((unsigned long)(*((c)++)))<< 8;     \
+                       case 3: l|=((unsigned long)(*((c)++)));         \
+                               } }
+#define HOST_p_c2l_p(c,l,sc,len) {                                     \
+                       switch (sc) {                                   \
+                       case 0: l =((unsigned long)(*((c)++)))<<24;     \
+                               if (--len == 0) break;                  \
+                       case 1: l|=((unsigned long)(*((c)++)))<<16;     \
+                               if (--len == 0) break;                  \
+                       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) {                                    \
+                       case 3: l =((unsigned long)(*(--(c))))<< 8;     \
+                       case 2: l|=((unsigned long)(*(--(c))))<<16;     \
+                       case 1: l|=((unsigned long)(*(--(c))))<<24;     \
+                               } }
+#define HOST_l2c(l,c)  (*((c)++)=(unsigned char)(((l)>>24)&0xff),      \
+                        *((c)++)=(unsigned char)(((l)>>16)&0xff),      \
+                        *((c)++)=(unsigned char)(((l)>> 8)&0xff),      \
+                        *((c)++)=(unsigned char)(((l)    )&0xff),      \
+                        l)
+
+#elif defined(DATA_ORDER_IS_LITTLE_ENDIAN)
+
+#define HOST_c2l(c,l)  (l =(((unsigned long)(*((c)++)))    ),          \
+                        l|=(((unsigned long)(*((c)++)))<< 8),          \
+                        l|=(((unsigned long)(*((c)++)))<<16),          \
+                        l|=(((unsigned long)(*((c)++)))<<24),          \
+                        l)
+#define HOST_p_c2l(c,l,n)      {                                       \
+                       switch (n) {                                    \
+                       case 0: l =((unsigned long)(*((c)++)));         \
+                       case 1: l|=((unsigned long)(*((c)++)))<< 8;     \
+                       case 2: l|=((unsigned long)(*((c)++)))<<16;     \
+                       case 3: l|=((unsigned long)(*((c)++)))<<24;     \
+                               } }
+#define HOST_p_c2l_p(c,l,sc,len) {                                     \
+                       switch (sc) {                                   \
+                       case 0: l =((unsigned long)(*((c)++)));         \
+                               if (--len == 0) break;                  \
+                       case 1: l|=((unsigned long)(*((c)++)))<< 8;     \
+                               if (--len == 0) break;                  \
+                       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) {                                    \
+                       case 3: l =((unsigned long)(*(--(c))))<<16;     \
+                       case 2: l|=((unsigned long)(*(--(c))))<< 8;     \
+                       case 1: l|=((unsigned long)(*(--(c))));         \
+                               } }
+#define HOST_l2c(l,c)  (*((c)++)=(unsigned char)(((l)    )&0xff),      \
+                        *((c)++)=(unsigned char)(((l)>> 8)&0xff),      \
+                        *((c)++)=(unsigned char)(((l)>>16)&0xff),      \
+                        *((c)++)=(unsigned char)(((l)>>24)&0xff),      \
+                        l)
+
+#endif
+
+/*
+ * Time for some action:-)
+ */
+
+int HASH_UPDATE (HASH_CTX *c, const void *data_, mDNSu32 len)
+       {
+       const unsigned char *data=(const unsigned char *)data_;
+       register HASH_LONG * p;
+       register unsigned long l;
+       int sw,sc,ew,ec;
+
+       if (len==0) return 1;
+
+       l=(c->Nl+(len<<3))&0xffffffffL;
+       /* 95-05-24 eay Fixed a bug with the overflow handling, thanks to
+        * Wei Dai <weidai@eskimo.com> for pointing it out. */
+       if (l < c->Nl) /* overflow */
+               c->Nh++;
+       c->Nh+=(len>>29);
+       c->Nl=l;
+
+       if (c->num != 0)
+               {
+               p=c->data;
+               sw=c->num>>2;
+               sc=c->num&0x03;
+
+               if ((c->num+len) >= HASH_CBLOCK)
+                       {
+                       l=p[sw]; HOST_p_c2l(data,l,sc); p[sw++]=l;
+                       for (; sw<HASH_LBLOCK; sw++)
+                               {
+                               HOST_c2l(data,l); p[sw]=l;
+                               }
+                       HASH_BLOCK_HOST_ORDER (c,p,1);
+                       len-=(HASH_CBLOCK-c->num);
+                       c->num=0;
+                       /* drop through and do the rest */
+                       }
+               else
+                       {
+                       c->num+=len;
+                       if ((sc+len) < 4) /* ugly, add char's to a word */
+                               {
+                               l=p[sw]; HOST_p_c2l_p(data,l,sc,len); p[sw]=l;
+                               }
+                       else
+                               {
+                               ew=(c->num>>2);
+                               ec=(c->num&0x03);
+                               if (sc)
+                                       l=p[sw];
+                               HOST_p_c2l(data,l,sc);
+                               p[sw++]=l;
+                               for (; sw < ew; sw++)
+                                       {
+                                       HOST_c2l(data,l); p[sw]=l;
+                                       }
+                               if (ec)
+                                       {
+                                       HOST_c2l_p(data,l,ec); p[sw]=l;
+                                       }
+                               }
+                       return 1;
+                       }
+               }
+
+       sw=(int)(len/HASH_CBLOCK);
+       if (sw > 0)
+               {
+#if defined(HASH_BLOCK_DATA_ORDER_ALIGNED)
+               /*
+                * Note that HASH_BLOCK_DATA_ORDER_ALIGNED gets defined
+                * only if sizeof(HASH_LONG)==4.
+                */
+               if ((((unsigned long)data)%4) == 0)
+                       {
+                       /* data is properly aligned so that we can cast it: */
+                       HASH_BLOCK_DATA_ORDER_ALIGNED (c,(HASH_LONG *)data,sw);
+                       sw*=HASH_CBLOCK;
+                       data+=sw;
+                       len-=sw;
+                       }
+               else
+#if !defined(HASH_BLOCK_DATA_ORDER)
+                       while (sw--)
+                               {
+                               memcpy (p=c->data,data,HASH_CBLOCK);
+                               HASH_BLOCK_DATA_ORDER_ALIGNED(c,p,1);
+                               data+=HASH_CBLOCK;
+                               len-=HASH_CBLOCK;
+                               }
+#endif
+#endif
+#if defined(HASH_BLOCK_DATA_ORDER)
+                       {
+                       HASH_BLOCK_DATA_ORDER(c,data,sw);
+                       sw*=HASH_CBLOCK;
+                       data+=sw;
+                       len-=sw;
+                       }
+#endif
+               }
+
+       if (len!=0)
+               {
+               p = c->data;
+               c->num = (int)len;
+               ew=(int)(len>>2);       /* words to copy */
+               ec=(int)(len&0x03);
+               for (; ew; ew--,p++)
+                       {
+                       HOST_c2l(data,l); *p=l;
+                       }
+               HOST_c2l_p(data,l,ec);
+               *p=l;
+               }
+       return 1;
+       }
+
+
+void HASH_TRANSFORM (HASH_CTX *c, const unsigned char *data)
+       {
+#if defined(HASH_BLOCK_DATA_ORDER_ALIGNED)
+       if ((((unsigned long)data)%4) == 0)
+               /* data is properly aligned so that we can cast it: */
+               HASH_BLOCK_DATA_ORDER_ALIGNED (c,(HASH_LONG *)data,1);
+       else
+#if !defined(HASH_BLOCK_DATA_ORDER)
+               {
+               memcpy (c->data,data,HASH_CBLOCK);
+               HASH_BLOCK_DATA_ORDER_ALIGNED (c,c->data,1);
+               }
+#endif
+#endif
+#if defined(HASH_BLOCK_DATA_ORDER)
+       HASH_BLOCK_DATA_ORDER (c,data,1);
+#endif
+       }
+
+
+int HASH_FINAL (unsigned char *md, HASH_CTX *c)
+       {
+       register HASH_LONG *p;
+       register unsigned long l;
+       register int i,j;
+       static const unsigned char end[4]={0x80,0x00,0x00,0x00};
+       const unsigned char *cp=end;
+
+       /* c->num should definitly have room for at least one more byte. */
+       p=c->data;
+       i=c->num>>2;
+       j=c->num&0x03;
+
+#if 0
+       /* purify often complains about the following line as an
+        * Uninitialized Memory Read.  While this can be true, the
+        * following p_c2l macro will reset l when that case is true.
+        * This is because j&0x03 contains the number of 'valid' bytes
+        * already in p[i].  If and only if j&0x03 == 0, the UMR will
+        * occur but this is also the only time p_c2l will do
+        * l= *(cp++) instead of l|= *(cp++)
+        * Many thanks to Alex Tang <altitude@cic.net> for pickup this
+        * 'potential bug' */
+#ifdef PURIFY
+       if (j==0) p[i]=0; /* Yeah, but that's not the way to fix it:-) */
+#endif
+       l=p[i];
+#else
+       l = (j==0) ? 0 : p[i];
+#endif
+       HOST_p_c2l(cp,l,j); p[i++]=l; /* i is the next 'undefined word' */
+
+       if (i>(HASH_LBLOCK-2)) /* save room for Nl and Nh */
+               {
+               if (i<HASH_LBLOCK) p[i]=0;
+               HASH_BLOCK_HOST_ORDER (c,p,1);
+               i=0;
+               }
+       for (; i<(HASH_LBLOCK-2); i++)
+               p[i]=0;
+
+#if   defined(DATA_ORDER_IS_BIG_ENDIAN)
+       p[HASH_LBLOCK-2]=c->Nh;
+       p[HASH_LBLOCK-1]=c->Nl;
+#elif defined(DATA_ORDER_IS_LITTLE_ENDIAN)
+       p[HASH_LBLOCK-2]=c->Nl;
+       p[HASH_LBLOCK-1]=c->Nh;
+#endif
+       HASH_BLOCK_HOST_ORDER (c,p,1);
+
+#ifndef HASH_MAKE_STRING
+#error "HASH_MAKE_STRING must be defined!"
+#else
+       HASH_MAKE_STRING(c,md);
+#endif
+
+       c->num=0;
+       /* clear stuff, HASH_BLOCK may be leaving some stuff on the stack
+        * but I'm not worried :-)
+       OPENSSL_cleanse((void *)c,sizeof(HASH_CTX));
+        */
+       return 1;
+       }
+
+#ifndef MD32_REG_T
+#define MD32_REG_T long
+/*
+ * This comment was originaly written for MD5, which is why it
+ * discusses A-D. But it basically applies to all 32-bit digests,
+ * which is why it was moved to common header file.
+ *
+ * In case you wonder why A-D are declared as long and not
+ * as mDNSu32. Doing so results in slight performance
+ * boost on LP64 architectures. The catch is we don't
+ * really care if 32 MSBs of a 64-bit register get polluted
+ * with eventual overflows as we *save* only 32 LSBs in
+ * *either* case. Now declaring 'em long excuses the compiler
+ * from keeping 32 MSBs zeroed resulting in 13% performance
+ * improvement under SPARC Solaris7/64 and 5% under AlphaLinux.
+ * Well, to be honest it should say that this *prevents* 
+ * performance degradation.
+ *                             <appro@fy.chalmers.se>
+ * Apparently there're LP64 compilers that generate better
+ * code if A-D are declared int. Most notably GCC-x86_64
+ * generates better code.
+ *                             <appro@fy.chalmers.se>
+ */
+#endif
+
+
+// from md5_locl.h (continued)
+
+/*
+#define        F(x,y,z)        (((x) & (y))  |  ((~(x)) & (z)))
+#define        G(x,y,z)        (((x) & (z))  |  ((y) & (~(z))))
+*/
+
+/* As pointed out by Wei Dai <weidai@eskimo.com>, the above can be
+ * simplified to the code below.  Wei attributes these optimizations
+ * to Peter Gutmann's SHS code, and he attributes it to Rich Schroeppel.
+ */
+#define        F(b,c,d)        ((((c) ^ (d)) & (b)) ^ (d))
+#define        G(b,c,d)        ((((b) ^ (c)) & (d)) ^ (c))
+#define        H(b,c,d)        ((b) ^ (c) ^ (d))
+#define        I(b,c,d)        (((~(d)) | (b)) ^ (c))
+
+#define R0(a,b,c,d,k,s,t) { \
+       a+=((k)+(t)+F((b),(c),(d))); \
+       a=ROTATE(a,s); \
+       a+=b; };\
+
+#define R1(a,b,c,d,k,s,t) { \
+       a+=((k)+(t)+G((b),(c),(d))); \
+       a=ROTATE(a,s); \
+       a+=b; };
+
+#define R2(a,b,c,d,k,s,t) { \
+       a+=((k)+(t)+H((b),(c),(d))); \
+       a=ROTATE(a,s); \
+       a+=b; };
+
+#define R3(a,b,c,d,k,s,t) { \
+       a+=((k)+(t)+I((b),(c),(d))); \
+       a=ROTATE(a,s); \
+       a+=b; };
+       
+// from md5_dgst.c
+
+
+/* Implemented from RFC1321 The MD5 Message-Digest Algorithm
+ */
+
+#define INIT_DATA_A (unsigned long)0x67452301L
+#define INIT_DATA_B (unsigned long)0xefcdab89L
+#define INIT_DATA_C (unsigned long)0x98badcfeL
+#define INIT_DATA_D (unsigned long)0x10325476L
+
+int MD5_Init(MD5_CTX *c)
+       {
+       c->A=INIT_DATA_A;
+       c->B=INIT_DATA_B;
+       c->C=INIT_DATA_C;
+       c->D=INIT_DATA_D;
+       c->Nl=0;
+       c->Nh=0;
+       c->num=0;
+       return 1;
+       }
+
+#ifndef md5_block_host_order
+void md5_block_host_order (MD5_CTX *c, const void *data, int num)
+       {
+       const mDNSu32 *X=(const mDNSu32 *)data;
+       register unsigned MD32_REG_T A,B,C,D;
+
+       A=c->A;
+       B=c->B;
+       C=c->C;
+       D=c->D;
+
+       for (;num--;X+=HASH_LBLOCK)
+               {
+       /* Round 0 */
+       R0(A,B,C,D,X[ 0], 7,0xd76aa478L);
+       R0(D,A,B,C,X[ 1],12,0xe8c7b756L);
+       R0(C,D,A,B,X[ 2],17,0x242070dbL);
+       R0(B,C,D,A,X[ 3],22,0xc1bdceeeL);
+       R0(A,B,C,D,X[ 4], 7,0xf57c0fafL);
+       R0(D,A,B,C,X[ 5],12,0x4787c62aL);
+       R0(C,D,A,B,X[ 6],17,0xa8304613L);
+       R0(B,C,D,A,X[ 7],22,0xfd469501L);
+       R0(A,B,C,D,X[ 8], 7,0x698098d8L);
+       R0(D,A,B,C,X[ 9],12,0x8b44f7afL);
+       R0(C,D,A,B,X[10],17,0xffff5bb1L);
+       R0(B,C,D,A,X[11],22,0x895cd7beL);
+       R0(A,B,C,D,X[12], 7,0x6b901122L);
+       R0(D,A,B,C,X[13],12,0xfd987193L);
+       R0(C,D,A,B,X[14],17,0xa679438eL);
+       R0(B,C,D,A,X[15],22,0x49b40821L);
+       /* Round 1 */
+       R1(A,B,C,D,X[ 1], 5,0xf61e2562L);
+       R1(D,A,B,C,X[ 6], 9,0xc040b340L);
+       R1(C,D,A,B,X[11],14,0x265e5a51L);
+       R1(B,C,D,A,X[ 0],20,0xe9b6c7aaL);
+       R1(A,B,C,D,X[ 5], 5,0xd62f105dL);
+       R1(D,A,B,C,X[10], 9,0x02441453L);
+       R1(C,D,A,B,X[15],14,0xd8a1e681L);
+       R1(B,C,D,A,X[ 4],20,0xe7d3fbc8L);
+       R1(A,B,C,D,X[ 9], 5,0x21e1cde6L);
+       R1(D,A,B,C,X[14], 9,0xc33707d6L);
+       R1(C,D,A,B,X[ 3],14,0xf4d50d87L);
+       R1(B,C,D,A,X[ 8],20,0x455a14edL);
+       R1(A,B,C,D,X[13], 5,0xa9e3e905L);
+       R1(D,A,B,C,X[ 2], 9,0xfcefa3f8L);
+       R1(C,D,A,B,X[ 7],14,0x676f02d9L);
+       R1(B,C,D,A,X[12],20,0x8d2a4c8aL);
+       /* Round 2 */
+       R2(A,B,C,D,X[ 5], 4,0xfffa3942L);
+       R2(D,A,B,C,X[ 8],11,0x8771f681L);
+       R2(C,D,A,B,X[11],16,0x6d9d6122L);
+       R2(B,C,D,A,X[14],23,0xfde5380cL);
+       R2(A,B,C,D,X[ 1], 4,0xa4beea44L);
+       R2(D,A,B,C,X[ 4],11,0x4bdecfa9L);
+       R2(C,D,A,B,X[ 7],16,0xf6bb4b60L);
+       R2(B,C,D,A,X[10],23,0xbebfbc70L);
+       R2(A,B,C,D,X[13], 4,0x289b7ec6L);
+       R2(D,A,B,C,X[ 0],11,0xeaa127faL);
+       R2(C,D,A,B,X[ 3],16,0xd4ef3085L);
+       R2(B,C,D,A,X[ 6],23,0x04881d05L);
+       R2(A,B,C,D,X[ 9], 4,0xd9d4d039L);
+       R2(D,A,B,C,X[12],11,0xe6db99e5L);
+       R2(C,D,A,B,X[15],16,0x1fa27cf8L);
+       R2(B,C,D,A,X[ 2],23,0xc4ac5665L);
+       /* Round 3 */
+       R3(A,B,C,D,X[ 0], 6,0xf4292244L);
+       R3(D,A,B,C,X[ 7],10,0x432aff97L);
+       R3(C,D,A,B,X[14],15,0xab9423a7L);
+       R3(B,C,D,A,X[ 5],21,0xfc93a039L);
+       R3(A,B,C,D,X[12], 6,0x655b59c3L);
+       R3(D,A,B,C,X[ 3],10,0x8f0ccc92L);
+       R3(C,D,A,B,X[10],15,0xffeff47dL);
+       R3(B,C,D,A,X[ 1],21,0x85845dd1L);
+       R3(A,B,C,D,X[ 8], 6,0x6fa87e4fL);
+       R3(D,A,B,C,X[15],10,0xfe2ce6e0L);
+       R3(C,D,A,B,X[ 6],15,0xa3014314L);
+       R3(B,C,D,A,X[13],21,0x4e0811a1L);
+       R3(A,B,C,D,X[ 4], 6,0xf7537e82L);
+       R3(D,A,B,C,X[11],10,0xbd3af235L);
+       R3(C,D,A,B,X[ 2],15,0x2ad7d2bbL);
+       R3(B,C,D,A,X[ 9],21,0xeb86d391L);
+
+       A = c->A += A;
+       B = c->B += B;
+       C = c->C += C;
+       D = c->D += D;
+               }
+       }
+#endif
+
+#ifndef md5_block_data_order
+#ifdef X
+#undef X
+#endif
+void md5_block_data_order (MD5_CTX *c, const void *data_, int num)
+       {
+       const unsigned char *data=data_;
+       register unsigned MD32_REG_T A,B,C,D,l;
+#ifndef MD32_XARRAY
+       /* See comment in crypto/sha/sha_locl.h for details. */
+       unsigned MD32_REG_T     XX0, XX1, XX2, XX3, XX4, XX5, XX6, XX7,
+                               XX8, XX9,XX10,XX11,XX12,XX13,XX14,XX15;
+# define X(i)  XX##i
+#else
+       mDNSu32 XX[MD5_LBLOCK];
+# define X(i)  XX[i]
+#endif
+
+       A=c->A;
+       B=c->B;
+       C=c->C;
+       D=c->D;
+
+       for (;num--;)
+               {
+       HOST_c2l(data,l); X( 0)=l;              HOST_c2l(data,l); X( 1)=l;
+       /* Round 0 */
+       R0(A,B,C,D,X( 0), 7,0xd76aa478L);       HOST_c2l(data,l); X( 2)=l;
+       R0(D,A,B,C,X( 1),12,0xe8c7b756L);       HOST_c2l(data,l); X( 3)=l;
+       R0(C,D,A,B,X( 2),17,0x242070dbL);       HOST_c2l(data,l); X( 4)=l;
+       R0(B,C,D,A,X( 3),22,0xc1bdceeeL);       HOST_c2l(data,l); X( 5)=l;
+       R0(A,B,C,D,X( 4), 7,0xf57c0fafL);       HOST_c2l(data,l); X( 6)=l;
+       R0(D,A,B,C,X( 5),12,0x4787c62aL);       HOST_c2l(data,l); X( 7)=l;
+       R0(C,D,A,B,X( 6),17,0xa8304613L);       HOST_c2l(data,l); X( 8)=l;
+       R0(B,C,D,A,X( 7),22,0xfd469501L);       HOST_c2l(data,l); X( 9)=l;
+       R0(A,B,C,D,X( 8), 7,0x698098d8L);       HOST_c2l(data,l); X(10)=l;
+       R0(D,A,B,C,X( 9),12,0x8b44f7afL);       HOST_c2l(data,l); X(11)=l;
+       R0(C,D,A,B,X(10),17,0xffff5bb1L);       HOST_c2l(data,l); X(12)=l;
+       R0(B,C,D,A,X(11),22,0x895cd7beL);       HOST_c2l(data,l); X(13)=l;
+       R0(A,B,C,D,X(12), 7,0x6b901122L);       HOST_c2l(data,l); X(14)=l;
+       R0(D,A,B,C,X(13),12,0xfd987193L);       HOST_c2l(data,l); X(15)=l;
+       R0(C,D,A,B,X(14),17,0xa679438eL);
+       R0(B,C,D,A,X(15),22,0x49b40821L);
+       /* Round 1 */
+       R1(A,B,C,D,X( 1), 5,0xf61e2562L);
+       R1(D,A,B,C,X( 6), 9,0xc040b340L);
+       R1(C,D,A,B,X(11),14,0x265e5a51L);
+       R1(B,C,D,A,X( 0),20,0xe9b6c7aaL);
+       R1(A,B,C,D,X( 5), 5,0xd62f105dL);
+       R1(D,A,B,C,X(10), 9,0x02441453L);
+       R1(C,D,A,B,X(15),14,0xd8a1e681L);
+       R1(B,C,D,A,X( 4),20,0xe7d3fbc8L);
+       R1(A,B,C,D,X( 9), 5,0x21e1cde6L);
+       R1(D,A,B,C,X(14), 9,0xc33707d6L);
+       R1(C,D,A,B,X( 3),14,0xf4d50d87L);
+       R1(B,C,D,A,X( 8),20,0x455a14edL);
+       R1(A,B,C,D,X(13), 5,0xa9e3e905L);
+       R1(D,A,B,C,X( 2), 9,0xfcefa3f8L);
+       R1(C,D,A,B,X( 7),14,0x676f02d9L);
+       R1(B,C,D,A,X(12),20,0x8d2a4c8aL);
+       /* Round 2 */
+       R2(A,B,C,D,X( 5), 4,0xfffa3942L);
+       R2(D,A,B,C,X( 8),11,0x8771f681L);
+       R2(C,D,A,B,X(11),16,0x6d9d6122L);
+       R2(B,C,D,A,X(14),23,0xfde5380cL);
+       R2(A,B,C,D,X( 1), 4,0xa4beea44L);
+       R2(D,A,B,C,X( 4),11,0x4bdecfa9L);
+       R2(C,D,A,B,X( 7),16,0xf6bb4b60L);
+       R2(B,C,D,A,X(10),23,0xbebfbc70L);
+       R2(A,B,C,D,X(13), 4,0x289b7ec6L);
+       R2(D,A,B,C,X( 0),11,0xeaa127faL);
+       R2(C,D,A,B,X( 3),16,0xd4ef3085L);
+       R2(B,C,D,A,X( 6),23,0x04881d05L);
+       R2(A,B,C,D,X( 9), 4,0xd9d4d039L);
+       R2(D,A,B,C,X(12),11,0xe6db99e5L);
+       R2(C,D,A,B,X(15),16,0x1fa27cf8L);
+       R2(B,C,D,A,X( 2),23,0xc4ac5665L);
+       /* Round 3 */
+       R3(A,B,C,D,X( 0), 6,0xf4292244L);
+       R3(D,A,B,C,X( 7),10,0x432aff97L);
+       R3(C,D,A,B,X(14),15,0xab9423a7L);
+       R3(B,C,D,A,X( 5),21,0xfc93a039L);
+       R3(A,B,C,D,X(12), 6,0x655b59c3L);
+       R3(D,A,B,C,X( 3),10,0x8f0ccc92L);
+       R3(C,D,A,B,X(10),15,0xffeff47dL);
+       R3(B,C,D,A,X( 1),21,0x85845dd1L);
+       R3(A,B,C,D,X( 8), 6,0x6fa87e4fL);
+       R3(D,A,B,C,X(15),10,0xfe2ce6e0L);
+       R3(C,D,A,B,X( 6),15,0xa3014314L);
+       R3(B,C,D,A,X(13),21,0x4e0811a1L);
+       R3(A,B,C,D,X( 4), 6,0xf7537e82L);
+       R3(D,A,B,C,X(11),10,0xbd3af235L);
+       R3(C,D,A,B,X( 2),15,0x2ad7d2bbL);
+       R3(B,C,D,A,X( 9),21,0xeb86d391L);
+
+       A = c->A += A;
+       B = c->B += B;
+       C = c->C += C;
+       D = c->D += D;
+               }
+       }
+#endif
+
+
+
+ // ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark - base64 -> binary conversion
+#endif
+
+static const char Base64[] =
+       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+static const char Pad64 = '=';
+
+
+#define mDNSisspace(x) (x == '\t' || x == '\n' || x == '\v' || x == '\f' || x == '\r' || x == ' ')
+
+static const char *mDNSstrchr(const char *s, int c)
+       {
+       while (1)
+               {
+               if (c == *s) return s;
+               if (!*s) return mDNSNULL;
+               s++;
+               }
+       }
+
+// skips all whitespace anywhere.
+// converts characters, four at a time, starting at (or after)
+// src from base - 64 numbers into three 8 bit bytes in the target area.
+// it returns the number of data bytes stored at the target, or -1 on error.
+// adapted from BIND sources
+
+mDNSexport mDNSs32 DNSDigest_Base64ToBin(const char *src, mDNSu8 *target, mDNSu32 targsize)
+       {
+       int tarindex, state, ch;
+       const char *pos;
+
+       state = 0;
+       tarindex = 0;
+
+       while ((ch = *src++) != '\0') {
+               if (mDNSisspace(ch))    /* Skip whitespace anywhere. */
+                       continue;
+
+               if (ch == Pad64)
+                       break;
+
+               pos = mDNSstrchr(Base64, ch);
+               if (pos == 0)           /* A non-base64 character. */
+                       return (-1);
+
+               switch (state) {
+               case 0:
+                       if (target) {
+                               if ((mDNSu32)tarindex >= targsize)
+                                       return (-1);
+                               target[tarindex] = (mDNSu8)((pos - Base64) << 2);
+                       }
+                       state = 1;
+                       break;
+               case 1:
+                       if (target) {
+                               if ((mDNSu32)tarindex + 1 >= targsize)
+                                       return (-1);
+                               target[tarindex]   |=  (pos - Base64) >> 4;
+                               target[tarindex+1]  = (mDNSu8)(((pos - Base64) & 0x0f) << 4);
+                       }
+                       tarindex++;
+                       state = 2;
+                       break;
+               case 2:
+                       if (target) {
+                               if ((mDNSu32)tarindex + 1 >= targsize)
+                                       return (-1);
+                               target[tarindex]   |=  (pos - Base64) >> 2;
+                               target[tarindex+1]  = (mDNSu8)(((pos - Base64) & 0x03) << 6);
+                       }
+                       tarindex++;
+                       state = 3;
+                       break;
+               case 3:
+                       if (target) {
+                               if ((mDNSu32)tarindex >= targsize)
+                                       return (-1);
+                               target[tarindex] |= (pos - Base64);
+                       }
+                       tarindex++;
+                       state = 0;
+                       break;
+               default:
+                       return -1;
+               }
+       }
+
+       /*
+        * We are done decoding Base-64 chars.  Let's see if we ended
+        * on a byte boundary, and/or with erroneous trailing characters.
+        */
+
+       if (ch == Pad64) {              /* We got a pad char. */
+               ch = *src++;            /* Skip it, get next. */
+               switch (state) {
+               case 0:         /* Invalid = in first position */
+               case 1:         /* Invalid = in second position */
+                       return (-1);
+
+               case 2:         /* Valid, means one byte of info */
+                       /* Skip any number of spaces. */
+                       for ((void)mDNSNULL; ch != '\0'; ch = *src++)
+                               if (!mDNSisspace(ch))
+                                       break;
+                       /* Make sure there is another trailing = sign. */
+                       if (ch != Pad64)
+                               return (-1);
+                       ch = *src++;            /* Skip the = */
+                       /* Fall through to "single trailing =" case. */
+                       /* FALLTHROUGH */
+
+               case 3:         /* Valid, means two bytes of info */
+                       /*
+                        * We know this char is an =.  Is there anything but
+                        * whitespace after it?
+                        */
+                       for ((void)mDNSNULL; ch != '\0'; ch = *src++)
+                               if (!mDNSisspace(ch))
+                                       return (-1);
+
+                       /*
+                        * Now make sure for cases 2 and 3 that the "extra"
+                        * bits that slopped past the last full byte were
+                        * zeros.  If we don't check them, they become a
+                        * subliminal channel.
+                        */
+                       if (target && target[tarindex] != 0)
+                               return (-1);
+               }
+       } else {
+               /*
+                * We ended by seeing the end of the string.  Make sure we
+                * have no partial bytes lying around.
+                */
+               if (state != 0)
+                       return (-1);
+               }
+
+       return (tarindex);
+       }
+
+
+ // ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark - API exported to mDNS Core
+#endif
+
+// Constants
+#define HMAC_IPAD   0x36
+#define HMAC_OPAD   0x5c
+#define MD5_LEN     16
+
+static domainname HMAC_MD5_AlgName = { { '\010', 'h', 'm', 'a', 'c', '-', 'm', 'd', '5',
+                                                                                '\007', 's', 'i', 'g', '-', 'a', 'l', 'g',
+                                                                                '\003', 'r', 'e', 'g',
+                                                                                '\003', 'i', 'n', 't',
+                                                                                '\0' } };
+// Adapted from Appendix, RFC 2104
+mDNSexport void DNSDigest_ConstructHMACKey(uDNS_AuthInfo *info, mDNSu8 *key, mDNSu32 len)              
+       {
+       MD5_CTX k;
+       mDNSu8 buf[MD5_LEN];
+       int i;
+       
+       // If key is longer than HMAC_LEN reset it to MD5(key)
+       if (len > HMAC_LEN)
+               {
+               MD5_Init(&k);
+               MD5_Update(&k, key, len);
+               MD5_Final(buf, &k);
+               key = buf;
+               len = MD5_LEN;
+               }
+
+       // store key in pads
+       mDNSPlatformMemZero(info->key.ipad, HMAC_LEN);
+       mDNSPlatformMemZero(info->key.opad, HMAC_LEN);
+       mDNSPlatformMemCopy(key, info->key.ipad, len);
+       mDNSPlatformMemCopy(key, info->key.opad, len);
+
+       // XOR key with ipad and opad values
+       for (i = 0; i < HMAC_LEN; i++)
+               {
+               info->key.ipad[i] ^= HMAC_IPAD;
+               info->key.opad[i] ^= HMAC_OPAD;
+               }
+
+       }
+
+mDNSexport mDNSu8 *DNSDigest_SignMessage(DNSMessage *msg, mDNSu8 **end, mDNSu16 *numAdditionals, uDNS_AuthInfo *info)
+       {
+       AuthRecord tsig;
+       mDNSu8 *countPtr, *rdata;
+       mDNSu32 utc32;
+       mDNSu8 utc48[6];
+       mDNSu8 digest[MD5_LEN];
+       mDNSu8 *ptr = *end;
+       mDNSu32 len;
+       mDNSOpaque16 buf;
+       MD5_CTX c;
+       
+       // Init MD5 context, digest inner key pad and message
+    MD5_Init(&c);
+    MD5_Update(&c, info->key.ipad, HMAC_LEN);
+       MD5_Update(&c, (mDNSu8 *)msg, (unsigned long)(*end - (mDNSu8 *)msg));
+          
+       // Construct TSIG RR, digesting variables as apporpriate
+       mDNSPlatformMemZero(&tsig, sizeof(AuthRecord)); 
+       mDNS_SetupResourceRecord(&tsig, mDNSNULL, 0, kDNSType_TSIG, 0, kDNSRecordTypeKnownUnique, mDNSNULL, mDNSNULL);
+       rdata = tsig.resrec.rdata->u.data;
+
+       // key name
+       mDNSPlatformStrCopy(info->keyname.c, tsig.resrec.name.c);
+       MD5_Update(&c, info->keyname.c, mDNSPlatformStrLen(info->keyname.c)+1);
+
+       // class
+       tsig.resrec.rrclass = kDNSQClass_ANY;
+       buf = mDNSOpaque16fromIntVal(kDNSQClass_ANY);
+       MD5_Update(&c, buf.b, sizeof(mDNSOpaque16));
+
+       // ttl
+       tsig.resrec.rroriginalttl = 0;
+       MD5_Update(&c, (mDNSu8 *)&tsig.resrec.rroriginalttl, sizeof(tsig.resrec.rroriginalttl));
+       
+       // alg name
+       mDNSPlatformStrCopy(HMAC_MD5_AlgName.c, rdata);     
+       len = mDNSPlatformStrLen(HMAC_MD5_AlgName.c) + 1;
+       rdata += len;
+       MD5_Update(&c, HMAC_MD5_AlgName.c, len);
+
+       // time
+       // get UTC (universal time), convert to 48-bit unsigned in network byte order
+       utc32 = (mDNSu32)mDNSPlatformUTC();
+       if (utc32 == (unsigned)-1) { LogMsg("ERROR: DNSDigest_SignMessage - mDNSPlatformUTC returned bad time -1"); return mDNSNULL; }
+       utc48[0] = 0;
+       utc48[1] = 0;
+       utc48[2] = (mDNSu8)((utc32 >> 24) & 0xff);
+       utc48[3] = (mDNSu8)((utc32 >> 16) & 0xff);
+       utc48[4] = (mDNSu8)((utc32 >> 8)  & 0xff);
+       utc48[5] = (mDNSu8)( utc32        & 0xff);
+
+       mDNSPlatformMemCopy(utc48, rdata, 6);
+       rdata += 6;                     
+       MD5_Update(&c, utc48, 6);
+
+       // fudge
+       buf = mDNSOpaque16fromIntVal(300);     // 300 sec is fudge recommended in RFC 2485
+       ((mDNSOpaque16 *)rdata)->NotAnInteger = buf.NotAnInteger;
+       rdata += sizeof(mDNSOpaque16);
+       MD5_Update(&c, buf.b, sizeof(mDNSOpaque16));
+
+       // digest error and other data len (both zero) - we'll add them to the rdata later
+       buf.NotAnInteger = 0;
+       MD5_Update(&c, buf.b, sizeof(mDNSOpaque16));  // error
+       MD5_Update(&c, buf.b, sizeof(mDNSOpaque16));  // other data len
+
+       // finish the message & tsig var hash
+    MD5_Final(digest, &c);
+       
+       // perform outer MD5 (outer key pad, inner digest)
+       MD5_Init(&c);
+       MD5_Update(&c, info->key.opad, HMAC_LEN);
+       MD5_Update(&c, digest, MD5_LEN);
+       MD5_Final(digest, &c);
+
+       // set remaining rdata fields
+       *(mDNSOpaque16 *)rdata = mDNSOpaque16fromIntVal(MD5_LEN);             // MAC size       
+       rdata += sizeof(mDNSOpaque16);
+       mDNSPlatformMemCopy(digest, rdata, MD5_LEN);                          // MAC
+       rdata += MD5_LEN;
+       ((mDNSOpaque16 *)rdata)->NotAnInteger = msg->h.id.NotAnInteger;       // original ID
+       rdata += sizeof(mDNSOpaque16);
+       ((mDNSOpaque16 *)rdata)->NotAnInteger = 0;                            // no error
+       rdata += sizeof(mDNSOpaque16);
+       ((mDNSOpaque16 *)rdata)->NotAnInteger = 0;                            // other data len
+       rdata += sizeof(mDNSOpaque16);
+       
+       tsig.resrec.rdlength = (mDNSu16)(rdata - tsig.resrec.rdata->u.data);
+       *end = PutResourceRecordTTL(msg, ptr, numAdditionals, &tsig.resrec, 0);
+       if (!*end) { LogMsg("ERROR: DNSDigest_SignMessage - could not put TSIG"); return mDNSNULL; }
+
+       // update num additionals
+       countPtr = (mDNSu8 *)&msg->h.numAdditionals;  // increment (network-byte ordered) header value
+       *countPtr++ = (mDNSu8)(*numAdditionals >> 8);
+       *countPtr++ = (mDNSu8)(*numAdditionals &  0xFF);
+
+       return *end;
+       }
+       
+
+#ifdef __cplusplus
+}
+#endif
index 556bdd1140b268d64ea84ab8a434a40f230d577b..b5364c2d426ab1af630c419b972ce770d444d861 100755 (executable)
@@ -3,6 +3,8 @@
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
     Change History (most recent first):
 
 $Log: mDNS.c,v $
-Revision 1.307.2.13  2005/01/28 05:39:12  cheshire
-Remove LogMsg()
+Revision 1.382  2004/06/08 04:59:40  cheshire
+Tidy up wording -- log messages are already prefixed with "mDNSResponder", so don't need to repeat it
+
+Revision 1.381  2004/06/05 00:57:30  cheshire
+Remove incorrect LogMsg()
+
+Revision 1.380  2004/06/05 00:04:26  cheshire
+<rdar://problem/3668639>: wide-area domains should be returned in reg. domain enumeration
+
+Revision 1.379  2004/05/28 23:42:36  ksekar
+<rdar://problem/3258021>: Feature: DNS server->client notification on record changes (#7805)
+
+Revision 1.378  2004/05/25 17:25:25  cheshire
+Remove extraneous blank lines and white space
+
+Revision 1.377  2004/05/18 23:51:25  cheshire
+Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
+
+Revision 1.376  2004/05/05 18:30:44  ksekar
+Restored surpressed Cache Tail debug messages.
+
+Revision 1.375  2004/04/26 21:36:25  cheshire
+Only send IPv4 (or v6) multicast when IPv4 (or v6) multicast send/receive
+is indicated as being available on that interface
+
+Revision 1.374  2004/04/21 02:53:26  cheshire
+Typo in debugf statement
+
+Revision 1.373  2004/04/21 02:49:11  cheshire
+To reduce future confusion, renamed 'TxAndRx' to 'McastTxRx'
+
+Revision 1.372  2004/04/21 02:38:51  cheshire
+Add debugging checks
+
+Revision 1.371  2004/04/14 23:09:28  ksekar
+Support for TSIG signed dynamic updates.
+
+Revision 1.370  2004/04/09 17:40:26  cheshire
+Remove unnecessary "Multicast" field -- it duplicates the semantics of the existing McastTxRx field
+
+Revision 1.369  2004/04/09 16:34:00  cheshire
+Debugging code for later; currently unused
+
+Revision 1.368  2004/04/02 19:19:48  cheshire
+Add code to do optional logging of multi-packet KA list time intervals
+
+Revision 1.367  2004/03/20 03:16:10  cheshire
+Minor refinement to "Excessive update rate" message
 
-Revision 1.307.2.12  2005/01/28 05:02:05  cheshire
-<rdar://problem/3770559> SUPan: Replace IP TTL 255 check with local-subnet check
+Revision 1.366  2004/03/20 03:12:57  cheshire
+<rdar://problem/3587619>: UpdateCredits not granted promptly enough
 
-Revision 1.307.2.11  2005/01/28 04:03:23  cheshire
-<rdar://problem/3759302> SUPan: Current method of doing subtypes causes name collisions
-Summary: Pulled in ConstructServiceName, CountSubTypes and AllocateSubTypes from Tiger version.
+Revision 1.365  2004/03/19 23:51:22  cheshire
+Change to use symbolic constant kUpdateCreditRefreshInterval instead of (mDNSPlatformOneSecond * 60)
 
-Revision 1.307.2.10  2004/06/18 17:28:18  cheshire
-<rdar://problem/3588761> Current method of doing subtypes causes name collisions
+Revision 1.364  2004/03/13 01:57:33  ksekar
+<rdar://problem/3192546>: DynDNS: Dynamic update of service records
 
-Revision 1.307.2.9  2004/06/18 00:31:51  cheshire
-<rdar://problem/3617655> mDNSResponder escape handling inconsistent with BIND
-(Prerequisite for fixing <rdar://problem/3588761>)
+Revision 1.363  2004/03/12 21:00:51  cheshire
+Also show port numbers when logging "apparent spoof mDNS Response" messages
 
-Revision 1.307.2.8  2004/04/03 05:18:19  bradley
-Added cast to fix signed/unsigned warning due to int promotion.
+Revision 1.362  2004/03/12 08:58:18  cheshire
+Guard against empty TXT records
 
-Revision 1.307.2.7  2004/03/30 06:46:24  cheshire
-Compiler warning fixes from Don Woodward at Roku Labs
+Revision 1.361  2004/03/09 03:00:46  cheshire
+<rdar://problem/3581961> Don't take lock until after mDNS_Update() has validated that the data is good.
 
-Revision 1.307.2.6  2004/03/09 03:03:38  cheshire
-<rdar://problem/3581961> Don't take lock until after mDNS_Update() has validated that the data is good
+Revision 1.360  2004/03/08 02:52:41  cheshire
+Minor debugging fix: Make sure 'target' is initialized so we don't crash writing debugging log messages
 
-Revision 1.307.2.5  2004/03/02 02:55:24  cheshire
+Revision 1.359  2004/03/02 03:21:56  cheshire
 <rdar://problem/3549576> Properly support "_services._dns-sd._udp" meta-queries
 
-Revision 1.307.2.4  2004/02/18 01:55:08  cheshire
-<rdar://problem/3553472>: Increase delay to 400ms when answering queries with multi-packet KA lists
+Revision 1.358  2004/02/20 08:18:34  cheshire
+<rdar://problem/3564799>: mDNSResponder sometimes announces AAAA records unnecessarily
 
-Revision 1.307.2.3  2004/01/28 23:08:45  cheshire
-<rdar://problem/3488559>: Hard code domain enumeration functions to return ".local" only
+Revision 1.357  2004/02/18 01:47:41  cheshire
+<rdar://problem/3553472>: Insufficient delay waiting for multi-packet KA lists causes AirPort traffic storms
 
-Revision 1.307.2.2  2003/12/20 01:51:40  cheshire
+Revision 1.356  2004/02/06 23:04:19  ksekar
+Basic Dynamic Update support via mDNS_Register (dissabled via
+UNICAST_REGISTRATION #define)
+
+Revision 1.355  2004/02/05 09:32:33  cheshire
+Fix from Bob Bradley: When using the "%.*s" string form,
+guard against truncating in the middle of a multi-byte UTF-8 character.
+
+Revision 1.354  2004/02/05 09:30:22  cheshire
+Update comments
+
+Revision 1.353  2004/01/28 03:41:00  cheshire
+<rdar://problem/3541946>: Need ability to do targeted queries as well as multicast queries
+
+Revision 1.352  2004/01/28 02:30:07  ksekar
+Added default Search Domains to unicast browsing, controlled via
+Networking sharing prefs pane.  Stopped sending unicast messages on
+every interface.  Fixed unicast resolving via mach-port API.
+
+Revision 1.351  2004/01/27 20:15:22  cheshire
+<rdar://problem/3541288>: Time to prune obsolete code for listening on port 53
+
+Revision 1.350  2004/01/24 23:38:16  cheshire
+Use mDNSVal16() instead of shifting and ORing operations
+
+Revision 1.349  2004/01/23 23:23:14  ksekar
+Added TCP support for truncated unicast messages.
+
+Revision 1.348  2004/01/22 03:54:11  cheshire
+Create special meta-interface 'mDNSInterface_ForceMCast' (-2),
+which means "do this query via multicast, even if it's apparently a unicast domain"
+
+Revision 1.347  2004/01/22 03:50:49  cheshire
+If the client has specified an explicit InterfaceID, then do query by multicast, not unicast
+
+Revision 1.346  2004/01/22 03:48:41  cheshire
+Make sure uDNS client doesn't accidentally use query ID zero
+
+Revision 1.345  2004/01/22 03:43:08  cheshire
+Export constants like mDNSInterface_LocalOnly so that the client layers can use them
+
+Revision 1.344  2004/01/21 21:53:18  cheshire
+<rdar://problem/3448144>: Don't try to receive unicast responses if we're not the first to bind to the UDP port
+
+Revision 1.343  2003/12/23 00:07:47  cheshire
+Make port number in debug message be five-character field, left justified
+
+Revision 1.342  2003/12/20 01:34:28  cheshire
 <rdar://problem/3515876>: Error putting additional records into packets
 Another fix from Rampi: responseptr needs to be updated inside the "for" loop,
 after every record, not once at the end.
 
-Revision 1.307.2.1  2003/12/03 11:20:27  cheshire
-<rdar://problem/3457718>: Stop and start of a service uses old ip address (with old port number)
+Revision 1.341  2003/12/18 22:56:12  cheshire
+<rdar://problem/3510798>: Reduce syslog messages about ignored spoof packets
+
+Revision 1.340  2003/12/16 02:31:37  cheshire
+Minor update to comments
+
+Revision 1.339  2003/12/13 05:50:33  bradley
+Fixed crash with mDNS_Lock/Unlock being called for the initial GrowCache before the platform
+layer has been initialized. Protect mDNS_reentrancy when completing the core initialization to
+fix a race condition during async initialization. Fixed buffer overrun for 1 byte mDNS_snprintf.
+
+Revision 1.338  2003/12/13 03:05:27  ksekar
+<rdar://problem/3192548>: DynDNS: Unicast query of service records
+
+Revision 1.337  2003/12/01 21:46:05  cheshire
+mDNS_StartQuery returns mStatus_BadInterfaceErr if the specified interface does not exist
+
+Revision 1.336  2003/12/01 21:26:19  cheshire
+Guard against zero-length sbuffer in mDNS_vsnprintf()
+
+Revision 1.335  2003/12/01 20:27:48  cheshire
+Display IPv6 addresses correctly (e.g. in log messages) on little-endian processors
+
+Revision 1.334  2003/11/20 22:59:53  cheshire
+Changed runtime checks in mDNS.c to be compile-time checks in mDNSClientAPI.h
+Thanks to Bob Bradley for suggesting the ingenious compiler trick to make this work.
+
+Revision 1.333  2003/11/20 20:49:53  cheshire
+Another fix from HP: Use packedstruct macro to ensure proper packing for on-the-wire packet structures
+
+Revision 1.332  2003/11/20 05:47:37  cheshire
+<rdar://problem/3490355>: Don't exclude known answers whose expiry time is before the next query
+Now that we only include answers in the known answer list if they are less than
+halfway to expiry, the check to also see if we have another query scheduled
+before the record expires is no longer necessary (and in fact, not correct).
+
+Revision 1.331  2003/11/19 22:31:48  cheshire
+When automatically adding A records to SRVs, add them as additionals, not answers
+
+Revision 1.330  2003/11/19 22:28:50  cheshire
+Increment/Decrement mDNS_reentrancy around calls to m->MainCallback()
+to allow client to make mDNS calls (specifically the call to mDNS_GrowCache())
+
+Revision 1.329  2003/11/19 22:19:24  cheshire
+Show log message when ignoring packets with bad TTL.
+This is to help diagnose problems on Linux versions that may not report the TTL reliably.
+
+Revision 1.328  2003/11/19 22:06:38  cheshire
+Show log messages when a service or hostname is renamed
+
+Revision 1.327  2003/11/19 22:03:44  cheshire
+Move common "m->NextScheduledResponse = m->timenow" to before "if" statement
+
+Revision 1.326  2003/11/17 22:27:02  cheshire
+Another fix from ramaprasad.kr@hp.com: Improve reply delay computation
+on platforms that have native clock rates below fifty ticks per second.
+
+Revision 1.325  2003/11/17 20:41:44  cheshire
+Fix some missing mDNS_Lock(m)/mDNS_Unlock(m) calls.
+
+Revision 1.324  2003/11/17 20:36:32  cheshire
+Function rename: Remove "mDNS_" prefix from AdvertiseInterface() and
+DeadvertiseInterface() -- they're internal private routines, not API routines.
+
+Revision 1.323  2003/11/14 20:59:08  cheshire
+Clients can't use AssignDomainName macro because mDNSPlatformMemCopy is defined in mDNSPlatformFunctions.h.
+Best solution is just to combine mDNSClientAPI.h and mDNSPlatformFunctions.h into a single file.
+
+Revision 1.322  2003/11/14 19:47:52  cheshire
+Define symbol MAX_ESCAPED_DOMAIN_NAME to indicate recommended buffer size for ConvertDomainNameToCString
+
+Revision 1.321  2003/11/14 19:18:34  cheshire
+Move AssignDomainName macro to mDNSClientAPI.h to that client layers can use it too
+
+Revision 1.320  2003/11/13 06:45:04  cheshire
+Fix compiler warning on certain compilers
+
+Revision 1.319  2003/11/13 00:47:40  cheshire
+<rdar://problem/3437556> We should delay AAAA record query if A record already in cache.
+
+Revision 1.318  2003/11/13 00:33:26  cheshire
+Change macro "RRIsAddressType" to "RRTypeIsAddressType"
+
+Revision 1.317  2003/11/13 00:10:49  cheshire
+<rdar://problem/3436412>: Verify that rr data is different before updating.
+
+Revision 1.316  2003/11/08 23:37:54  cheshire
+Give explicit zero initializers to blank static structure, required by certain compilers.
+(Thanks to ramaprasad.kr@hp.com for reporting this.)
+
+Revision 1.315  2003/11/07 03:32:56  cheshire
+<rdar://problem/3472153> mDNSResponder delivers answers in inconsistent order
+This is the real fix. Checkin 1.312 was overly simplistic; Calling GetFreeCacheRR() can sometimes
+purge records from the cache, causing tail pointer *rp to be stale on return. The correct fix is
+to maintain a system-wide tail pointer for each cache slot, and then if neccesary GetFreeCacheRR()
+can update this pointer, so that mDNSCoreReceiveResponse() appends records in the right place.
+
+Revision 1.314  2003/11/07 03:19:49  cheshire
+Minor variable renaming for clarity
+
+Revision 1.313  2003/11/07 03:14:49  cheshire
+Previous checkin proved to be overly simplistic; reversing
+
+Revision 1.312  2003/11/03 23:45:15  cheshire
+<rdar://problem/3472153> mDNSResponder delivers answers in inconsistent order
+Build cache lists in FIFO order, not customary C LIFO order
+(Append new elements to tail of cache list, instead of prepending at the head.)
+
+Revision 1.311  2003/10/09 18:00:11  cheshire
+Another compiler warning fix.
+
+Revision 1.310  2003/10/07 20:27:05  cheshire
+Patch from Bob Bradley, to fix warning and compile error on Windows
+
+Revision 1.309  2003/09/26 01:06:36  cheshire
+<rdar://problem/3427923> Set kDNSClass_UniqueRRSet bit for updates too
+Made new routine HaveSentEntireRRSet() to check if flag should be set
+
+Revision 1.308  2003/09/23 01:05:01  cheshire
+Minor changes to comments and debugf() message
 
 Revision 1.307  2003/09/09 20:13:30  cheshire
 <rdar://problem/3411105> Don't send a Goodbye record if we never announced it
@@ -236,7 +447,7 @@ Revision 1.271  2003/08/14 02:17:05  cheshire
 <rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
 
 Revision 1.270  2003/08/13 17:07:28  ksekar
-Bug #: <rdar://problem/3376458>: Extra RR linked to list even if registration fails - causes crash
+<rdar://problem/3376458>: Extra RR linked to list even if registration fails - causes crash
 Added check to result of mDNS_Register() before linking extra record into list.
 
 Revision 1.269  2003/08/12 19:56:23  cheshire
@@ -741,7 +952,7 @@ Revision 1.128  2003/05/23 01:55:13  cheshire
 <rdar://problem/3267127> After name change, mDNSResponder needs to re-probe for name uniqueness
 
 Revision 1.127  2003/05/23 01:02:15  ksekar
-Bug #: <rdar://problem/3032577>: mDNSResponder needs to include unique id in default name
+<rdar://problem/3032577>: mDNSResponder needs to include unique id in default name
 
 Revision 1.126  2003/05/22 02:29:22  cheshire
 <rdar://problem/2984918> SendQueries needs to handle multihoming better
@@ -761,7 +972,7 @@ Revision 1.122  2003/05/21 19:59:04  cheshire
 Minor refinements; make sure we don't truncate in the middle of a multi-byte UTF-8 character
 
 Revision 1.121  2003/05/21 17:54:07  ksekar
-Bug #: <rdar://problem/3148431> ER: Tweak responder's default name conflict behavior
+<rdar://problem/3148431> ER: Tweak responder's default name conflict behavior
 New rename behavior - domain name "foo" becomes "foo--2" on conflict, richtext name becomes "foo (2)"
 
 Revision 1.120  2003/05/19 22:14:14  ksekar
@@ -827,22 +1038,21 @@ Revision 1.104  2003/04/21 19:15:52  cheshire
 Fix some compiler warnings
 
 Revision 1.103  2003/04/19 02:26:35  cheshire
-Bug #: <rdar://problem/3233804> Incorrect goodbye packet after conflict
+<rdar://problem/3233804> Incorrect goodbye packet after conflict
 
 Revision 1.102  2003/04/17 03:06:28  cheshire
-Bug #: <rdar://problem/3231321> No need to query again when a service goes away
+<rdar://problem/3231321> No need to query again when a service goes away
 Set UnansweredQueries to 2 when receiving a "goodbye" packet
 
 Revision 1.101  2003/04/15 20:58:31  jgraessl
-Bug #: 3229014
-Added a hash to lookup records in the cache.
+<rdar://problem/3229014> Added a hash to lookup records in the cache.
 
 Revision 1.100  2003/04/15 18:53:14  cheshire
-Bug #: <rdar://problem/3229064> Bug in ScheduleNextTask
+<rdar://problem/3229064> Bug in ScheduleNextTask
 mDNS.c 1.94 incorrectly combined two "if" statements into one.
 
 Revision 1.99  2003/04/15 18:09:13  jgraessl
-Bug #: 3228892
+<rdar://problem/3228892>
 Reviewed by: Stuart Cheshire
 Added code to keep track of when the next cache item will expire so we can
 call TidyRRCache only when necessary.
@@ -877,7 +1087,7 @@ Revision 1.92  2003/03/27 03:30:55  cheshire
 Problem was that HostNameCallback() was calling mDNS_DeregisterInterface(), which is not safe in a callback
 Fixes:
 1. Make mDNS_DeregisterInterface() safe to call from a callback
-2. Make HostNameCallback() use mDNS_DeadvertiseInterface() instead
+2. Make HostNameCallback() use DeadvertiseInterface() instead
    (it never really needed to deregister the interface at all)
 
 Revision 1.91  2003/03/15 04:40:36  cheshire
@@ -899,41 +1109,41 @@ Revision 1.86  2003/03/06 20:44:33  cheshire
 Comment tidyup
 
 Revision 1.85  2003/03/05 03:38:35  cheshire
-Bug #: 3185731 Bogus error message in console: died or deallocated, but no record of client can be found!
+<rdar://problem/3185731> Bogus error message in console: died or deallocated, but no record of client can be found!
 Fixed by leaving client in list after conflict, until client explicitly deallocates
 
 Revision 1.84  2003/03/05 01:27:30  cheshire
-Bug #: 3185482 Different TTL for multicast versus unicast responses
+<rdar://problem/3185482> Different TTL for multicast versus unicast responses
 When building unicast responses, record TTLs are capped to 10 seconds
 
 Revision 1.83  2003/03/04 23:48:52  cheshire
-Bug #: 3188865 Double probes after wake from sleep
+<rdar://problem/3188865> Double probes after wake from sleep
 Don't reset record type to kDNSRecordTypeUnique if record is DependentOn another
 
 Revision 1.82  2003/03/04 23:38:29  cheshire
-Bug #: 3099194 mDNSResponder needs performance improvements
+<rdar://problem/3099194> mDNSResponder needs performance improvements
 Only set rr->CRActiveQuestion to point to the
 currently active representative of a question set
 
 Revision 1.81  2003/02/21 03:35:34  cheshire
-Bug #: 3179007 mDNSResponder needs to include AAAA records in additional answer section
+<rdar://problem/3179007> mDNSResponder needs to include AAAA records in additional answer section
 
 Revision 1.80  2003/02/21 02:47:53  cheshire
-Bug #: 3099194 mDNSResponder needs performance improvements
+<rdar://problem/3099194> mDNSResponder needs performance improvements
 Several places in the code were calling CacheRRActive(), which searched the entire
 question list every time, to see if this cache resource record answers any question.
 Instead, we now have a field "CRActiveQuestion" in the resource record structure
 
 Revision 1.79  2003/02/21 01:54:07  cheshire
-Bug #: 3099194 mDNSResponder needs performance improvements
+<rdar://problem/3099194> mDNSResponder needs performance improvements
 Switched to using new "mDNS_Execute" model (see "Implementer Notes.txt")
 
 Revision 1.78  2003/02/20 06:48:32  cheshire
-Bug #: 3169535 Xserve RAID needs to do interface-specific registrations
+<rdar://problem/3169535> Xserve RAID needs to do interface-specific registrations
 Reviewed by: Josh Graessley, Bob Bradley
 
 Revision 1.77  2003/01/31 03:35:59  cheshire
-Bug #: 3147097 mDNSResponder sometimes fails to find the correct results
+<rdar://problem/3147097> mDNSResponder sometimes fails to find the correct results
 When there were *two* active questions in the list, they were incorrectly
 finding *each other* and *both* being marked as duplicates of another question
 
@@ -948,19 +1158,19 @@ Revision 1.75  2003/01/29 01:47:40  cheshire
 Rename 'Active' to 'CRActive' or 'InterfaceActive' for improved clarity
 
 Revision 1.74  2003/01/28 05:26:25  cheshire
-Bug #: 3147097 mDNSResponder sometimes fails to find the correct results
+<rdar://problem/3147097> mDNSResponder sometimes fails to find the correct results
 Add 'Active' flag for interfaces
 
 Revision 1.73  2003/01/28 03:45:12  cheshire
 Fixed missing "not" in "!mDNSAddrIsDNSMulticast(dstaddr)"
 
 Revision 1.72  2003/01/28 01:49:48  cheshire
-Bug #: 3147097 mDNSResponder sometimes fails to find the correct results
+<rdar://problem/3147097> mDNSResponder sometimes fails to find the correct results
 FindDuplicateQuestion() was incorrectly finding the question itself in the list,
 and incorrectly marking it as a duplicate (of itself), so that it became inactive.
 
 Revision 1.71  2003/01/28 01:41:44  cheshire
-Bug #: 3153091 Race condition when network change causes bad stuff
+<rdar://problem/3153091> Race condition when network change causes bad stuff
 When an interface goes away, interface-specific questions on that interface become orphaned.
 Orphan questions cause HaveQueries to return true, but there's no interface to send them on.
 Fix: mDNS_DeregisterInterface() now calls DeActivateInterfaceQuestions()
@@ -969,30 +1179,30 @@ Revision 1.70  2003/01/23 19:00:20  cheshire
 Protect against infinite loops in mDNS_Execute
 
 Revision 1.69  2003/01/21 22:56:32  jgraessl
-Bug #: 3124348  service name changes are not properly handled
+<rdar://problem/3124348>  service name changes are not properly handled
 Submitted by: Stuart Cheshire
 Reviewed by: Joshua Graessley
 Applying changes for 3124348 to main branch. 3124348 changes went in to a
 branch for SU.
 
 Revision 1.68  2003/01/17 04:09:27  cheshire
-Bug #: 3141038 mDNSResponder Resolves are unreliable on multi-homed hosts
+<rdar://problem/3141038> mDNSResponder Resolves are unreliable on multi-homed hosts
 
 Revision 1.67  2003/01/17 03:56:45  cheshire
 Default 24-hour TTL is far too long. Changing to two hours.
 
 Revision 1.66  2003/01/13 23:49:41  jgraessl
 Merged changes for the following fixes in to top of tree:
-3086540  computer name changes not handled properly
-3124348  service name changes are not properly handled
-3124352  announcements sent in pairs, failing chattiness test
+<rdar://problem/3086540>  computer name changes not handled properly
+<rdar://problem/3124348>  service name changes are not properly handled
+<rdar://problem/3124352>  announcements sent in pairs, failing chattiness test
 
 Revision 1.65  2002/12/23 22:13:28  jgraessl
 Reviewed by: Stuart Cheshire
 Initial IPv6 support for mDNSResponder.
 
 Revision 1.64  2002/11/26 20:49:06  cheshire
-Bug #: 3104543 RFC 1123 allows the first character of a name label to be either a letter or a digit
+<rdar://problem/3104543> RFC 1123 allows the first character of a name label to be either a letter or a digit
 
 Revision 1.63  2002/09/21 20:44:49  zarzycki
 Added APSL info
@@ -1004,7 +1214,7 @@ Revision 1.61  2002/09/20 01:05:24  cheshire
 Don't kill the Extras list in mDNS_DeregisterService()
 
 Revision 1.60  2002/09/19 23:47:35  cheshire
-Added mDNS_RegisterNoSuchService() function for assertion of non-existence
+Added mDNS_RegisterNoSuchService() function for assertion of non-existance
 of a particular named service
 
 Revision 1.59  2002/09/19 21:25:34  cheshire
@@ -1022,9 +1232,9 @@ Merge in license terms from Quinn's copy, in preparation for Darwin release
 
 #define TEST_LOCALONLY_FOR_EVERYTHING 0
 
-#include "mDNSClientAPI.h"                             // Defines the interface provided to the client layer above
-#include "mDNSPlatformFunctions.h"             // Defines the interface required of the supporting layer below
-
+//#include "mDNSClientAPI.h"                           // Defines the interface provided to the client layer above
+#include "DNSCommon.h"                  // Defines general DNS untility routines
+#include "uDNS.h"                                              // Defines entry points into unicast-specific routines
 // Disable certain benign warnings with Microsoft compilers
 #if(defined(_MSC_VER))
        // Disable "conditional expression is constant" warning for debug macros.
@@ -1032,11 +1242,6 @@ Merge in license terms from Quinn's copy, in preparation for Darwin release
        // If someone knows a variant way of writing "while(1)" that doesn't generate warning messages, please let us know
        #pragma warning(disable:4127)
        
-       // Disable "const object should be initialized"
-       // We know that static/globals are defined to be zeroed in ANSI C, and to avoid this warning would require some
-       // *really* ugly chunk of zeroes and curly braces to initialize zeroRR and mDNSprintf_format_default to all zeroes
-       #pragma warning(disable:4132)
-       
        // Disable "assignment within conditional expression".
        // Other compilers understand the convention that if you place the assignment expression within an extra pair
        // of parentheses, this signals to the compiler that you really intended an assignment and no warning is necessary.
@@ -1045,66 +1250,25 @@ Merge in license terms from Quinn's copy, in preparation for Darwin release
        #pragma warning(disable:4706)
 #endif
 
-// ***************************************************************************
-#if COMPILER_LIKES_PRAGMA_MARK
-#pragma mark - DNS Protocol Constants
-#endif
-
-typedef enum
-       {
-       kDNSFlag0_QR_Mask     = 0x80,           // Query or response?
-       kDNSFlag0_QR_Query    = 0x00,
-       kDNSFlag0_QR_Response = 0x80,
-       
-       kDNSFlag0_OP_Mask     = 0x78,           // Operation type
-       kDNSFlag0_OP_StdQuery = 0x00,
-       kDNSFlag0_OP_Iquery   = 0x08,
-       kDNSFlag0_OP_Status   = 0x10,
-       kDNSFlag0_OP_Unused3  = 0x18,
-       kDNSFlag0_OP_Notify   = 0x20,
-       kDNSFlag0_OP_Update   = 0x28,
-       
-       kDNSFlag0_QROP_Mask   = kDNSFlag0_QR_Mask | kDNSFlag0_OP_Mask,
-       
-       kDNSFlag0_AA          = 0x04,           // Authoritative Answer?
-       kDNSFlag0_TC          = 0x02,           // Truncated?
-       kDNSFlag0_RD          = 0x01,           // Recursion Desired?
-       kDNSFlag1_RA          = 0x80,           // Recursion Available?
-       
-       kDNSFlag1_Zero        = 0x40,           // Reserved; must be zero
-       kDNSFlag1_AD          = 0x20,           // Authentic Data [RFC 2535]
-       kDNSFlag1_CD          = 0x10,           // Checking Disabled [RFC 2535]
-
-       kDNSFlag1_RC          = 0x0F,           // Response code
-       kDNSFlag1_RC_NoErr    = 0x00,
-       kDNSFlag1_RC_FmtErr   = 0x01,
-       kDNSFlag1_RC_SrvErr   = 0x02,
-       kDNSFlag1_RC_NXDomain = 0x03,
-       kDNSFlag1_RC_NotImpl  = 0x04,
-       kDNSFlag1_RC_Refused  = 0x05,
-       kDNSFlag1_RC_YXDomain = 0x06,
-       kDNSFlag1_RC_YXRRSet  = 0x07,
-       kDNSFlag1_RC_NXRRSet  = 0x08,
-       kDNSFlag1_RC_NotAuth  = 0x09,
-       kDNSFlag1_RC_NotZone  = 0x0A
-       } DNS_Flags;
-
 // ***************************************************************************
 #if COMPILER_LIKES_PRAGMA_MARK
 #pragma mark -
 #pragma mark - Program Constants
 #endif
 
-mDNSexport const ResourceRecord  zeroRR;
 mDNSexport const mDNSIPPort      zeroIPPort        = { { 0 } };
 mDNSexport const mDNSv4Addr      zeroIPAddr        = { { 0 } };
 mDNSexport const mDNSv6Addr      zerov6Addr        = { { 0 } };
 mDNSexport const mDNSv4Addr      onesIPv4Addr      = { { 255, 255, 255, 255 } };
 mDNSexport const mDNSv6Addr      onesIPv6Addr      = { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } };
-mDNSlocal  const mDNSAddr        zeroAddr          = { mDNSAddrType_None, {{{ 0 }}} };
+mDNSexport const mDNSAddr        zeroAddr          = { mDNSAddrType_None, {{{ 0 }}} };
+
+mDNSexport const mDNSInterfaceID mDNSInterface_Any        = 0;
+mDNSexport const mDNSInterfaceID mDNSInterface_LocalOnly  = (mDNSInterfaceID)-1;
+mDNSexport const mDNSInterfaceID mDNSInterface_ForceMCast = (mDNSInterfaceID)-2;
 
-mDNSexport const mDNSInterfaceID mDNSInterface_Any = { 0 };
-mDNSlocal  const mDNSInterfaceID mDNSInterfaceMark = { (mDNSInterfaceID)~0 };
+// Note that mDNSInterfaceMark is the same value as mDNSInterface_LocalOnly, but they are used in different contexts
+mDNSlocal  const mDNSInterfaceID mDNSInterfaceMark        = (mDNSInterfaceID)~0;
 
 #define UnicastDNSPortAsNumber 53
 #define MulticastDNSPortAsNumber 5353
@@ -1116,9 +1280,11 @@ mDNSexport const mDNSv6Addr AllDNSLinkGroupv6  = { { 0xFF,0x02,0x00,0x00, 0x00,0
 mDNSexport const mDNSAddr   AllDNSLinkGroup_v4 = { mDNSAddrType_IPv4, { { { 224,   0,   0, 251 } } } };
 mDNSexport const mDNSAddr   AllDNSLinkGroup_v6 = { mDNSAddrType_IPv6, { { { 0xFF,0x02,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xFB } } } };
 
-static const mDNSOpaque16 zeroID = { { 0, 0 } };
-static const mDNSOpaque16 QueryFlags    = { { kDNSFlag0_QR_Query    | kDNSFlag0_OP_StdQuery,                0 } };
-static const mDNSOpaque16 ResponseFlags = { { kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery | kDNSFlag0_AA, 0 } };
+mDNSexport const mDNSOpaque16 zeroID = { { 0, 0 } };
+mDNSexport const mDNSOpaque16 QueryFlags    = { { kDNSFlag0_QR_Query    | kDNSFlag0_OP_StdQuery,                0 } };
+mDNSexport const mDNSOpaque16 ResponseFlags = { { kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery | kDNSFlag0_AA, 0 } };
+mDNSexport const mDNSOpaque16 UpdateReqFlags= { { kDNSFlag0_OP_Update   | kDNSFlag0_QR_Query,                   0 } };
+mDNSexport const mDNSOpaque16 UpdateRespFlags={ { kDNSFlag0_OP_Update   | kDNSFlag0_QR_Response,                0 } };
 #define zeroDomainNamePtr ((domainname*)"")
 
 // Any records bigger than this are considered 'large' records
@@ -1128,17 +1294,16 @@ static const mDNSOpaque16 ResponseFlags = { { kDNSFlag0_QR_Response | kDNSFlag0_
 #define kDefaultTTLforShared (2*3600)
 
 #define kMaxUpdateCredits 10
+#define kUpdateCreditRefreshInterval (mDNSPlatformOneSecond * 50)
 
 static const char *const mDNS_DomainTypeNames[] =
        {
-       "_browse._dns-sd._udp.local.",
-       "_default._browse._dns-sd._udp.local.",
-       "_register._dns-sd._udp.local.",
-       "_default._register._dns-sd._udp.local."
+       "_browse._dns-sd._udp.",
+       "_default._browse._dns-sd._udp.",
+       "_register._dns-sd._udp.",
+       "_default._register._dns-sd._udp."
        };
 
-#define AssignDomainName(DST, SRC) mDNSPlatformMemCopy((SRC).c, (DST).c, DomainNameLength(&(SRC)))
-
 // ***************************************************************************
 #if COMPILER_LIKES_PRAGMA_MARK
 #pragma mark -
@@ -1157,13 +1322,15 @@ static const struct mDNSprintf_format
        char          sign;             // +, - or space
        unsigned int  fieldWidth;
        unsigned int  precision;
-       } mDNSprintf_format_default;
+       } mDNSprintf_format_default = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
 
 mDNSexport mDNSu32 mDNS_vsnprintf(char *sbuffer, mDNSu32 buflen, const char *fmt, va_list arg)
        {
        mDNSu32 nwritten = 0;
        int c;
+       if (buflen == 0) return(0);
        buflen--;               // Pre-reserve one space in the buffer for the terminating nul
+       if (buflen == 0) goto exit;
 
        for (c = *fmt; c != 0; c = *++fmt)
                {
@@ -1275,17 +1442,14 @@ mDNSexport mDNSu32 mDNS_vsnprintf(char *sbuffer, mDNSu32 buflen, const char *fmt
                                                        if (!a) { static char emsg[] = "<<NULL>>"; s = emsg; i = sizeof(emsg)-1; }
                                                        else
                                                                {
-                                                               unsigned short *w = (unsigned short *)a;
                                                                s = mDNS_VACB;  // Adjust s to point to the start of the buffer, not the end
                                                                if (F.altForm)
                                                                        {
                                                                        mDNSAddr *ip = (mDNSAddr*)a;
-                                                                       a = (unsigned char  *)&ip->ip.v4;
-                                                                       w = (unsigned short *)&ip->ip.v6;
                                                                        switch (ip->type)
                                                                                {
-                                                                               case mDNSAddrType_IPv4: F.precision =  4; break;
-                                                                               case mDNSAddrType_IPv6: F.precision = 16; break;
+                                                                               case mDNSAddrType_IPv4: F.precision =  4; a = (unsigned char *)&ip->ip.v4; break;
+                                                                               case mDNSAddrType_IPv6: F.precision = 16; a = (unsigned char *)&ip->ip.v6; break;
                                                                                default:                F.precision =  0; break;
                                                                                }
                                                                        }
@@ -1295,8 +1459,10 @@ mDNSexport mDNSu32 mDNS_vsnprintf(char *sbuffer, mDNSu32 buflen, const char *fmt
                                                                                                                a[0], a[1], a[2], a[3]); break;
                                                                        case  6: i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "%02X:%02X:%02X:%02X:%02X:%02X",
                                                                                                                a[0], a[1], a[2], a[3], a[4], a[5]); break;
-                                                                       case 16: i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "%04X:%04X:%04X:%04X:%04X:%04X:%04X:%04X",
-                                                                                                               w[0], w[1], w[2], w[3], w[4], w[5], w[6], w[7]); break;
+                                                                       case 16: i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB),
+                                                                                                               "%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X",
+                                                                                                               a[0x0], a[0x1], a[0x2], a[0x3], a[0x4], a[0x5], a[0x6], a[0x7],
+                                                                                                               a[0x8], a[0x9], a[0xA], a[0xB], a[0xC], a[0xD], a[0xE], a[0xF]); break;
                                                                        default: i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "%s", "<< ERROR: Must specify address size "
                                                                                                                "(i.e. %.4a=IPv4, %.6a=Ethernet, %.16a=IPv6) >>"); break;
                                                                        }
@@ -1334,7 +1500,35 @@ mDNSexport mDNSu32 mDNS_vsnprintf(char *sbuffer, mDNSu32 buflen, const char *fmt
                                                        if (!s) { static char emsg[] = "<<NULL>>"; s = emsg; i = sizeof(emsg)-1; }
                                                        else switch (F.altForm)
                                                                {
-                                                               case 0: { char *a=s; i=0; while(*a++) i++; break; }     // C string
+                                                               case 0: i=0;
+                                                                               if (!F.havePrecision)                           // C string
+                                                                                       while(s[i]) i++;
+                                                                               else
+                                                                                       {
+                                                                                       while ((i < F.precision) && s[i]) i++;
+                                                                                       // Make sure we don't truncate in the middle of a UTF-8 character
+                                                                                       // If last character we got was any kind of UTF-8 multi-byte character,
+                                                                                       // then see if we have to back up.
+                                                                                       // This is not as easy as the similar checks below, because
+                                                                                       // here we can't assume it's safe to examine the *next* byte, so we
+                                                                                       // have to confine ourselves to working only backwards in the string.
+                                                                                       j = i;          // Record where we got to
+                                                                                       // Now, back up until we find first non-continuation-char
+                                                                                       while (i>0 && (s[i-1] & 0xC0) == 0x80) i--;
+                                                                                       // Now s[i-1] is the first non-continuation-char
+                                                                                       // and (j-i) is the number of continuation-chars we found
+                                                                                       if (i>0 && (s[i-1] & 0xC0) == 0xC0)     // If we found a start-char
+                                                                                               {
+                                                                                               i--;            // Tentatively eliminate this start-char as well
+                                                                                               // Now (j-i) is the number of characters we're considering eliminating.
+                                                                                               // To be legal UTF-8, the start-char must contain (j-i) one-bits,
+                                                                                               // followed by a zero bit. If we shift it right by (7-(j-i)) bits
+                                                                                               // (with sign extension) then the result has to be 0xFE.
+                                                                                               // If this is right, then we reinstate the tentatively eliminated bytes.
+                                                                                               if (((j-i) < 7) && (((s[i] >> (7-(j-i))) & 0xFF) == 0xFE)) i = j;
+                                                                                               }
+                                                                                       }
+                                                                               break;
                                                                case 1: i = (unsigned char) *s++; break;        // Pascal string
                                                                case 2: {                                                                       // DNS label-sequence name
                                                                                unsigned char *a = (unsigned char *)s;
@@ -1352,7 +1546,8 @@ mDNSexport mDNSu32 mDNS_vsnprintf(char *sbuffer, mDNSu32 buflen, const char *fmt
                                                                                break;
                                                                                }
                                                                }
-                                                       if (F.havePrecision && i > F.precision)         // Make sure we don't truncate in the middle of a UTF-8 character
+                                                       // Make sure we don't truncate in the middle of a UTF-8 character (see similar comment below)
+                                                       if (F.havePrecision && i > F.precision)
                                                                { i = F.precision; while (i>0 && (s[i] & 0xC0) == 0x80) i--; }
                                                        break;
        
@@ -1376,7 +1571,11 @@ mDNSexport mDNSu32 mDNS_vsnprintf(char *sbuffer, mDNSu32 buflen, const char *fmt
                                        if (++nwritten >= buflen) goto exit;
                                        } while (i < --F.fieldWidth);
        
-                       if (i > buflen - nwritten)      // Make sure we don't truncate in the middle of a UTF-8 character
+                       // Make sure we don't truncate in the middle of a UTF-8 character.
+                       // Note: s[i] is the first eliminated character; i.e. the next character *after* the last character of the allowed output. If s[i] is a
+                       // UTF-8 continuation character, then we've cut a unicode character in half, so back up 'i' until s[i] is no longer a UTF-8 continuation
+                       // character. (if the input was proprly formed, s[i] will now be the UTF-8 start character of the multi-byte character we just eliminated).
+                       if (i > buflen - nwritten)
                                { i = buflen - nwritten; while (i>0 && (s[i] & 0xC0) == 0x80) i--; }
                        for (j=0; j<i; j++) *sbuffer++ = *s++;                  // Write the converted result
                        nwritten += i;
@@ -1412,117 +1611,6 @@ mDNSexport mDNSu32 mDNS_snprintf(char *sbuffer, mDNSu32 buflen, const char *fmt,
 #pragma mark - General Utility Functions
 #endif
 
-mDNSexport char *DNSTypeName(mDNSu16 rrtype)
-       {
-       switch (rrtype)
-               {
-               case kDNSType_A:    return("Addr");
-               case kDNSType_CNAME:return("CNAME");
-               case kDNSType_NULL: return("NULL");
-               case kDNSType_PTR:  return("PTR");
-               case kDNSType_HINFO:return("HINFO");
-               case kDNSType_TXT:  return("TXT");
-               case kDNSType_AAAA: return("AAAA");
-               case kDNSType_SRV:  return("SRV");
-               case kDNSQType_ANY: return("ANY");
-               default:                        {
-                                                       static char buffer[16];
-                                                       mDNS_snprintf(buffer, sizeof(buffer), "(%d)", rrtype);
-                                                       return(buffer);
-                                                       }
-               }
-       }
-
-mDNSexport char *GetRRDisplayString_rdb(mDNS *const m, const ResourceRecord *rr, RDataBody *rd)
-       {
-       char *ptr = m->MsgBuffer;
-       mDNSu32 length = mDNS_snprintf(m->MsgBuffer, 79, "%4d %##s %s ", rr->rdlength, rr->name.c, DNSTypeName(rr->rrtype));
-       switch (rr->rrtype)
-               {
-               case kDNSType_A:        mDNS_snprintf(m->MsgBuffer+length, 79-length, "%.4a", &rd->ip);         break;
-               case kDNSType_CNAME:// Same as PTR
-               case kDNSType_PTR:      mDNS_snprintf(m->MsgBuffer+length, 79-length, "%##s", &rd->name);       break;
-               case kDNSType_HINFO:// Display this the same as TXT (just show first string)
-               case kDNSType_TXT:  mDNS_snprintf(m->MsgBuffer+length, 79-length, "%#s", rd->txt.c);        break;
-               case kDNSType_AAAA:     mDNS_snprintf(m->MsgBuffer+length, 79-length, "%.16a", &rd->ipv6);      break;
-               case kDNSType_SRV:      mDNS_snprintf(m->MsgBuffer+length, 79-length, "%##s", &rd->srv.target); break;
-               default:                        mDNS_snprintf(m->MsgBuffer+length, 79-length, "RDLen %d: %s",
-                                                               rr->rdlength, rd->data);  break;
-               }
-       for (ptr = m->MsgBuffer; *ptr; ptr++) if (*ptr < ' ') *ptr='.';
-       return(m->MsgBuffer);
-       }
-
-mDNSlocal mDNSu32 mDNSRandom(mDNSu32 max)
-       {
-       static mDNSu32 seed = 0;
-       mDNSu32 mask = 1;
-       
-       if (!seed) seed = (mDNSu32)mDNSPlatformTimeNow();
-       while (mask < max) mask = (mask << 1) | 1;
-       do seed = seed * 21 + 1; while ((seed & mask) > max);
-       return (seed & mask);
-       }
-
-#define mDNSSameIPv4Address(A,B) ((A).NotAnInteger == (B).NotAnInteger)
-#define mDNSSameIPv6Address(A,B) ((A).l[0] == (B).l[0] && (A).l[1] == (B).l[1] && (A).l[2] == (B).l[2] && (A).l[3] == (B).l[3])
-
-#define mDNSIPv4AddressIsZero(A) mDNSSameIPv4Address((A), zeroIPAddr)
-#define mDNSIPv6AddressIsZero(A) mDNSSameIPv6Address((A), zerov6Addr)
-
-#define mDNSIPv4AddressIsOnes(A) mDNSSameIPv4Address((A), onesIPv4Addr)
-#define mDNSIPv6AddressIsOnes(A) mDNSSameIPv6Address((A), onesIPv6Addr)
-
-#define mDNSAddressIsZero(X) (                                              \
-       ((X)->type == mDNSAddrType_IPv4 && mDNSIPv4AddressIsZero((X)->ip.v4)) || \
-       ((X)->type == mDNSAddrType_IPv6 && mDNSIPv6AddressIsZero((X)->ip.v6))    )
-
-#define mDNSAddressIsOnes(X) (                                              \
-       ((X)->type == mDNSAddrType_IPv4 && mDNSIPv4AddressIsOnes((X)->ip.v4)) || \
-       ((X)->type == mDNSAddrType_IPv6 && mDNSIPv6AddressIsOnes((X)->ip.v6))    )
-
-#define mDNSAddressIsValid(X) (                                                                                             \
-       ((X)->type == mDNSAddrType_IPv4) ? !(mDNSIPv4AddressIsZero((X)->ip.v4) || mDNSIPv4AddressIsOnes((X)->ip.v4)) :          \
-       ((X)->type == mDNSAddrType_IPv6) ? !(mDNSIPv6AddressIsZero((X)->ip.v6) || mDNSIPv6AddressIsOnes((X)->ip.v6)) : mDNSfalse)
-
-mDNSexport mDNSBool mDNSSameAddress(const mDNSAddr *ip1, const mDNSAddr *ip2)
-       {
-       if (ip1->type == ip2->type)
-               {
-               switch (ip1->type)
-                       {
-                       case mDNSAddrType_IPv4 : return(mDNSBool)(mDNSSameIPv4Address(ip1->ip.v4, ip2->ip.v4));
-                       case mDNSAddrType_IPv6 : return(mDNSBool)(mDNSSameIPv6Address(ip1->ip.v6, ip2->ip.v6));
-                       }
-               }
-       return(mDNSfalse);
-       }
-
-mDNSexport mDNSBool mDNSAddrIsDNSMulticast(const mDNSAddr *ip)
-       {
-       switch(ip->type)
-               {
-               case mDNSAddrType_IPv4: return(mDNSBool)(ip->ip.v4.NotAnInteger == AllDNSLinkGroup.NotAnInteger);
-               case mDNSAddrType_IPv6: return(mDNSBool)(ip->ip.v6.l[0] == AllDNSLinkGroupv6.l[0] &&
-                                                                                                ip->ip.v6.l[1] == AllDNSLinkGroupv6.l[1] &&
-                                                                                                ip->ip.v6.l[2] == AllDNSLinkGroupv6.l[2] &&
-                                                                                                ip->ip.v6.l[3] == AllDNSLinkGroupv6.l[3] );
-               default: return(mDNSfalse);
-               }
-       }
-
-mDNSlocal const NetworkInterfaceInfo *GetFirstActiveInterface(const NetworkInterfaceInfo *intf)
-       {
-       while (intf && !intf->InterfaceActive) intf = intf->next;
-       return(intf);
-       }
-
-mDNSlocal mDNSInterfaceID GetNextActiveInterfaceID(const NetworkInterfaceInfo *intf)
-       {
-       const NetworkInterfaceInfo *next = GetFirstActiveInterface(intf->next);
-       if (next) return(next->InterfaceID); else return(mDNSNULL);
-       }
-
 #define InitialQuestionInterval (mDNSPlatformOneSecond/2)
 #define ActiveQuestion(Q) ((Q)->ThisQInterval > 0 && !(Q)->DuplicateOf)
 #define TimeToSendThisQuestion(Q,time) (ActiveQuestion(Q) && (time) - ((Q)->LastQTime + (Q)->ThisQInterval) >= 0)
@@ -1537,730 +1625,125 @@ mDNSlocal void SetNextQueryTime(mDNS *const m, const DNSQuestion *const q)
 // ***************************************************************************
 #if COMPILER_LIKES_PRAGMA_MARK
 #pragma mark -
-#pragma mark - Domain Name Utility Functions
+#pragma mark - Resource Record Utility Functions
 #endif
 
-#define mdnsIsDigit(X)     ((X) >= '0' && (X) <= '9')
-#define mDNSIsUpperCase(X) ((X) >= 'A' && (X) <= 'Z')
-#define mDNSIsLowerCase(X) ((X) >= 'a' && (X) <= 'z')
-#define mdnsIsLetter(X)    (mDNSIsUpperCase(X) || mDNSIsLowerCase(X))
-
-mDNSexport mDNSBool SameDomainLabel(const mDNSu8 *a, const mDNSu8 *b)
-       {
-       int i;
-       const int len = *a++;
+#define RRTypeIsAddressType(T) ((T) == kDNSType_A || (T) == kDNSType_AAAA)
 
-       if (len > MAX_DOMAIN_LABEL)
-               { debugf("Malformed label (too long)"); return(mDNSfalse); }
+#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))  )
 
-       if (len != *b++) return(mDNSfalse);
-       for (i=0; i<len; i++)
-               {
-               mDNSu8 ac = *a++;
-               mDNSu8 bc = *b++;
-               if (mDNSIsUpperCase(ac)) ac += 'a' - 'A';
-               if (mDNSIsUpperCase(bc)) bc += 'a' - 'A';
-               if (ac != bc) return(mDNSfalse);
-               }
-       return(mDNStrue);
-       }
+#define ResourceRecordIsValidInterfaceAnswer(RR, INTID) \
+       (ResourceRecordIsValidAnswer(RR) && \
+       ((RR)->resrec.InterfaceID == mDNSInterface_Any || (RR)->resrec.InterfaceID == (INTID)))
 
-mDNSexport mDNSBool SameDomainName(const domainname *const d1, const domainname *const d2)
-       {
-       const mDNSu8 *      a   = d1->c;
-       const mDNSu8 *      b   = d2->c;
-       const mDNSu8 *const max = d1->c + MAX_DOMAIN_NAME;                      // Maximum that's valid
+#define RRUniqueOrKnownUnique(RR) ((RR)->RecordType & (kDNSRecordTypeUnique | kDNSRecordTypeKnownUnique))
 
-       while (*a || *b)
-               {
-               if (a + 1 + *a >= max)
-                       { debugf("Malformed domain name (more than 255 characters)"); return(mDNSfalse); }
-               if (!SameDomainLabel(a, b)) return(mDNSfalse);
-               a += 1 + *a;
-               b += 1 + *b;
-               }
-       
-       return(mDNStrue);
-       }
+#define DefaultProbeCountForTypeUnique ((mDNSu8)3)
+#define DefaultProbeCountForRecordType(X)      ((X) == kDNSRecordTypeUnique ? DefaultProbeCountForTypeUnique : (mDNSu8)0)
 
-// Returns length of a domain name INCLUDING the byte for the final null label
-// i.e. for the root label "." it returns one
-// For the FQDN "com." it returns 5 (length byte, three data bytes, final zero)
-// Legal results are 1 (just root label) to 255 (MAX_DOMAIN_NAME)
-// If the given domainname is invalid, result is 256
-mDNSexport mDNSu16 DomainNameLength(const domainname *const name)
-       {
-       const mDNSu8 *src = name->c;
-       while (*src)
-               {
-               if (*src > MAX_DOMAIN_LABEL) return(MAX_DOMAIN_NAME+1);
-               src += 1 + *src;
-               if (src - name->c >= MAX_DOMAIN_NAME) return(MAX_DOMAIN_NAME+1);
-               }
-       return((mDNSu16)(src - name->c + 1));
-       }
+// For records that have *never* been announced on the wire, their AnnounceCount will be set to InitialAnnounceCount (10).
+// When de-registering these records we do not need to send any goodbye packet because we never announced them in the first
+// place. If AnnounceCount is less than InitialAnnounceCount that means we have announced them at least once, so a goodbye
+// packet is needed. For this reason, if we ever reset AnnounceCount (e.g. after an interface change) we set it to
+// ReannounceCount (9), not InitialAnnounceCount. If we were to reset AnnounceCount back to InitialAnnounceCount that would
+// imply that the record had never been announced on the wire (which is false) and if the client were then to immediately
+// deregister that record before it had a chance to announce, we'd fail to send its goodbye packet (which would be a bug).
+#define InitialAnnounceCount ((mDNSu8)10)
+#define ReannounceCount      ((mDNSu8)9)
 
-// CompressedDomainNameLength returns the length of a domain name INCLUDING the byte
-// for the final null label i.e. for the root label "." it returns one.
-// E.g. for the FQDN "foo.com." it returns 9
-// (length, three data bytes, length, three more data bytes, final zero).
-// In the case where a parent domain name is provided, and the given name is a child
-// of that parent, CompressedDomainNameLength returns the length of the prefix portion
-// of the child name, plus TWO bytes for the compression pointer.
-// E.g. for the name "foo.com." with parent "com.", it returns 6
-// (length, three data bytes, two-byte compression pointer).
-mDNSlocal mDNSu16 CompressedDomainNameLength(const domainname *const name, const domainname *parent)
-       {
-       const mDNSu8 *src = name->c;
-       if (parent && parent->c[0] == 0) parent = mDNSNULL;
-       while (*src)
-               {
-               if (*src > MAX_DOMAIN_LABEL) return(MAX_DOMAIN_NAME+1);
-               if (parent && SameDomainName((domainname *)src, parent)) return((mDNSu16)(src - name->c + 2));
-               src += 1 + *src;
-               if (src - name->c >= MAX_DOMAIN_NAME) return(MAX_DOMAIN_NAME+1);
-               }
-       return((mDNSu16)(src - name->c + 1));
-       }
+// Note that the announce intervals use exponential backoff, doubling each time. The probe intervals do not.
+// This means that because the announce interval is doubled after sending the first packet, the first
+// observed on-the-wire inter-packet interval between announcements is actually one second.
+// The half-second value here may be thought of as a conceptual (non-existent) half-second delay *before* the first packet is sent.
+#define DefaultProbeIntervalForTypeUnique (mDNSPlatformOneSecond/4)
+#define DefaultAnnounceIntervalForTypeShared (mDNSPlatformOneSecond/2)
+#define DefaultAnnounceIntervalForTypeUnique (mDNSPlatformOneSecond/2)
 
-// AppendLiteralLabelString appends a single label to an existing (possibly empty) domainname.
-// The C string contains the label as-is, with no escaping, etc.
-// Any dots in the name are literal dots, not label separators
-// If successful, AppendLiteralLabelString returns a pointer to the next unused byte
-// in the domainname bufer (i.e., the next byte after the terminating zero).
-// If unable to construct a legal domain name (i.e. label more than 63 bytes, or total more than 255 bytes)
-// AppendLiteralLabelString returns mDNSNULL.
-mDNSexport mDNSu8 *AppendLiteralLabelString(domainname *const name, const char *cstr)
-       {
-       mDNSu8       *      ptr  = name->c + DomainNameLength(name) - 1;        // Find end of current name
-       const mDNSu8 *const lim1 = name->c + MAX_DOMAIN_NAME - 1;                       // Limit of how much we can add (not counting final zero)
-       const mDNSu8 *const lim2 = ptr + 1 + MAX_DOMAIN_LABEL;
-       const mDNSu8 *const lim  = (lim1 < lim2) ? lim1 : lim2;
-       mDNSu8       *lengthbyte = ptr++;                                                                       // Record where the length is going to go
-       
-       while (*cstr && ptr < lim) *ptr++ = (mDNSu8)*cstr++;    // Copy the data
-       *lengthbyte = (mDNSu8)(ptr - lengthbyte - 1);                   // Fill in the length byte
-       *ptr++ = 0;                                                                                             // Put the null root label on the end
-       if (*cstr) return(mDNSNULL);                                                    // Failure: We didn't successfully consume all input
-       else return(ptr);                                                                               // Success: return new value of ptr
-       }
+#define DefaultAPIntervalForRecordType(X)  ((X) & (kDNSRecordTypeAdvisory | kDNSRecordTypeShared     ) ? DefaultAnnounceIntervalForTypeShared : \
+                                                                                       (X) & (kDNSRecordTypeUnique                              ) ? DefaultProbeIntervalForTypeUnique    : \
+                                                                                       (X) & (kDNSRecordTypeVerified | kDNSRecordTypeKnownUnique) ? DefaultAnnounceIntervalForTypeUnique : 0)
 
-// AppendDNSNameString appends zero or more labels to an existing (possibly empty) domainname.
-// The C string is in conventional DNS syntax:
-// Textual labels, escaped as necessary using the usual DNS '\' notation, separated by dots.
-// If successful, AppendDNSNameString returns a pointer to the next unused byte
-// in the domainname bufer (i.e., the next byte after the terminating zero).
-// If unable to construct a legal domain name (i.e. label more than 63 bytes, or total more than 255 bytes)
-// AppendDNSNameString returns mDNSNULL.
-mDNSexport mDNSu8 *AppendDNSNameString(domainname *const name, const char *cstr)
-       {
-       mDNSu8       *      ptr = name->c + DomainNameLength(name) - 1; // Find end of current name
-       const mDNSu8 *const lim = name->c + MAX_DOMAIN_NAME - 1;                // Limit of how much we can add (not counting final zero)
-       while (*cstr && ptr < lim)                                                                              // While more characters, and space to put them...
-               {
-               mDNSu8 *lengthbyte = ptr++;                                                                     // Record where the length is going to go
-               while (*cstr && *cstr != '.' && ptr < lim)                                      // While we have characters in the label...
-                       {
-                       mDNSu8 c = (mDNSu8)*cstr++;                                                             // Read the character
-                       if (c == '\\')                                                                                  // If escape character, check next character
-                               {
-                               c = (mDNSu8)*cstr++;                                                            // Assume we'll just take the next character
-                               if (mdnsIsDigit(cstr[-1]) && mdnsIsDigit(cstr[0]) && mdnsIsDigit(cstr[1]))
-                                       {                                                                                               // If three decimal digits,
-                                       int v0 = cstr[-1] - '0';                                                // then interpret as three-digit decimal
-                                       int v1 = cstr[ 0] - '0';
-                                       int v2 = cstr[ 1] - '0';
-                                       int val = v0 * 100 + v1 * 10 + v2;
-                                       if (val <= 255) { c = (mDNSu8)val; cstr += 2; } // If valid three-digit decimal value, use it
-                                       }
-                               }
-                       *ptr++ = c;                                                                                             // Write the character
-                       }
-               if (*cstr) cstr++;                                                                                      // Skip over the trailing dot (if present)
-               if (ptr - lengthbyte - 1 > MAX_DOMAIN_LABEL)                            // If illegal label, abort
-                       return(mDNSNULL);
-               *lengthbyte = (mDNSu8)(ptr - lengthbyte - 1);                           // Fill in the length byte
-               }
+#define TimeToAnnounceThisRecord(RR,time) ((RR)->AnnounceCount && (time) - ((RR)->LastAPTime + (RR)->ThisAPInterval) >= 0)
+#define TimeToSendThisRecord(RR,time) ((TimeToAnnounceThisRecord(RR,time) || (RR)->ImmedAnswer) && ResourceRecordIsValidAnswer(RR))
+#define TicksTTL(RR) ((mDNSs32)(RR)->resrec.rroriginalttl * mDNSPlatformOneSecond)
+#define RRExpireTime(RR) ((RR)->TimeRcvd + TicksTTL(RR))
 
-       *ptr++ = 0;                                                                                                             // Put the null root label on the end
-       if (*cstr) return(mDNSNULL);                                                                    // Failure: We didn't successfully consume all input
-       else return(ptr);                                                                                               // Success: return new value of ptr
-       }
+#define MaxUnansweredQueries 4
 
-// AppendDomainLabel appends a single label to a name.
-// If successful, AppendDomainLabel returns a pointer to the next unused byte
-// in the domainname bufer (i.e., the next byte after the terminating zero).
-// If unable to construct a legal domain name (i.e. label more than 63 bytes, or total more than 255 bytes)
-// AppendDomainLabel returns mDNSNULL.
-mDNSexport mDNSu8 *AppendDomainLabel(domainname *const name, const domainlabel *const label)
+// SameResourceRecordSignature returns true if two resources records have the same name, type, and class, and may be sent
+// (or were received) on the same interface (i.e. if *both* records specify an interface, then it has to match).
+// TTL and rdata may differ.
+// This is used for cache flush management:
+// When sending a unique record, all other records matching "SameResourceRecordSignature" must also be sent
+// When receiving a unique record, all old cache records matching "SameResourceRecordSignature" are flushed
+mDNSlocal mDNSBool SameResourceRecordSignature(const ResourceRecord *const r1, const ResourceRecord *const r2)
        {
-       int i;
-       mDNSu8 *ptr = name->c + DomainNameLength(name) - 1;
-
-       // Check label is legal
-       if (label->c[0] > MAX_DOMAIN_LABEL) return(mDNSNULL);
-
-       // Check that ptr + length byte + data bytes + final zero does not exceed our limit
-       if (ptr + 1 + label->c[0] + 1 > name->c + MAX_DOMAIN_NAME) return(mDNSNULL);
-
-       for (i=0; i<=label->c[0]; i++) *ptr++ = label->c[i];    // Copy the label data
-       *ptr++ = 0;                                                             // Put the null root label on the end
-       return(ptr);
+       if (!r1) { LogMsg("SameResourceRecordSignature ERROR: r1 is NULL"); return(mDNSfalse); }
+       if (!r2) { LogMsg("SameResourceRecordSignature ERROR: r2 is NULL"); return(mDNSfalse); }
+       if (r1->InterfaceID &&
+               r2->InterfaceID &&
+               r1->InterfaceID != r2->InterfaceID) return(mDNSfalse);
+       return(mDNSBool)(r1->rrtype == r2->rrtype && r1->rrclass == r2->rrclass && r1->namehash == r2->namehash && SameDomainName(&r1->name, &r2->name));
        }
 
-mDNSexport mDNSu8 *AppendDomainName(domainname *const name, const domainname *const append)
+// PacketRRMatchesSignature behaves as SameResourceRecordSignature, except that types may differ if the
+// authoratative record is in the probing state.  We always send probes with the wildcard type kDNSQType_ANY,
+// so a response of any type should match, even if it is not the type the client plans to use.
+mDNSlocal mDNSBool PacketRRMatchesSignature(const CacheRecord *const pktrr, const AuthRecord *const authrr)
        {
-       mDNSu8       *      ptr = name->c + DomainNameLength(name) - 1; // Find end of current name
-       const mDNSu8 *const lim = name->c + MAX_DOMAIN_NAME - 1;                // Limit of how much we can add (not counting final zero)
-       const mDNSu8 *      src = append->c;
-       while(src[0])
-               {
-               int i;
-               if (ptr + 1 + src[0] > lim) return(mDNSNULL);
-               for (i=0; i<=src[0]; i++) *ptr++ = src[i];
-               *ptr = 0;       // Put the null root label on the end
-               src += i;
-               }
-       return(ptr);
+       if (!pktrr)  { LogMsg("PacketRRMatchesSignature ERROR: pktrr is NULL"); return(mDNSfalse); }
+       if (!authrr) { LogMsg("PacketRRMatchesSignature ERROR: authrr is NULL"); return(mDNSfalse); }
+       if (pktrr->resrec.InterfaceID &&
+               authrr->resrec.InterfaceID &&
+               pktrr->resrec.InterfaceID != authrr->resrec.InterfaceID) return(mDNSfalse);
+       if (authrr->resrec.RecordType != kDNSRecordTypeUnique && pktrr->resrec.rrtype != authrr->resrec.rrtype) return(mDNSfalse);
+       return(mDNSBool)(pktrr->resrec.rrclass == authrr->resrec.rrclass && pktrr->resrec.namehash == authrr->resrec.namehash && SameDomainName(&pktrr->resrec.name, &authrr->resrec.name));
        }
 
-// MakeDomainLabelFromLiteralString makes a single domain label from a single literal C string (with no escaping).
-// If successful, MakeDomainLabelFromLiteralString returns mDNStrue.
-// If unable to convert the whole string to a legal domain label (i.e. because length is more than 63 bytes) then
-// MakeDomainLabelFromLiteralString makes a legal domain label from the first 63 bytes of the string and returns mDNSfalse.
-// In some cases silently truncated oversized names to 63 bytes is acceptable, so the return result may be ignored.
-// In other cases silent truncation may not be acceptable, so in those cases the calling function needs to check the return result.
-mDNSexport mDNSBool MakeDomainLabelFromLiteralString(domainlabel *const label, const char *cstr)
+// IdenticalResourceRecord returns true if two resources records have
+// the same name, type, class, and identical rdata (InterfaceID and TTL may differ)
+mDNSlocal mDNSBool IdenticalResourceRecord(const ResourceRecord *const r1, const ResourceRecord *const r2)
        {
-       mDNSu8       *      ptr   = label->c + 1;                                               // Where we're putting it
-       const mDNSu8 *const limit = label->c + 1 + MAX_DOMAIN_LABEL;    // The maximum we can put
-       while (*cstr && ptr < limit) *ptr++ = (mDNSu8)*cstr++;                  // Copy the label
-       label->c[0] = (mDNSu8)(ptr - label->c - 1);                                             // Set the length byte
-       return(*cstr == 0);                                                                                             // Return mDNStrue if we successfully consumed all input
+       if (!r1) { LogMsg("IdenticalResourceRecord ERROR: r1 is NULL"); return(mDNSfalse); }
+       if (!r2) { LogMsg("IdenticalResourceRecord ERROR: r2 is NULL"); return(mDNSfalse); }
+       if (r1->rrtype != r2->rrtype || r1->rrclass != r2->rrclass || r1->namehash != r2->namehash || !SameDomainName(&r1->name, &r2->name)) return(mDNSfalse);
+       return(SameRData(r1, r2));
        }
 
-// MakeDomainNameFromDNSNameString makes a native DNS-format domainname from a C string.
-// The C string is in conventional DNS syntax:
-// Textual labels, escaped as necessary using the usual DNS '\' notation, separated by dots.
-// If successful, MakeDomainNameFromDNSNameString returns a pointer to the next unused byte
-// in the domainname bufer (i.e., the next byte after the terminating zero).
-// If unable to construct a legal domain name (i.e. label more than 63 bytes, or total more than 255 bytes)
-// MakeDomainNameFromDNSNameString returns mDNSNULL.
-mDNSexport mDNSu8 *MakeDomainNameFromDNSNameString(domainname *const name, const char *cstr)
+// CacheRecord *ks is the CacheRecord from the known answer list in the query.
+// This is the information that the requester believes to be correct.
+// AuthRecord *rr is the answer we are proposing to give, if not suppressed.
+// This is the information that we believe to be correct.
+// We've already determined that we plan to give this answer on this interface
+// (either the record is non-specific, or it is specific to this interface)
+// so now we just need to check the name, type, class, rdata and TTL.
+mDNSlocal mDNSBool ShouldSuppressKnownAnswer(const CacheRecord *const ka, const AuthRecord *const rr)
        {
-       name->c[0] = 0;                                                                 // Make an empty domain name
-       return(AppendDNSNameString(name, cstr));                // And then add this string to it
+       // If RR signature is different, or data is different, then don't suppress our answer
+       if (!IdenticalResourceRecord(&ka->resrec,&rr->resrec)) return(mDNSfalse);
+       
+       // If the requester's indicated TTL is less than half the real TTL,
+       // we need to give our answer before the requester's copy expires.
+       // If the requester's indicated TTL is at least half the real TTL,
+       // then we can suppress our answer this time.
+       // If the requester's indicated TTL is greater than the TTL we believe,
+       // then that's okay, and we don't need to do anything about it.
+       // (If two responders on the network are offering the same information,
+       // that's okay, and if they are offering the information with different TTLs,
+       // the one offering the lower TTL should defer to the one offering the higher TTL.)
+       return(mDNSBool)(ka->resrec.rroriginalttl >= rr->resrec.rroriginalttl / 2);
        }
 
-mDNSexport char *ConvertDomainLabelToCString_withescape(const domainlabel *const label, char *ptr, char esc)
+mDNSlocal void SetNextAnnounceProbeTime(mDNS *const m, const AuthRecord *const rr)
        {
-       const mDNSu8 *      src = label->c;                                                     // Domain label we're reading
-       const mDNSu8        len = *src++;                                                       // Read length of this (non-null) label
-       const mDNSu8 *const end = src + len;                                            // Work out where the label ends
-       if (len > MAX_DOMAIN_LABEL) return(mDNSNULL);                           // If illegal label, abort
-       while (src < end)                                                                                       // While we have characters in the label
+       if (rr->resrec.RecordType == kDNSRecordTypeUnique)
                {
-               mDNSu8 c = *src++;
-               if (esc)
-                       {
-                       if (c == '.' || c == esc)                                                       // If character is a dot or the escape character
-                               *ptr++ = esc;                                                                   // Output escape character
-                       else if (c <= ' ')                                                                      // If non-printing ascii,
-                               {                                                                                               // Output decimal escape sequence
-                               *ptr++ = esc;
-                               *ptr++ = (char)  ('0' + (c / 100)     );
-                               *ptr++ = (char)  ('0' + (c /  10) % 10);
-                               c      = (mDNSu8)('0' + (c      ) % 10);
-                               }
-                       }
-               *ptr++ = (char)c;                                                                               // Copy the character
-               }
-       *ptr = 0;                                                                                                       // Null-terminate the string
-       return(ptr);                                                                                            // and return
-       }
-
-// Note, to guarantee that there will be no possible overrun, cstr must be at least 1005 bytes
-// The longest legal domain name is 255 bytes, in the form of three 64-byte labels, one 62-byte label,
-// and the null root label.
-// If every label character has to be escaped as a four-byte escape sequence, the maximum textual
-// ascii display of this is 63*4 + 63*4 + 63*4 + 61*4 = 1000 label characters,
-// plus four dots and the null at the end of the C string = 1005
-mDNSexport char *ConvertDomainNameToCString_withescape(const domainname *const name, char *ptr, char esc)
-       {
-       const mDNSu8 *src         = name->c;                                                            // Domain name we're reading
-       const mDNSu8 *const max   = name->c + MAX_DOMAIN_NAME;                  // Maximum that's valid
-       
-       if (*src == 0) *ptr++ = '.';                                                                    // Special case: For root, just write a dot
-
-       while (*src)                                                                                                    // While more characters in the domain name
-               {
-               if (src + 1 + *src >= max) return(mDNSNULL);
-               ptr = ConvertDomainLabelToCString_withescape((const domainlabel *)src, ptr, esc);
-               if (!ptr) return(mDNSNULL);
-               src += 1 + *src;
-               *ptr++ = '.';                                                                                           // Write the dot after the label
-               }
-
-       *ptr++ = 0;                                                                                                             // Null-terminate the string
-       return(ptr);                                                                                                    // and return
-       }
-
-// RFC 1034 rules:
-// Host names must start with a letter, end with a letter or digit,
-// and have as interior characters only letters, digits, and hyphen.
-// This was subsequently modified in RFC 1123 to allow the first character to be either a letter or a digit
-#define mdnsValidHostChar(X, notfirst, notlast) (mdnsIsLetter(X) || mdnsIsDigit(X) || ((notfirst) && (notlast) && (X) == '-') )
-
-mDNSexport void ConvertUTF8PstringToRFC1034HostLabel(const mDNSu8 UTF8Name[], domainlabel *const hostlabel)
-       {
-       const mDNSu8 *      src  = &UTF8Name[1];
-       const mDNSu8 *const end  = &UTF8Name[1] + UTF8Name[0];
-             mDNSu8 *      ptr  = &hostlabel->c[1];
-       const mDNSu8 *const lim  = &hostlabel->c[1] + MAX_DOMAIN_LABEL;
-       while (src < end)
-               {
-               // Delete apostrophes from source name
-               if (src[0] == '\'') { src++; continue; }                // Standard straight single quote
-               if (src + 2 < end && src[0] == 0xE2 && src[1] == 0x80 && src[2] == 0x99)
-                       { src += 3; continue; } // Unicode curly apostrophe
-               if (ptr < lim)
-                       {
-                       if (mdnsValidHostChar(*src, (ptr > &hostlabel->c[1]), (src < end-1))) *ptr++ = *src;
-                       else if (ptr > &hostlabel->c[1] && ptr[-1] != '-') *ptr++ = '-';
-                       }
-               src++;
-               }
-       while (ptr > &hostlabel->c[1] && ptr[-1] == '-') ptr--; // Truncate trailing '-' marks
-       hostlabel->c[0] = (mDNSu8)(ptr - &hostlabel->c[1]);
-       }
-
-mDNSexport mDNSu8 *ConstructServiceName(domainname *const fqdn,
-       const domainlabel *name, const domainname *type, const domainname *const domain)
-       {
-       int i, len;
-       mDNSu8 *dst = fqdn->c;
-       const mDNSu8 *src;
-       const char *errormsg;
-
-       // 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)
-               {
-               const mDNSu8 *s0 = type->c;
-               if (s0[0] && s0[0] < 0x40)              // If legal first label (at least one character, and no more than 63)
-                       {
-                       const mDNSu8 * s1 = s0 + 1 + s0[0];
-                       if (s1[0] && s1[0] < 0x40)      // and legal second label (at least one character, and no more than 63)
-                               {
-                               const mDNSu8 *s2 = s1 + 1 + s1[0];
-                               if (s2[0] && s2[0] < 0x40 && s2[1+s2[0]] == 0)  // and we have three and only three labels
-                                       {
-                                       static const mDNSu8 SubTypeLabel[5] = "\x04_sub";
-                                       src = s0;                                                                       // Copy the first label
-                                       len = *src;
-                                       for (i=0; i <= len;                      i++) *dst++ = *src++;
-                                       for (i=0; i < (int)sizeof(SubTypeLabel); i++) *dst++ = SubTypeLabel[i];
-                                       type = (domainname *)s1;
-                                       
-                                       // Special support for queries done by older versions of "Rendezvous Browser"
-                                       // For these queries, we retract the "._sub" we just added between the subtype and the main type
-                                       if (SameDomainName((domainname*)s0, (domainname*)"\x09_services\x07_dns-sd\x04_udp") ||
-                                               SameDomainName((domainname*)s0, (domainname*)"\x09_services\x05_mdns\x04_udp"))
-                                               dst -= sizeof(SubTypeLabel);
-                                       }
-                               }
-                       }
-               }
-
-       if (name && name->c[0])
-               {
-               src = name->c;                                                                  // Put the service name into the domain name
-               len = *src;
-               if (len >= 0x40) { errormsg="Service instance name too long"; goto fail; }
-               for (i=0; i<=len; i++) *dst++ = *src++;
-               }
-       else
-               name = (domainlabel*)"";        // Set this up to be non-null, to avoid errors if we have to call LogMsg() below
-
-       src = type->c;                                                                          // Put the service type into the domain name
-       len = *src;
-       if (len < 2 || len >= 0x40 || (len > 15 && !SameDomainName(domain, (domainname*)"\x05" "local")))
-               {
-               errormsg="Application protocol name must be underscore plus 1-14 characters. See <http://www.dns-sd.org/ServiceTypes.html>";
-               goto fail;
-               }
-       if (src[1] != '_') { errormsg="Application protocol name must begin with underscore"; goto fail; }
-       for (i=2; i<=len; i++)
-               if (!mdnsIsLetter(src[i]) && !mdnsIsDigit(src[i]) && src[i] != '-' && src[i] != '_')
-                       { errormsg="Application protocol name must contain only letters, digits, and hyphens"; goto fail; }
-       for (i=0; i<=len; i++) *dst++ = *src++;
-
-       len = *src;
-       if (!(len == 4 && src[1] == '_' &&
-               (((src[2] | 0x20) == 'u' && (src[3] | 0x20) == 'd') || ((src[2] | 0x20) == 't' && (src[3] | 0x20) == 'c')) &&
-               (src[4] | 0x20) == 'p'))
-               { errormsg="Transport protocol name must be _udp or _tcp"; goto fail; }
-       for (i=0; i<=len; i++) *dst++ = *src++;
-
-       if (*src) { errormsg="Service type must have only two labels"; goto fail; }
-
-       *dst = 0;
-       dst = AppendDomainName(fqdn, domain);
-       if (!dst) { errormsg="Service domain too long"; goto fail; }
-       return(dst);
-
-fail:
-       LogMsg("ConstructServiceName: %s: %#s.%##s%##s", errormsg, name->c, type->c, domain->c);
-       return(mDNSNULL);
-       }
-
-mDNSexport mDNSBool DeconstructServiceName(const domainname *const fqdn,
-       domainlabel *const name, domainname *const type, domainname *const domain)
-       {
-       int i, len;
-       const mDNSu8 *src = fqdn->c;
-       const mDNSu8 *max = fqdn->c + MAX_DOMAIN_NAME;
-       mDNSu8 *dst;
-       
-       dst = name->c;                                                                          // Extract the service name from the domain name
-       len = *src;
-       if (len >= 0x40) { debugf("DeconstructServiceName: service name too long"); return(mDNSfalse); }
-       for (i=0; i<=len; i++) *dst++ = *src++;
-       
-       dst = type->c;                                                                          // Extract the service type from the domain name
-       len = *src;
-       if (len >= 0x40) { debugf("DeconstructServiceName: service type too long"); return(mDNSfalse); }
-       for (i=0; i<=len; i++) *dst++ = *src++;
-
-       len = *src;
-       if (len >= 0x40) { debugf("DeconstructServiceName: service type too long"); return(mDNSfalse); }
-       for (i=0; i<=len; i++) *dst++ = *src++;
-       *dst++ = 0;             // Put the null root label on the end of the service type
-
-       dst = domain->c;                                                                        // Extract the service domain from the domain name
-       while (*src)
-               {
-               len = *src;
-               if (len >= 0x40)
-                       { debugf("DeconstructServiceName: service domain label too long"); return(mDNSfalse); }
-               if (src + 1 + len + 1 >= max)
-                       { debugf("DeconstructServiceName: service domain too long"); return(mDNSfalse); }
-               for (i=0; i<=len; i++) *dst++ = *src++;
-               }
-       *dst++ = 0;             // Put the null root label on the end
-       
-       return(mDNStrue);
-       }
-
-// Returns true if a rich text label ends in " (nnn)", or if an RFC 1034
-// name ends in "-nnn", where n is some decimal number.
-mDNSlocal mDNSBool LabelContainsSuffix(const domainlabel *const name, const mDNSBool RichText)
-       {
-       mDNSu16 l = name->c[0];
-       
-       if (RichText)
-               {
-               if (l < 4) return mDNSfalse;                                                    // Need at least " (2)"
-               if (name->c[l--] != ')') return mDNSfalse;                              // Last char must be ')'
-               if (!mdnsIsDigit(name->c[l])) return mDNSfalse;                 // Preceeded by a digit
-               l--;
-               while (l > 2 && mdnsIsDigit(name->c[l])) l--;                   // Strip off digits
-               return (name->c[l] == '(' && name->c[l - 1] == ' ');
-               }
-       else
-               {
-               if (l < 2) return mDNSfalse;                                                    // Need at least "-2"
-               if (!mdnsIsDigit(name->c[l])) return mDNSfalse;                 // Last char must be a digit
-               l--;
-               while (l > 2 && mdnsIsDigit(name->c[l])) l--;                   // Strip off digits
-               return (name->c[l] == '-');
-               }
-       }
-
-// removes an auto-generated suffix (appended on a name collision) from a label.  caller is
-// responsible for ensuring that the label does indeed contain a suffix.  returns the number
-// from the suffix that was removed.
-mDNSlocal mDNSu32 RemoveLabelSuffix(domainlabel *name, mDNSBool RichText)
-       {
-       mDNSu32 val = 0, multiplier = 1;
-
-       // Chop closing parentheses from RichText suffix
-       if (RichText && name->c[0] >= 1 && name->c[name->c[0]] == ')') name->c[0]--;
-
-       // Get any existing numerical suffix off the name
-       while (mdnsIsDigit(name->c[name->c[0]]))
-               { val += (name->c[name->c[0]] - '0') * multiplier; multiplier *= 10; name->c[0]--; }
-
-       // Chop opening parentheses or dash from suffix
-       if (RichText)
-               {
-               if (name->c[0] >= 2 && name->c[name->c[0]] == '(' && name->c[name->c[0]-1] == ' ') name->c[0] -= 2;
-               }
-       else
-               {
-               if (name->c[0] >= 1 && name->c[name->c[0]] == '-') name->c[0] -= 1;
-               }
-
-       return(val);
-       }
-
-// appends a numerical suffix to a label, with the number following a whitespace and enclosed
-// in parentheses (rich text) or following two consecutive hyphens (RFC 1034 domain label).
-mDNSlocal void AppendLabelSuffix(domainlabel *name, mDNSu32 val, mDNSBool RichText)
-       {
-       mDNSu32 divisor = 1, chars = 2; // Shortest possible RFC1034 name suffix is 3 characters ("-2")
-       if (RichText) chars = 4;                // Shortest possible RichText suffix is 4 characters (" (2)")
-       
-       // Truncate trailing spaces from RichText names
-       if (RichText) while (name->c[name->c[0]] == ' ') name->c[0]--;
-
-       while (val >= divisor * 10) { divisor *= 10; chars++; }
-
-       if (name->c[0] > (mDNSu8)(MAX_DOMAIN_LABEL - chars))
-               {
-               name->c[0] = (mDNSu8)(MAX_DOMAIN_LABEL - chars);
-               // If the following character is a UTF-8 continuation character,
-               // we just chopped a multi-byte UTF-8 character in the middle, so strip back to a safe truncation point
-               while (name->c[0] > 0 && (name->c[name->c[0]+1] & 0xC0) == 0x80) name->c[0]--;
-               }
-
-       if (RichText) { name->c[++name->c[0]] = ' '; name->c[++name->c[0]] = '('; }
-       else          { name->c[++name->c[0]] = '-'; }
-       
-       while (divisor)
-               {
-               name->c[++name->c[0]] = (mDNSu8)('0' + val / divisor);
-               val     %= divisor;
-               divisor /= 10;
-               }
-
-       if (RichText) name->c[++name->c[0]] = ')';
-       }
-
-mDNSexport void IncrementLabelSuffix(domainlabel *name, mDNSBool RichText)
-       {
-       mDNSu32 val = 0;
-
-       if (LabelContainsSuffix(name, RichText))
-               val = RemoveLabelSuffix(name, RichText);
-               
-       // If no existing suffix, start by renaming "Foo" as "Foo (2)" or "Foo-2" as appropriate.
-       // If existing suffix in the range 2-9, increment it.
-       // If we've had ten conflicts already, there are probably too many hosts trying to use the same name,
-       // so add a random increment to improve the chances of finding an available name next time.
-       if      (val == 0) val = 2;
-       else if (val < 10) val++;
-       else               val += 1 + mDNSRandom(99);
-       
-       AppendLabelSuffix(name, val, RichText);
-       }
-
-// ***************************************************************************
-#if COMPILER_LIKES_PRAGMA_MARK
-#pragma mark -
-#pragma mark - Resource Record Utility Functions
-#endif
-
-#define RRIsAddressType(RR) ((RR)->resrec.rrtype == kDNSType_A || (RR)->resrec.rrtype == kDNSType_AAAA)
-#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))  )
-
-#define ResourceRecordIsValidInterfaceAnswer(RR, INTID) \
-       (ResourceRecordIsValidAnswer(RR) && \
-       ((RR)->resrec.InterfaceID == mDNSInterface_Any || (RR)->resrec.InterfaceID == (INTID)))
-
-#define RRUniqueOrKnownUnique(RR) ((RR)->RecordType & (kDNSRecordTypeUnique | kDNSRecordTypeKnownUnique))
-
-#define DefaultProbeCountForTypeUnique ((mDNSu8)3)
-#define DefaultProbeCountForRecordType(X)      ((X) == kDNSRecordTypeUnique ? DefaultProbeCountForTypeUnique : (mDNSu8)0)
-
-// For records that have *never* been announced on the wire, their AnnounceCount will be set to InitialAnnounceCount (10).
-// When de-registering these records we do not need to send any goodbye packet because we never announced them in the first
-// place. If AnnounceCount is less than InitialAnnounceCount that means we have announced them at least once, so a goodbye
-// packet is needed. For this reason, if we ever reset AnnounceCount (e.g. after an interface change) we set it to
-// ReannounceCount (9), not InitialAnnounceCount. If we were to reset AnnounceCount back to InitialAnnounceCount that would
-// imply that the record had never been announced on the wire (which is false) and if the client were then to immediately
-// deregister that record before it had a chance to announce, we'd fail to send its goodbye packet (which would be a bug).
-#define InitialAnnounceCount ((mDNSu8)10)
-#define ReannounceCount      ((mDNSu8)9)
-
-// Note that the announce intervals use exponential backoff, doubling each time. The probe intervals do not.
-// This means that because the announce interval is doubled after sending the first packet, the first
-// observed on-the-wire inter-packet interval between announcements is actually one second.
-// The half-second value here may be thought of as a conceptual (non-existent) half-second delay *before* the first packet is sent.
-#define DefaultProbeIntervalForTypeUnique (mDNSPlatformOneSecond/4)
-#define DefaultAnnounceIntervalForTypeShared (mDNSPlatformOneSecond/2)
-#define DefaultAnnounceIntervalForTypeUnique (mDNSPlatformOneSecond/2)
-
-#define DefaultAPIntervalForRecordType(X)  ((X) & (kDNSRecordTypeAdvisory | kDNSRecordTypeShared     ) ? DefaultAnnounceIntervalForTypeShared : \
-                                                                                       (X) & (kDNSRecordTypeUnique                              ) ? DefaultProbeIntervalForTypeUnique    : \
-                                                                                       (X) & (kDNSRecordTypeVerified | kDNSRecordTypeKnownUnique) ? DefaultAnnounceIntervalForTypeUnique : 0)
-
-#define TimeToAnnounceThisRecord(RR,time) ((RR)->AnnounceCount && (time) - ((RR)->LastAPTime + (RR)->ThisAPInterval) >= 0)
-#define TimeToSendThisRecord(RR,time) ((TimeToAnnounceThisRecord(RR,time) || (RR)->ImmedAnswer) && ResourceRecordIsValidAnswer(RR))
-#define TicksTTL(RR) ((mDNSs32)(RR)->resrec.rroriginalttl * mDNSPlatformOneSecond)
-#define RRExpireTime(RR) ((RR)->TimeRcvd + TicksTTL(RR))
-
-#define MaxUnansweredQueries 4
-
-mDNSlocal mDNSBool SameRData(const ResourceRecord *const r1, const ResourceRecord *const r2)
-       {
-       if (r1->rrtype     != r2->rrtype)   return(mDNSfalse);
-       if (r1->rdlength   != r2->rdlength) return(mDNSfalse);
-       if (r1->rdatahash  != r2->rdatahash) return(mDNSfalse);
-       if (r1->rdnamehash != r2->rdnamehash) return(mDNSfalse);
-       switch(r1->rrtype)
-               {
-               case kDNSType_CNAME:// Same as PTR
-               case kDNSType_PTR:      return(SameDomainName(&r1->rdata->u.name, &r2->rdata->u.name));
-
-               case kDNSType_SRV:      return(mDNSBool)(       r1->rdata->u.srv.priority          == r2->rdata->u.srv.priority          &&
-                                                                                               r1->rdata->u.srv.weight            == r2->rdata->u.srv.weight            &&
-                                                                                               r1->rdata->u.srv.port.NotAnInteger == r2->rdata->u.srv.port.NotAnInteger &&
-                                                                                               SameDomainName(&r1->rdata->u.srv.target, &r2->rdata->u.srv.target)       );
-
-               default:                        return(mDNSPlatformMemSame(r1->rdata->u.data, r2->rdata->u.data, r1->rdlength));
-               }
-       }
-
-mDNSlocal mDNSBool ResourceRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q)
-       {
-       if (rr->InterfaceID &&
-               q ->InterfaceID &&
-               rr->InterfaceID != q->InterfaceID) return(mDNSfalse);
-
-       // RR type CNAME matches any query type. QTYPE ANY matches any RR type. QCLASS ANY matches any RR class.
-       if (rr->rrtype != kDNSType_CNAME && rr->rrtype  != q->qtype  && q->qtype  != kDNSQType_ANY ) return(mDNSfalse);
-       if (                                rr->rrclass != q->qclass && q->qclass != kDNSQClass_ANY) return(mDNSfalse);
-       return(rr->namehash == q->qnamehash && SameDomainName(&rr->name, &q->qname));
-       }
-
-mDNSlocal mDNSu32 DomainNameHashValue(const domainname *const name)
-       {
-       mDNSu32 sum = 0;
-       const mDNSu8 *c;
-
-       for (c = name->c; c[0] != 0 && c[1] != 0; c += 2)
-               {
-               sum += ((mDNSIsUpperCase(c[0]) ? c[0] + 'a' - 'A' : c[0]) << 8) |
-                               (mDNSIsUpperCase(c[1]) ? c[1] + 'a' - 'A' : c[1]);
-               sum = (sum<<3) | (sum>>29);
-               }
-       if (c[0]) sum += ((mDNSIsUpperCase(c[0]) ? c[0] + 'a' - 'A' : c[0]) << 8);
-       return(sum);
-       }
-
-#define HashSlot(X) (DomainNameHashValue(X) % CACHE_HASH_SLOTS)
-
-mDNSlocal mDNSu32 RDataHashValue(mDNSu16 const rdlength, const RDataBody *const rdb)
-       {
-       mDNSu32 sum = 0;
-       int i;
-       for (i=0; i+1 < rdlength; i+=2)
-               {
-               sum += (((mDNSu32)(rdb->data[i])) << 8) | rdb->data[i+1];
-               sum = (sum<<3) | (sum>>29);
-               }
-       if (i < rdlength)
-               {
-               sum += ((mDNSu32)(rdb->data[i])) << 8;
-               }
-       return(sum);
-       }
-
-// SameResourceRecordSignature returns true if two resources records have the same name, type, and class, and may be sent
-// (or were received) on the same interface (i.e. if *both* records specify an interface, then it has to match).
-// TTL and rdata may differ.
-// This is used for cache flush management:
-// When sending a unique record, all other records matching "SameResourceRecordSignature" must also be sent
-// When receiving a unique record, all old cache records matching "SameResourceRecordSignature" are flushed
-mDNSlocal mDNSBool SameResourceRecordSignature(const ResourceRecord *const r1, const ResourceRecord *const r2)
-       {
-       if (!r1) { LogMsg("SameResourceRecordSignature ERROR: r1 is NULL"); return(mDNSfalse); }
-       if (!r2) { LogMsg("SameResourceRecordSignature ERROR: r2 is NULL"); return(mDNSfalse); }
-       if (r1->InterfaceID &&
-               r2->InterfaceID &&
-               r1->InterfaceID != r2->InterfaceID) return(mDNSfalse);
-       return(mDNSBool)(r1->rrtype == r2->rrtype && r1->rrclass == r2->rrclass && r1->namehash == r2->namehash && SameDomainName(&r1->name, &r2->name));
-       }
-
-// PacketRRMatchesSignature behaves as SameResourceRecordSignature, except that types may differ if the
-// authoratative record is in the probing state.  Probes are sent with the wildcard type, so a response of
-// any type should match, even if it is not the type the client plans to use.
-mDNSlocal mDNSBool PacketRRMatchesSignature(const CacheRecord *const pktrr, const AuthRecord *const authrr)
-       {
-       if (!pktrr)  { LogMsg("PacketRRMatchesSignature ERROR: pktrr is NULL"); return(mDNSfalse); }
-       if (!authrr) { LogMsg("PacketRRMatchesSignature ERROR: authrr is NULL"); return(mDNSfalse); }
-       if (pktrr->resrec.InterfaceID &&
-               authrr->resrec.InterfaceID &&
-               pktrr->resrec.InterfaceID != authrr->resrec.InterfaceID) return(mDNSfalse);
-       if (authrr->resrec.RecordType != kDNSRecordTypeUnique && pktrr->resrec.rrtype != authrr->resrec.rrtype) return(mDNSfalse);
-       return(mDNSBool)(pktrr->resrec.rrclass == authrr->resrec.rrclass && pktrr->resrec.namehash == authrr->resrec.namehash && SameDomainName(&pktrr->resrec.name, &authrr->resrec.name));
-       }
-
-// IdenticalResourceRecord returns true if two resources records have
-// the same name, type, class, and identical rdata (InterfaceID and TTL may differ)
-mDNSlocal mDNSBool IdenticalResourceRecord(const ResourceRecord *const r1, const ResourceRecord *const r2)
-       {
-       if (!r1) { LogMsg("IdenticalResourceRecord ERROR: r1 is NULL"); return(mDNSfalse); }
-       if (!r2) { LogMsg("IdenticalResourceRecord ERROR: r2 is NULL"); return(mDNSfalse); }
-       if (r1->rrtype != r2->rrtype || r1->rrclass != r2->rrclass || r1->namehash != r2->namehash || !SameDomainName(&r1->name, &r2->name)) return(mDNSfalse);
-       return(SameRData(r1, r2));
-       }
-
-// CacheRecord *ks is the CacheRecord from the known answer list in the query.
-// This is the information that the requester believes to be correct.
-// AuthRecord *rr is the answer we are proposing to give, if not suppressed.
-// This is the information that we believe to be correct.
-// We've already determined that we plan to give this answer on this interface
-// (either the record is non-specific, or it is specific to this interface)
-// so now we just need to check the name, type, class, rdata and TTL.
-mDNSlocal mDNSBool ShouldSuppressKnownAnswer(const CacheRecord *const ka, const AuthRecord *const rr)
-       {
-       // If RR signature is different, or data is different, then don't suppress our answer
-       if (!IdenticalResourceRecord(&ka->resrec,&rr->resrec)) return(mDNSfalse);
-       
-       // If the requester's indicated TTL is less than half the real TTL,
-       // we need to give our answer before the requester's copy expires.
-       // If the requester's indicated TTL is at least half the real TTL,
-       // then we can suppress our answer this time.
-       // If the requester's indicated TTL is greater than the TTL we believe,
-       // then that's okay, and we don't need to do anything about it.
-       // (If two responders on the network are offering the same information,
-       // that's okay, and if they are offering the information with different TTLs,
-       // the one offering the lower TTL should defer to the one offering the higher TTL.)
-       return(mDNSBool)(ka->resrec.rroriginalttl >= rr->resrec.rroriginalttl / 2);
-       }
-
-mDNSlocal mDNSu16 GetRDLength(const ResourceRecord *const rr, mDNSBool estimate)
-       {
-       RDataBody *rd = &rr->rdata->u;
-       const domainname *const name = estimate ? &rr->name : mDNSNULL;
-       switch (rr->rrtype)
-               {
-               case kDNSType_A:        return(sizeof(rd->ip));
-               case kDNSType_CNAME:// Same as PTR
-               case kDNSType_PTR:      return(CompressedDomainNameLength(&rd->name, name));
-               case kDNSType_HINFO:return(mDNSu16)(2 + (int)rd->data[0] + (int)rd->data[1 + (int)rd->data[0]]);
-               case kDNSType_NULL:     // Same as TXT -- not self-describing, so have to just trust rdlength
-               case kDNSType_TXT:  return(rr->rdlength); // TXT is not self-describing, so have to just trust rdlength
-               case kDNSType_AAAA:     return(sizeof(rd->ipv6));
-               case kDNSType_SRV:      return(mDNSu16)(6 + CompressedDomainNameLength(&rd->srv.target, name));
-               default:                        debugf("Warning! Don't know how to get length of resource type %d", rr->rrtype);
-                                                       return(rr->rdlength);
-               }
-       }
-
-mDNSlocal void SetNextAnnounceProbeTime(mDNS *const m, const AuthRecord *const rr)
-       {
-       if (rr->resrec.RecordType == kDNSRecordTypeUnique)
-               {
-               if (m->NextScheduledProbe - (rr->LastAPTime + rr->ThisAPInterval) >= 0)
-                       m->NextScheduledProbe = (rr->LastAPTime + rr->ThisAPInterval);
+               //LogMsg("ProbeCount %d Next %ld %s", rr->ProbeCount, (rr->LastAPTime + rr->ThisAPInterval) - m->timenow, GetRRDisplayString(m, rr));
+               if (m->NextScheduledProbe - (rr->LastAPTime + rr->ThisAPInterval) >= 0)
+                       m->NextScheduledProbe = (rr->LastAPTime + rr->ThisAPInterval);
                }
        else if (rr->AnnounceCount && ResourceRecordIsValidAnswer(rr))
                {
@@ -2269,10 +1752,6 @@ mDNSlocal void SetNextAnnounceProbeTime(mDNS *const m, const AuthRecord *const r
                }
        }
 
-#define GetRRDomainNameTarget(RR) (                                                                          \
-       ((RR)->rrtype == kDNSType_CNAME || (RR)->rrtype == kDNSType_PTR) ? &(RR)->rdata->u.name       :          \
-       ((RR)->rrtype == kDNSType_SRV                                  ) ? &(RR)->rdata->u.srv.target : mDNSNULL )
-
 mDNSlocal void InitializeLastAPTime(mDNS *const m, AuthRecord *const rr)
        {
        // To allow us to aggregate probes when a group of services are registered together,
@@ -2317,21 +1796,7 @@ mDNSlocal void InitializeLastAPTime(mDNS *const m, AuthRecord *const rr)
        SetNextAnnounceProbeTime(m, rr);
        }
 
-mDNSlocal void SetNewRData(ResourceRecord *const rr, RData *NewRData, mDNSu16 rdlength)
-       {
-       domainname *target;
-       if (NewRData)
-               {
-               rr->rdata    = NewRData;
-               rr->rdlength = rdlength;
-               }
-       // Must not try to get target pointer until after updating rr->rdata
-       target = GetRRDomainNameTarget(rr);
-       rr->rdlength   = GetRDLength(rr, mDNSfalse);
-       rr->rdestimate = GetRDLength(rr, mDNStrue);
-       rr->rdatahash  = RDataHashValue(rr->rdlength, &rr->rdata->u);
-       rr->rdnamehash = target ? DomainNameHashValue(target) : 0;
-       }
+#define HashSlot(X) (DomainNameHashValue(X) % CACHE_HASH_SLOTS)
 
 mDNSlocal void SetTargetToHostName(mDNS *const m, AuthRecord *const rr)
        {
@@ -2379,49 +1844,6 @@ mDNSlocal void CompleteProbing(mDNS *const m, AuthRecord *const rr)
                }
        }
 
-#define ValidateDomainName(N) (DomainNameLength(N) <= MAX_DOMAIN_NAME)
-
-mDNSlocal mDNSBool ValidateRData(const mDNSu16 rrtype, const mDNSu16 rdlength, const RData *const rd)
-       {
-       mDNSu16 len;
-       switch(rrtype)
-               {
-               case kDNSType_A:        return(rdlength == sizeof(mDNSv4Addr));
-
-               case kDNSType_NS:       // Same as PTR
-               case kDNSType_MD:       // Same as PTR
-               case kDNSType_MF:       // Same as PTR
-               case kDNSType_CNAME:// Same as PTR
-               //case kDNSType_SOA not checked
-               case kDNSType_MB:       // Same as PTR
-               case kDNSType_MG:       // Same as PTR
-               case kDNSType_MR:       // Same as PTR
-               //case kDNSType_NULL not checked (no specified format, so always valid)
-               //case kDNSType_WKS not checked
-               case kDNSType_PTR:      len = DomainNameLength(&rd->u.name);
-                                                       return(len <= MAX_DOMAIN_NAME && rdlength == len);
-
-               case kDNSType_HINFO:// Same as TXT (roughly)
-               case kDNSType_MINFO:// Same as TXT (roughly)
-               case kDNSType_TXT:  {
-                                                       const mDNSu8 *ptr = rd->u.txt.c;
-                                                       const mDNSu8 *end = rd->u.txt.c + rdlength;
-                                                       while (ptr < end) ptr += 1 + ptr[0];
-                                                       return (ptr == end);
-                                                       }
-
-               case kDNSType_AAAA:     return(rdlength == sizeof(mDNSv6Addr));
-
-               case kDNSType_MX:   len = DomainNameLength(&rd->u.mx.exchange);
-                                                       return(len <= MAX_DOMAIN_NAME && rdlength == 2+len);
-
-               case kDNSType_SRV:      len = DomainNameLength(&rd->u.srv.target);
-                                                       return(len <= MAX_DOMAIN_NAME && rdlength == 6+len);
-
-               default:                        return(mDNStrue);       // Allow all other types without checking
-               }
-       }
-
 // Two records qualify to be local duplicates if the RecordTypes are the same, or if one is Unique and the other Verified
 #define RecordLDT(A,B) ((A)->resrec.RecordType == (B)->resrec.RecordType || ((A)->resrec.RecordType | (B)->resrec.RecordType) == (kDNSRecordTypeUnique | kDNSRecordTypeVerified))
 #define RecordIsLocalDuplicate(A,B) ((A)->resrec.InterfaceID == (B)->resrec.InterfaceID && RecordLDT((A),(B)) && IdenticalResourceRecord(&(A)->resrec, &(B)->resrec))
@@ -2435,9 +1857,15 @@ mDNSlocal mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr)
        AuthRecord **l = &m->LocalOnlyRecords;
        
 #if TEST_LOCALONLY_FOR_EVERYTHING
-       rr->resrec.InterfaceID = (mDNSInterfaceID)~0;
+       rr->resrec.InterfaceID = mDNSInterface_LocalOnly;
 #endif
 
+       // If the client has specified an explicit InterfaceID,
+       // then we do a multicast registration  on that interface, even for unicast domains.
+    if (rr->resrec.InterfaceID || IsLocalDomain(&rr->resrec.name))
+       rr->uDNS_info.id = zeroID;
+    else return uDNS_RegisterRecord(m, rr);
+
        while (*p && *p != rr) p=&(*p)->next;
        while (*d && *d != rr) d=&(*d)->next;
        while (*l && *l != rr) l=&(*l)->next;
@@ -2466,7 +1894,7 @@ mDNSlocal mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr)
                }
 
        // If this resource record is referencing a specific interface, make sure it exists
-       if (rr->resrec.InterfaceID && rr->resrec.InterfaceID != ((mDNSInterfaceID)~0))
+       if (rr->resrec.InterfaceID && rr->resrec.InterfaceID != mDNSInterface_LocalOnly)
                {
                NetworkInterfaceInfo *intf;
                for (intf = m->HostInterfaces; intf; intf = intf->next)
@@ -2489,6 +1917,8 @@ mDNSlocal mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr)
 //     rr->Context           = already set in mDNS_SetupResourceRecord
 //     rr->RecordType        = already set in mDNS_SetupResourceRecord
 //     rr->HostTarget        = set to mDNSfalse in mDNS_SetupResourceRecord; may be overridden by client
+       // Make sure target is not uninitialized data, or we may crash writing debugging log messages
+       if (rr->HostTarget && target) target->c[0] = 0;
 
        // Field Group 2: Transient state for Authoritative Records
        rr->Acknowledged      = mDNSfalse;
@@ -2504,7 +1934,7 @@ mDNSlocal mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr)
        rr->NR_AnswerTo       = mDNSNULL;
        rr->NR_AdditionalTo   = mDNSNULL;
        rr->ThisAPInterval    = DefaultAPIntervalForRecordType(rr->resrec.RecordType);
-       InitializeLastAPTime(m, rr);
+       if (!rr->HostTarget) InitializeLastAPTime(m, rr);
 //     rr->AnnounceUntil     = Set for us in InitializeLastAPTime()
 //     rr->LastAPTime        = Set for us in InitializeLastAPTime()
 //     rr->LastMCTime        = Set for us in InitializeLastAPTime()
@@ -2524,10 +1954,7 @@ mDNSlocal mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr)
 //     rr->resrec.rdata             = MUST be set by client, unless record type is CNAME or PTR and rr->HostTarget is set
 
        if (rr->HostTarget)
-               {
-               if (target) target->c[0] = 0;
-               SetTargetToHostName(m, rr);     // This also sets rdlength and rdestimate for us
-               }
+               SetTargetToHostName(m, rr);     // Also sets rdlength and rdestimate for us, and calls InitializeLastAPTime();
        else
                {
                rr->resrec.rdlength   = GetRDLength(&rr->resrec, mDNSfalse);
@@ -2545,7 +1972,7 @@ mDNSlocal mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr)
        rr->resrec.rdatahash  = RDataHashValue(rr->resrec.rdlength, &rr->resrec.rdata->u);
        rr->resrec.rdnamehash = target ? DomainNameHashValue(target) : 0;
        
-       if (rr->resrec.InterfaceID == ((mDNSInterfaceID)~0))
+       if (rr->resrec.InterfaceID == mDNSInterface_LocalOnly)
                {
                debugf("Adding %p %##s (%s) to LocalOnly list", rr, rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype));
                *l = rr;
@@ -2603,10 +2030,21 @@ mDNSlocal void RecordProbeFailure(mDNS *const m, const AuthRecord *const rr)
        m->NumFailedProbes++;
        // If we've had ten or more probe failures, rate-limit to one every five seconds
        // The result is ORed with 1 to make sure SuppressProbes is not accidentally set to zero
-       if (m->NumFailedProbes >= 10) m->SuppressProbes = (m->timenow + mDNSPlatformOneSecond * 5) | 1;
-       if (m->NumFailedProbes >= 16)
-               LogMsg("Name in use: %##s (%s); need to choose another (%d)",
-                       rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype), m->NumFailedProbes);
+       if (m->NumFailedProbes >= 10)
+               {
+               m->SuppressProbes = (m->timenow + mDNSPlatformOneSecond * 5) | 1;
+               LogMsg("Excessive name conflicts (%d) for %##s (%s); rate limiting in effect",
+                       m->NumFailedProbes, rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype));
+               }
+       }
+
+mDNSlocal void CompleteRDataUpdate(mDNS *const m, AuthRecord *const rr)
+       {
+       RData *OldRData = rr->resrec.rdata;
+       SetNewRData(&rr->resrec, rr->NewRData, rr->newrdlength);        // Update our rdata
+       rr->NewRData = mDNSNULL;                                                                        // Clear the NewRData pointer ...
+       if (rr->UpdateCallback)
+               rr->UpdateCallback(m, rr, OldRData);                                    // ... and let the client know
        }
 
 // mDNS_Dereg_normal is used for most calls to mDNS_Deregister_internal
@@ -2620,7 +2058,11 @@ mDNSlocal mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr,
        {
        mDNSu8 RecordType = rr->resrec.RecordType;
        AuthRecord **p = &m->ResourceRecords;   // Find this record in our list of active records
-       if (rr->resrec.InterfaceID == ((mDNSInterfaceID)~0)) p = &m->LocalOnlyRecords;
+
+    if (!rr->resrec.InterfaceID && !IsLocalDomain(&rr->resrec.name) && rr->uDNS_info.id.NotAnInteger)
+               return uDNS_DeregisterRecord(m, rr);
+       
+       if (rr->resrec.InterfaceID == mDNSInterface_LocalOnly) p = &m->LocalOnlyRecords;
        while (*p && *p != rr) p=&(*p)->next;
 
        if (*p)
@@ -2690,565 +2132,60 @@ mDNSlocal mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr,
                rr->resrec.RecordType    = kDNSRecordTypeDeregistering;
                rr->resrec.rroriginalttl = 0;
                rr->ImmedAnswer          = mDNSInterfaceMark;
-               if (rr->resrec.InterfaceID == ((mDNSInterfaceID)~0))
+               if (rr->resrec.InterfaceID == mDNSInterface_LocalOnly)
                        m->DiscardLocalOnlyRecords = mDNStrue;
                else
                        {
                        if (m->NextScheduledResponse - (m->timenow + mDNSPlatformOneSecond/10) >= 0)
                                m->NextScheduledResponse = (m->timenow + mDNSPlatformOneSecond/10);
-                       }
-               }
-       else
-               {
-               *p = rr->next;                                  // Cut this record from the list
-               // If someone is about to look at this, bump the pointer forward
-               if (m->CurrentRecord       == rr) m->CurrentRecord       = rr->next;
-               if (m->NewLocalOnlyRecords == rr) m->NewLocalOnlyRecords = rr->next;
-               rr->next = mDNSNULL;
-
-               if      (RecordType == kDNSRecordTypeUnregistered)
-                       debugf("mDNS_Deregister_internal: Record %##s (%s) already marked kDNSRecordTypeUnregistered",
-                               rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype));
-               else if (RecordType == kDNSRecordTypeDeregistering)
-                       debugf("mDNS_Deregister_internal: Record %##s (%s) already marked kDNSRecordTypeDeregistering",
-                               rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype));
-               else
-                       {
-                       verbosedebugf("mDNS_Deregister_internal: Deleting record for %##s (%s)", rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype));
-                       rr->resrec.RecordType = kDNSRecordTypeUnregistered;
-                       }
-
-               if ((drt == mDNS_Dereg_conflict || drt == mDNS_Dereg_repeat) && RecordType == kDNSRecordTypeShared)
-                       debugf("mDNS_Deregister_internal: Cannot have a conflict on a shared record! %##s (%s)",
-                               rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype));
-
-               // If we have an update queued up which never executed, give the client a chance to free that memory
-               if (rr->NewRData)
-                       {
-                       RData *OldRData = rr->resrec.rdata;
-                       SetNewRData(&rr->resrec, rr->NewRData, rr->newrdlength);        // Update our rdata
-                       rr->NewRData = mDNSNULL;                                                                        // Clear the NewRData pointer ...
-                       if (rr->UpdateCallback)
-                               rr->UpdateCallback(m, rr, OldRData);                                    // ... and let the client know
-                       }
-               
-               // CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function
-               // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc.
-               // In this case the likely client action to the mStatus_MemFree message is to free the memory,
-               // so any attempt to touch rr after this is likely to lead to a crash.
-               m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
-               if (RecordType == kDNSRecordTypeShared)
-                       {
-                       if (rr->RecordCallback)
-                               rr->RecordCallback(m, rr, mStatus_MemFree);
-                       }
-               else if (drt == mDNS_Dereg_conflict)
-                       {
-                       RecordProbeFailure(m, rr);
-                       if (rr->RecordCallback)
-                               rr->RecordCallback(m, rr, mStatus_NameConflict);
-                       }
-               m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
-               }
-       return(mStatus_NoError);
-       }
-
-// ***************************************************************************
-#if COMPILER_LIKES_PRAGMA_MARK
-#pragma mark -
-#pragma mark -
-#pragma mark - DNS Message Creation Functions
-#endif
-
-mDNSlocal void InitializeDNSMessage(DNSMessageHeader *h, mDNSOpaque16 id, mDNSOpaque16 flags)
-       {
-       h->id             = id;
-       h->flags          = flags;
-       h->numQuestions   = 0;
-       h->numAnswers     = 0;
-       h->numAuthorities = 0;
-       h->numAdditionals = 0;
-       }
-
-mDNSlocal const mDNSu8 *FindCompressionPointer(const mDNSu8 *const base, const mDNSu8 *const end, const mDNSu8 *const domname)
-       {
-       const mDNSu8 *result = end - *domname - 1;
-
-       if (*domname == 0) return(mDNSNULL);    // There's no point trying to match just the root label
-       
-       // This loop examines each possible starting position in packet, starting end of the packet and working backwards
-       while (result >= base)
-               {
-               // If the length byte and first character of the label match, then check further to see
-               // if this location in the packet will yield a useful name compression pointer.
-               if (result[0] == domname[0] && result[1] == domname[1])
-                       {
-                       const mDNSu8 *name = domname;
-                       const mDNSu8 *targ = result;
-                       while (targ + *name < end)
-                               {
-                               // First see if this label matches
-                               int i;
-                               const mDNSu8 *pointertarget;
-                               for (i=0; i <= *name; i++) if (targ[i] != name[i]) break;
-                               if (i <= *name) break;                                                  // If label did not match, bail out
-                               targ += 1 + *name;                                                              // Else, did match, so advance target pointer
-                               name += 1 + *name;                                                              // and proceed to check next label
-                               if (*name == 0 && *targ == 0) return(result);   // If no more labels, we found a match!
-                               if (*name == 0) break;                                                  // If no more labels to match, we failed, so bail out
-
-                               // The label matched, so now follow the pointer (if appropriate) and then see if the next label matches
-                               if (targ[0] < 0x40) continue;                                   // If length value, continue to check next label
-                               if (targ[0] < 0xC0) break;                                              // If 40-BF, not valid
-                               if (targ+1 >= end) break;                                               // Second byte not present!
-                               pointertarget = base + (((mDNSu16)(targ[0] & 0x3F)) << 8) + targ[1];
-                               if (targ < pointertarget) break;                                // Pointertarget must point *backwards* in the packet
-                               if (pointertarget[0] >= 0x40) break;                    // Pointertarget must point to a valid length byte
-                               targ = pointertarget;
-                               }
-                       }
-               result--;       // We failed to match at this search position, so back up the tentative result pointer and try again
-               }
-       return(mDNSNULL);
-       }
-
-// Put a string of dot-separated labels as length-prefixed labels
-// domainname is a fully-qualified name (i.e. assumed to be ending in a dot, even if it doesn't)
-// msg points to the message we're building (pass mDNSNULL if we don't want to use compression pointers)
-// end points to the end of the message so far
-// ptr points to where we want to put the name
-// limit points to one byte past the end of the buffer that we must not overrun
-// domainname is the name to put
-mDNSlocal mDNSu8 *putDomainNameAsLabels(const DNSMessage *const msg,
-       mDNSu8 *ptr, const mDNSu8 *const limit, const domainname *const name)
-       {
-       const mDNSu8 *const base        = (const mDNSu8 *)msg;
-       const mDNSu8 *      np          = name->c;
-       const mDNSu8 *const max         = name->c + MAX_DOMAIN_NAME;    // Maximum that's valid
-       const mDNSu8 *      pointer     = mDNSNULL;
-       const mDNSu8 *const searchlimit = ptr;
-
-       while (*np && ptr < limit-1)            // While we've got characters in the name, and space to write them in the message...
-               {
-               if (*np > MAX_DOMAIN_LABEL)
-                       { LogMsg("Malformed domain name %##s (label more than 63 bytes)", name->c); return(mDNSNULL); }
-               
-               // This check correctly allows for the final trailing root label:
-               // e.g.
-               // Suppose our domain name is exactly 255 bytes long, including the final trailing root label.
-               // Suppose np is now at name->c[248], and we're about to write our last non-null label ("local").
-               // We know that max will be at name->c[255]
-               // That means that np + 1 + 5 == max - 1, so we (just) pass the "if" test below, write our
-               // six bytes, then exit the loop, write the final terminating root label, and the domain
-               // name we've written is exactly 255 bytes long, exactly at the correct legal limit.
-               // If the name is one byte longer, then we fail the "if" test below, and correctly bail out.
-               if (np + 1 + *np >= max)
-                       { LogMsg("Malformed domain name %##s (more than 255 bytes)", name->c); return(mDNSNULL); }
-
-               if (base) pointer = FindCompressionPointer(base, searchlimit, np);
-               if (pointer)                                    // Use a compression pointer if we can
-                       {
-                       mDNSu16 offset = (mDNSu16)(pointer - base);
-                       *ptr++ = (mDNSu8)(0xC0 | (offset >> 8));
-                       *ptr++ = (mDNSu8)(        offset      );
-                       return(ptr);
-                       }
-               else                                                    // Else copy one label and try again
-                       {
-                       int i;
-                       mDNSu8 len = *np++;
-                       if (ptr + 1 + len >= limit) return(mDNSNULL);
-                       *ptr++ = len;
-                       for (i=0; i<len; i++) *ptr++ = *np++;
-                       }
-               }
-
-       if (ptr < limit)                                                                                                // If we didn't run out of space
-               {
-               *ptr++ = 0;                                                                                                     // Put the final root label
-               return(ptr);                                                                                            // and return
-               }
-
-       return(mDNSNULL);
-       }
-
-mDNSlocal mDNSu8 *putRData(const DNSMessage *const msg, mDNSu8 *ptr, const mDNSu8 *const limit, ResourceRecord *rr)
-       {
-       switch (rr->rrtype)
-               {
-               case kDNSType_A:        if (rr->rdlength != 4)
-                                                               {
-                                                               debugf("putRData: Illegal length %d for kDNSType_A", rr->rdlength);
-                                                               return(mDNSNULL);
-                                                               }
-                                                       if (ptr + 4 > limit) return(mDNSNULL);
-                                                       *ptr++ = rr->rdata->u.ip.b[0];
-                                                       *ptr++ = rr->rdata->u.ip.b[1];
-                                                       *ptr++ = rr->rdata->u.ip.b[2];
-                                                       *ptr++ = rr->rdata->u.ip.b[3];
-                                                       return(ptr);
-
-               case kDNSType_CNAME:// Same as PTR
-               case kDNSType_PTR:      return(putDomainNameAsLabels(msg, ptr, limit, &rr->rdata->u.name));
-
-               case kDNSType_HINFO:// Same as TXT
-               case kDNSType_TXT:  if (ptr + rr->rdlength > limit) return(mDNSNULL);
-                                                       mDNSPlatformMemCopy(rr->rdata->u.data, ptr, rr->rdlength);
-                                                       return(ptr + rr->rdlength);
-
-               case kDNSType_AAAA:     if (rr->rdlength != sizeof(rr->rdata->u.ipv6))
-                                                               {
-                                                               debugf("putRData: Illegal length %d for kDNSType_AAAA", rr->rdlength);
-                                                               return(mDNSNULL);
-                                                               }
-                                                       if (ptr + sizeof(rr->rdata->u.ipv6) > limit) return(mDNSNULL);
-                                                       mDNSPlatformMemCopy(&rr->rdata->u.ipv6, ptr, sizeof(rr->rdata->u.ipv6));
-                                                       return(ptr + sizeof(rr->rdata->u.ipv6));
-
-               case kDNSType_SRV:      if (ptr + 6 > limit) return(mDNSNULL);
-                                                       *ptr++ = (mDNSu8)(rr->rdata->u.srv.priority >> 8);
-                                                       *ptr++ = (mDNSu8)(rr->rdata->u.srv.priority     );
-                                                       *ptr++ = (mDNSu8)(rr->rdata->u.srv.weight   >> 8);
-                                                       *ptr++ = (mDNSu8)(rr->rdata->u.srv.weight       );
-                                                       *ptr++ = rr->rdata->u.srv.port.b[0];
-                                                       *ptr++ = rr->rdata->u.srv.port.b[1];
-                                                       return(putDomainNameAsLabels(msg, ptr, limit, &rr->rdata->u.srv.target));
-
-               default:                        if (ptr + rr->rdlength > limit) return(mDNSNULL);
-                                                       debugf("putRData: Warning! Writing resource type %d as raw data", rr->rrtype);
-                                                       mDNSPlatformMemCopy(rr->rdata->u.data, ptr, rr->rdlength);
-                                                       return(ptr + rr->rdlength);
-               }
-       }
-
-mDNSlocal mDNSu8 *PutResourceRecordTTL(DNSMessage *const msg, mDNSu8 *ptr, mDNSu16 *count, ResourceRecord *rr, mDNSu32 ttl)
-       {
-       mDNSu8 *endofrdata;
-       mDNSu16 actualLength;
-       const mDNSu8 *limit = msg->data + AbsoluteMaxDNSMessageData;
-       
-       // If we have a single large record to put in the packet, then we allow the packet to be up to 9K bytes,
-       // but in the normal case we try to keep the packets below 1500 to avoid IP fragmentation on standard Ethernet
-       if (msg->h.numAnswers || msg->h.numAuthorities || msg->h.numAdditionals)
-               limit = msg->data + NormalMaxDNSMessageData;
-
-       if (rr->RecordType == kDNSRecordTypeUnregistered)
-               {
-               LogMsg("PutResourceRecord ERROR! Attempt to put kDNSRecordTypeUnregistered %##s (%s)", rr->name.c, DNSTypeName(rr->rrtype));
-               return(ptr);
-               }
-
-       ptr = putDomainNameAsLabels(msg, ptr, limit, &rr->name);
-       if (!ptr || ptr + 10 >= limit) return(mDNSNULL);        // If we're out-of-space, return mDNSNULL
-       ptr[0] = (mDNSu8)(rr->rrtype  >> 8);
-       ptr[1] = (mDNSu8)(rr->rrtype      );
-       ptr[2] = (mDNSu8)(rr->rrclass >> 8);
-       ptr[3] = (mDNSu8)(rr->rrclass     );
-       ptr[4] = (mDNSu8)(ttl >> 24);
-       ptr[5] = (mDNSu8)(ttl >> 16);
-       ptr[6] = (mDNSu8)(ttl >>  8);
-       ptr[7] = (mDNSu8)(ttl      );
-       endofrdata = putRData(msg, ptr+10, limit, rr);
-       if (!endofrdata) { verbosedebugf("Ran out of space in PutResourceRecord for %##s (%s)", rr->name.c, DNSTypeName(rr->rrtype)); return(mDNSNULL); }
-
-       // Go back and fill in the actual number of data bytes we wrote
-       // (actualLength can be less than rdlength when domain name compression is used)
-       actualLength = (mDNSu16)(endofrdata - ptr - 10);
-       ptr[8] = (mDNSu8)(actualLength >> 8);
-       ptr[9] = (mDNSu8)(actualLength     );
-
-       (*count)++;
-       return(endofrdata);
-       }
-
-#define PutResourceRecord(MSG, P, C, RR) PutResourceRecordTTL((MSG), (P), (C), (RR), (RR)->rroriginalttl)
-
-mDNSlocal mDNSu8 *PutResourceRecordCappedTTL(DNSMessage *const msg, mDNSu8 *ptr, mDNSu16 *count, ResourceRecord *rr, mDNSu32 maxttl)
-       {
-       if (maxttl > rr->rroriginalttl) maxttl = rr->rroriginalttl;
-       return(PutResourceRecordTTL(msg, ptr, count, rr, maxttl));
-       }
-
-#if 0
-mDNSlocal mDNSu8 *putEmptyResourceRecord(DNSMessage *const msg, mDNSu8 *ptr, const mDNSu8 *const limit,
-       mDNSu16 *count, const AuthRecord *rr)
-       {
-       ptr = putDomainNameAsLabels(msg, ptr, limit, &rr->name);
-       if (!ptr || ptr + 10 > limit) return(mDNSNULL);         // If we're out-of-space, return mDNSNULL
-       ptr[0] = (mDNSu8)(rr->resrec.rrtype  >> 8);                             // Put type
-       ptr[1] = (mDNSu8)(rr->resrec.rrtype      );
-       ptr[2] = (mDNSu8)(rr->resrec.rrclass >> 8);                             // Put class
-       ptr[3] = (mDNSu8)(rr->resrec.rrclass     );
-       ptr[4] = ptr[5] = ptr[6] = ptr[7] = 0;                          // TTL is zero
-       ptr[8] = ptr[9] = 0;                                                            // RDATA length is zero
-       (*count)++;
-       return(ptr + 10);
-       }
-#endif
-
-mDNSlocal mDNSu8 *putQuestion(DNSMessage *const msg, mDNSu8 *ptr, const mDNSu8 *const limit,
-                                                       const domainname *const name, mDNSu16 rrtype, mDNSu16 rrclass)
-       {
-       ptr = putDomainNameAsLabels(msg, ptr, limit, name);
-       if (!ptr || ptr+4 >= limit) return(mDNSNULL);                   // If we're out-of-space, return mDNSNULL
-       ptr[0] = (mDNSu8)(rrtype  >> 8);
-       ptr[1] = (mDNSu8)(rrtype      );
-       ptr[2] = (mDNSu8)(rrclass >> 8);
-       ptr[3] = (mDNSu8)(rrclass     );
-       msg->h.numQuestions++;
-       return(ptr+4);
-       }
-
-// ***************************************************************************
-#if COMPILER_LIKES_PRAGMA_MARK
-#pragma mark -
-#pragma mark - DNS Message Parsing Functions
-#endif
-
-mDNSlocal const mDNSu8 *skipDomainName(const DNSMessage *const msg, const mDNSu8 *ptr, const mDNSu8 *const end)
-       {
-       mDNSu16 total = 0;
-
-       if (ptr < (mDNSu8*)msg || ptr >= end)
-               { debugf("skipDomainName: Illegal ptr not within packet boundaries"); return(mDNSNULL); }
-
-       while (1)                                               // Read sequence of labels
-               {
-               const mDNSu8 len = *ptr++;      // Read length of this label
-               if (len == 0) return(ptr);      // If length is zero, that means this name is complete
-               switch (len & 0xC0)
-                       {
-                       case 0x00:      if (ptr + len >= end)                                   // Remember: expect at least one more byte for the root label
-                                                       { debugf("skipDomainName: Malformed domain name (overruns packet end)"); return(mDNSNULL); }
-                                               if (total + 1 + len >= MAX_DOMAIN_NAME) // Remember: expect at least one more byte for the root label
-                                                       { debugf("skipDomainName: Malformed domain name (more than 255 characters)"); return(mDNSNULL); }
-                                               ptr += len;
-                                               total += 1 + len;
-                                               break;
-
-                       case 0x40:      debugf("skipDomainName: Extended EDNS0 label types 0x%X not supported", len); return(mDNSNULL);
-                       case 0x80:      debugf("skipDomainName: Illegal label length 0x%X", len); return(mDNSNULL);
-                       case 0xC0:      return(ptr+1);
-                       }
-               }
-       }
-
-// Routine to fetch an FQDN from the DNS message, following compression pointers if necessary.
-mDNSlocal const mDNSu8 *getDomainName(const DNSMessage *const msg, const mDNSu8 *ptr, const mDNSu8 *const end,
-       domainname *const name)
-       {
-       const mDNSu8 *nextbyte = mDNSNULL;                                      // Record where we got to before we started following pointers
-       mDNSu8       *np = name->c;                                                     // Name pointer
-       const mDNSu8 *const limit = np + MAX_DOMAIN_NAME;       // Limit so we don't overrun buffer
-
-       if (ptr < (mDNSu8*)msg || ptr >= end)
-               { debugf("getDomainName: Illegal ptr not within packet boundaries"); return(mDNSNULL); }
-
-       *np = 0;                                                // Tentatively place the root label here (may be overwritten if we have more labels)
-
-       while (1)                                               // Read sequence of labels
-               {
-               const mDNSu8 len = *ptr++;      // Read length of this label
-               if (len == 0) break;            // If length is zero, that means this name is complete
-               switch (len & 0xC0)
-                       {
-                       int i;
-                       mDNSu16 offset;
-
-                       case 0x00:      if (ptr + len >= end)           // Remember: expect at least one more byte for the root label
-                                                       { debugf("getDomainName: Malformed domain name (overruns packet end)"); return(mDNSNULL); }
-                                               if (np + 1 + len >= limit)      // Remember: expect at least one more byte for the root label
-                                                       { debugf("getDomainName: Malformed domain name (more than 255 characters)"); return(mDNSNULL); }
-                                               *np++ = len;
-                                               for (i=0; i<len; i++) *np++ = *ptr++;
-                                               *np = 0;        // Tentatively place the root label here (may be overwritten if we have more labels)
-                                               break;
-
-                       case 0x40:      debugf("getDomainName: Extended EDNS0 label types 0x%X not supported in name %##s", len, name->c);
-                                               return(mDNSNULL);
-
-                       case 0x80:      debugf("getDomainName: Illegal label length 0x%X in domain name %##s", len, name->c); return(mDNSNULL);
-
-                       case 0xC0:      offset = (mDNSu16)((((mDNSu16)(len & 0x3F)) << 8) | *ptr++);
-                                               if (!nextbyte) nextbyte = ptr;  // Record where we got to before we started following pointers
-                                               ptr = (mDNSu8 *)msg + offset;
-                                               if (ptr < (mDNSu8*)msg || ptr >= end)
-                                                       { debugf("getDomainName: Illegal compression pointer not within packet boundaries"); return(mDNSNULL); }
-                                               if (*ptr & 0xC0)
-                                                       { debugf("getDomainName: Compression pointer must point to real label"); return(mDNSNULL); }
-                                               break;
-                       }
-               }
-       
-       if (nextbyte) return(nextbyte);
-       else return(ptr);
-       }
-
-mDNSlocal const mDNSu8 *skipResourceRecord(const DNSMessage *msg, const mDNSu8 *ptr, const mDNSu8 *end)
-       {
-       mDNSu16 pktrdlength;
-
-       ptr = skipDomainName(msg, ptr, end);
-       if (!ptr) { debugf("skipResourceRecord: Malformed RR name"); return(mDNSNULL); }
-       
-       if (ptr + 10 > end) { debugf("skipResourceRecord: Malformed RR -- no type/class/ttl/len!"); return(mDNSNULL); }
-       pktrdlength = (mDNSu16)((mDNSu16)ptr[8] <<  8 | ptr[9]);
-       ptr += 10;
-       if (ptr + pktrdlength > end) { debugf("skipResourceRecord: RDATA exceeds end of packet"); return(mDNSNULL); }
-
-       return(ptr + pktrdlength);
-       }
-
-#define GetLargeResourceRecord(m, msg, p, e, i, t, L) \
-       (((L)->r.rdatastorage.MaxRDLength = MaximumRDSize), GetResourceRecord((m), (msg), (p), (e), (i), (t), &(L)->r, (RData*)&(L)->r.rdatastorage))
-
-mDNSlocal const mDNSu8 *GetResourceRecord(mDNS *const m, const DNSMessage *msg, const mDNSu8 *ptr, const mDNSu8 *end,
-       const mDNSInterfaceID InterfaceID, mDNSu8 RecordType, CacheRecord *rr, RData *RDataStorage)
-       {
-       mDNSu16 pktrdlength;
-
-       rr->next              = mDNSNULL;
-       rr->resrec.RecordType        = RecordType;
-
-       rr->NextInKAList      = mDNSNULL;
-       rr->TimeRcvd          = m->timenow;
-       rr->NextRequiredQuery = m->timenow;             // Will be updated to the real value when we call SetNextCacheCheckTime()
-       rr->LastUsed          = m->timenow;
-       rr->UseCount          = 0;
-       rr->CRActiveQuestion  = mDNSNULL;
-       rr->UnansweredQueries = 0;
-       rr->LastUnansweredTime= 0;
-       rr->MPUnansweredQ     = 0;
-       rr->MPLastUnansweredQT= 0;
-       rr->MPUnansweredKA    = 0;
-       rr->MPExpectingKA     = mDNSfalse;
-       rr->NextInCFList      = mDNSNULL;
-
-       rr->resrec.InterfaceID       = InterfaceID;
-       ptr = getDomainName(msg, ptr, end, &rr->resrec.name);
-       if (!ptr) { debugf("GetResourceRecord: Malformed RR name"); return(mDNSNULL); }
-
-       if (ptr + 10 > end) { debugf("GetResourceRecord: Malformed RR -- no type/class/ttl/len!"); return(mDNSNULL); }
-       
-       rr->resrec.rrtype            = (mDNSu16) ((mDNSu16)ptr[0] <<  8 | ptr[1]);
-       rr->resrec.rrclass           = (mDNSu16)(((mDNSu16)ptr[2] <<  8 | ptr[3]) & kDNSClass_Mask);
-       rr->resrec.rroriginalttl     = (mDNSu32) ((mDNSu32)ptr[4] << 24 | (mDNSu32)ptr[5] << 16 | (mDNSu32)ptr[6] << 8 | ptr[7]);
-       if (rr->resrec.rroriginalttl > 0x70000000UL / mDNSPlatformOneSecond)
-               rr->resrec.rroriginalttl = 0x70000000UL / mDNSPlatformOneSecond;
-       // Note: We don't have to adjust m->NextCacheCheck here -- this is just getting a record into memory for
-       // us to look at. If we decide to copy it into the cache, then we'll update m->NextCacheCheck accordingly.
-       pktrdlength           = (mDNSu16)((mDNSu16)ptr[8] <<  8 | ptr[9]);
-       if (ptr[2] & (kDNSClass_UniqueRRSet >> 8))
-               rr->resrec.RecordType |= kDNSRecordTypePacketUniqueMask;
-       ptr += 10;
-       if (ptr + pktrdlength > end) { debugf("GetResourceRecord: RDATA exceeds end of packet"); return(mDNSNULL); }
-
-       if (RDataStorage)
-               rr->resrec.rdata = RDataStorage;
-       else
-               {
-               rr->resrec.rdata = (RData*)&rr->rdatastorage;
-               rr->resrec.rdata->MaxRDLength = sizeof(RDataBody);
-               }
-
-       switch (rr->resrec.rrtype)
-               {
-               case kDNSType_A:        rr->resrec.rdata->u.ip.b[0] = ptr[0];
-                                                       rr->resrec.rdata->u.ip.b[1] = ptr[1];
-                                                       rr->resrec.rdata->u.ip.b[2] = ptr[2];
-                                                       rr->resrec.rdata->u.ip.b[3] = ptr[3];
-                                                       break;
-
-               case kDNSType_CNAME:// Same as PTR
-               case kDNSType_PTR:      if (!getDomainName(msg, ptr, end, &rr->resrec.rdata->u.name))
-                                                               { debugf("GetResourceRecord: Malformed CNAME/PTR RDATA name"); return(mDNSNULL); }
-                                                       //debugf("%##s PTR %##s rdlen %d", rr->resrec.name.c, rr->resrec.rdata->u.name.c, pktrdlength);
-                                                       break;
-
-               case kDNSType_NULL:     //Same as TXT
-               case kDNSType_HINFO://Same as TXT
-               case kDNSType_TXT:  if (pktrdlength > rr->resrec.rdata->MaxRDLength)
-                                                               {
-                                                               debugf("GetResourceRecord: %s rdata size (%d) exceeds storage (%d)",
-                                                                       DNSTypeName(rr->resrec.rrtype), pktrdlength, rr->resrec.rdata->MaxRDLength);
-                                                               return(mDNSNULL);
-                                                               }
-                                                       rr->resrec.rdlength = pktrdlength;
-                                                       mDNSPlatformMemCopy(ptr, rr->resrec.rdata->u.data, pktrdlength);
-                                                       break;
-
-               case kDNSType_AAAA:     mDNSPlatformMemCopy(ptr, &rr->resrec.rdata->u.ipv6, sizeof(rr->resrec.rdata->u.ipv6));
-                                                       break;
-
-               case kDNSType_SRV:      rr->resrec.rdata->u.srv.priority = (mDNSu16)((mDNSu16)ptr[0] <<  8 | ptr[1]);
-                                                       rr->resrec.rdata->u.srv.weight   = (mDNSu16)((mDNSu16)ptr[2] <<  8 | ptr[3]);
-                                                       rr->resrec.rdata->u.srv.port.b[0] = ptr[4];
-                                                       rr->resrec.rdata->u.srv.port.b[1] = ptr[5];
-                                                       if (!getDomainName(msg, ptr+6, end, &rr->resrec.rdata->u.srv.target))
-                                                               { debugf("GetResourceRecord: Malformed SRV RDATA name"); return(mDNSNULL); }
-                                                       //debugf("%##s SRV %##s rdlen %d", rr->resrec.name.c, rr->resrec.rdata->u.srv.target.c, pktrdlength);
-                                                       break;
-
-               default:                        if (pktrdlength > rr->resrec.rdata->MaxRDLength)
-                                                               {
-                                                               debugf("GetResourceRecord: rdata %d (%s) size (%d) exceeds storage (%d)",
-                                                                       rr->resrec.rrtype, DNSTypeName(rr->resrec.rrtype), pktrdlength, rr->resrec.rdata->MaxRDLength);
-                                                               return(mDNSNULL);
-                                                               }
-                                                       debugf("GetResourceRecord: Warning! Reading resource type %d (%s) as opaque data",
-                                                               rr->resrec.rrtype, DNSTypeName(rr->resrec.rrtype));
-                                                       // Note: Just because we don't understand the record type, that doesn't
-                                                       // mean we fail. The DNS protocol specifies rdlength, so we can
-                                                       // safely skip over unknown records and ignore them.
-                                                       // We also grab a binary copy of the rdata anyway, since the caller
-                                                       // might know how to interpret it even if we don't.
-                                                       rr->resrec.rdlength = pktrdlength;
-                                                       mDNSPlatformMemCopy(ptr, rr->resrec.rdata->u.data, pktrdlength);
-                                                       break;
-               }
-
-       rr->resrec.namehash = DomainNameHashValue(&rr->resrec.name);
-       SetNewRData(&rr->resrec, mDNSNULL, 0);
-
-       return(ptr + pktrdlength);
-       }
-
-mDNSlocal const mDNSu8 *skipQuestion(const DNSMessage *msg, const mDNSu8 *ptr, const mDNSu8 *end)
-       {
-       ptr = skipDomainName(msg, ptr, end);
-       if (!ptr) { debugf("skipQuestion: Malformed domain name in DNS question section"); return(mDNSNULL); }
-       if (ptr+4 > end) { debugf("skipQuestion: Malformed DNS question section -- no query type and class!"); return(mDNSNULL); }
-       return(ptr+4);
-       }
+                       }
+               }
+       else
+               {
+               *p = rr->next;                                  // Cut this record from the list
+               // If someone is about to look at this, bump the pointer forward
+               if (m->CurrentRecord       == rr) m->CurrentRecord       = rr->next;
+               if (m->NewLocalOnlyRecords == rr) m->NewLocalOnlyRecords = rr->next;
+               rr->next = mDNSNULL;
 
-mDNSlocal const mDNSu8 *getQuestion(const DNSMessage *msg, const mDNSu8 *ptr, const mDNSu8 *end, const mDNSInterfaceID InterfaceID,
-       DNSQuestion *question)
-       {
-       question->InterfaceID = InterfaceID;
-       ptr = getDomainName(msg, ptr, end, &question->qname);
-       if (!ptr) { debugf("Malformed domain name in DNS question section"); return(mDNSNULL); }
-       if (ptr+4 > end) { debugf("Malformed DNS question section -- no query type and class!"); return(mDNSNULL); }
-
-       question->qnamehash = DomainNameHashValue(&question->qname);
-       question->qtype  = (mDNSu16)((mDNSu16)ptr[0] << 8 | ptr[1]);                    // Get type
-       question->qclass = (mDNSu16)((mDNSu16)ptr[2] << 8 | ptr[3]);                    // and class
-       return(ptr+4);
-       }
+               if      (RecordType == kDNSRecordTypeUnregistered)
+                       debugf("mDNS_Deregister_internal: Record %##s (%s) already marked kDNSRecordTypeUnregistered",
+                               rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype));
+               else if (RecordType == kDNSRecordTypeDeregistering)
+                       debugf("mDNS_Deregister_internal: Record %##s (%s) already marked kDNSRecordTypeDeregistering",
+                               rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype));
+               else
+                       {
+                       verbosedebugf("mDNS_Deregister_internal: Deleting record for %##s (%s)", rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype));
+                       rr->resrec.RecordType = kDNSRecordTypeUnregistered;
+                       }
 
-mDNSlocal const mDNSu8 *LocateAnswers(const DNSMessage *const msg, const mDNSu8 *const end)
-       {
-       int i;
-       const mDNSu8 *ptr = msg->data;
-       for (i = 0; i < msg->h.numQuestions && ptr; i++) ptr = skipQuestion(msg, ptr, end);
-       return(ptr);
-       }
+               if ((drt == mDNS_Dereg_conflict || drt == mDNS_Dereg_repeat) && RecordType == kDNSRecordTypeShared)
+                       debugf("mDNS_Deregister_internal: Cannot have a conflict on a shared record! %##s (%s)",
+                               rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype));
 
-mDNSlocal const mDNSu8 *LocateAuthorities(const DNSMessage *const msg, const mDNSu8 *const end)
-       {
-       int i;
-       const mDNSu8 *ptr = LocateAnswers(msg, end);
-       for (i = 0; i < msg->h.numAnswers && ptr; i++) ptr = skipResourceRecord(msg, ptr, end);
-       return(ptr);
+               // If we have an update queued up which never executed, give the client a chance to free that memory
+               if (rr->NewRData) CompleteRDataUpdate(m, rr);   // Update our rdata, clear the NewRData pointer, and return memory to the client
+               
+               // CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function
+               // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc.
+               // In this case the likely client action to the mStatus_MemFree message is to free the memory,
+               // so any attempt to touch rr after this is likely to lead to a crash.
+               m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
+               if (RecordType == kDNSRecordTypeShared)
+                       {
+                       if (rr->RecordCallback)
+                               rr->RecordCallback(m, rr, mStatus_MemFree);
+                       }
+               else if (drt == mDNS_Dereg_conflict)
+                       {
+                       RecordProbeFailure(m, rr);
+                       if (rr->RecordCallback)
+                               rr->RecordCallback(m, rr, mStatus_NameConflict);
+                       }
+               m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
+               }
+       return(mStatus_NoError);
        }
 
 // ***************************************************************************
@@ -3258,38 +2195,6 @@ mDNSlocal const mDNSu8 *LocateAuthorities(const DNSMessage *const msg, const mDN
 #pragma mark - Packet Sending Functions
 #endif
 
-mDNSlocal mStatus mDNSSendDNSMessage(const mDNS *const m, DNSMessage *const msg, const mDNSu8 *const end,
-       mDNSInterfaceID InterfaceID, mDNSIPPort srcport, const mDNSAddr *dst, mDNSIPPort dstport)
-       {
-       mStatus status;
-       mDNSu16 numQuestions   = msg->h.numQuestions;
-       mDNSu16 numAnswers     = msg->h.numAnswers;
-       mDNSu16 numAuthorities = msg->h.numAuthorities;
-       mDNSu16 numAdditionals = msg->h.numAdditionals;
-       
-       // Put all the integer values in IETF byte-order (MSB first, LSB second)
-       mDNSu8 *ptr = (mDNSu8 *)&msg->h.numQuestions;
-       *ptr++ = (mDNSu8)(numQuestions   >> 8);
-       *ptr++ = (mDNSu8)(numQuestions       );
-       *ptr++ = (mDNSu8)(numAnswers     >> 8);
-       *ptr++ = (mDNSu8)(numAnswers         );
-       *ptr++ = (mDNSu8)(numAuthorities >> 8);
-       *ptr++ = (mDNSu8)(numAuthorities     );
-       *ptr++ = (mDNSu8)(numAdditionals >> 8);
-       *ptr++ = (mDNSu8)(numAdditionals     );
-       
-       // Send the packet on the wire
-       status = mDNSPlatformSendUDP(m, msg, end, InterfaceID, srcport, dst, dstport);
-       
-       // Put all the integer values back the way they were before we return
-       msg->h.numQuestions   = numQuestions;
-       msg->h.numAnswers     = numAnswers;
-       msg->h.numAuthorities = numAuthorities;
-       msg->h.numAdditionals = numAdditionals;
-
-       return(status);
-       }
-
 mDNSlocal void CompleteDeregistration(mDNS *const m, AuthRecord *rr)
        {
        // Setting AnnounceCount to InitialAnnounceCount signals mDNS_Deregister_internal()
@@ -3316,6 +2221,12 @@ mDNSlocal void DiscardDeregistrations(mDNS *const m)
                }
        }
 
+mDNSlocal void GrantUpdateCredit(AuthRecord *rr)
+       {
+       if (++rr->UpdateCredits >= kMaxUpdateCredits) rr->NextUpdateCredit = 0;
+       else rr->NextUpdateCredit = (rr->NextUpdateCredit + kUpdateCreditRefreshInterval) | 1;
+       }
+
 mDNSlocal mDNSBool HaveSentEntireRRSet(const mDNS *const m, const AuthRecord *const rr, mDNSInterfaceID InterfaceID)
        {
        // Try to find another member of this set that we're still planning to send on this interface
@@ -3357,11 +2268,7 @@ mDNSlocal void SendResponses(mDNS *const m)
        // Run through our list of records, and decide which ones we're going to announce on all interfaces
        for (rr = m->ResourceRecords; rr; rr=rr->next)
                {
-               if (rr->NextUpdateCredit && m->timenow - rr->NextUpdateCredit >= 0)
-                       {
-                       if (++rr->UpdateCredits >= kMaxUpdateCredits) rr->NextUpdateCredit = 0; 
-                       else rr->NextUpdateCredit = (m->timenow + mDNSPlatformOneSecond * 60) | 1;
-                       }
+               while (rr->NextUpdateCredit && m->timenow - rr->NextUpdateCredit >= 0) GrantUpdateCredit(rr);
                if (TimeToAnnounceThisRecord(rr, m->timenow) && ResourceRecordIsValidAnswer(rr))
                        {
                        rr->ImmedAnswer = mDNSInterfaceMark;            // Send on all interfaces
@@ -3380,17 +2287,20 @@ mDNSlocal void SendResponses(mDNS *const m)
                        ResourceRecordIsValidAnswer(rr)))
                        rr->ImmedAnswer = mDNSInterfaceMark;            // Send on all interfaces
 
-       // When sending SRV records (particularly when announcing a new service) automatically add the related Address record(s)
+       // When sending SRV records (particularly when announcing a new service) automatically add related Address record(s) as additionals
+       // NOTE: Currently all address records are interface-specific, so it's safe to set ImmedAdditional to their InterfaceID,
+       // which will be non-null. If by some chance there is an address record that's not interface-specific (should never happen)
+       // then all that means is that it won't get sent -- which would not be the end of the world.
        for (rr = m->ResourceRecords; rr; rr=rr->next)
                if (rr->ImmedAnswer && rr->resrec.rrtype == kDNSType_SRV)
                        for (r2=m->ResourceRecords; r2; r2=r2->next)                            // Scan list of resource records
-                               if (RRIsAddressType(r2) &&                                                              // For all address records (A/AAAA) ...
+                               if (RRTypeIsAddressType(r2->resrec.rrtype) &&                   // For all address records (A/AAAA) ...
                                        ResourceRecordIsValidAnswer(r2) &&                                      // ... which are valid for answer ...
                                        rr->LastMCTime - r2->LastMCTime >= 0 &&                         // ... which we have not sent recently ...
                                        rr->resrec.rdnamehash == r2->resrec.namehash &&         // ... whose name is the name of the SRV target
                                        SameDomainName(&rr->resrec.rdata->u.srv.target, &r2->resrec.name) &&
                                        (rr->ImmedAnswer == mDNSInterfaceMark || rr->ImmedAnswer == r2->resrec.InterfaceID))
-                                       r2->ImmedAnswer = mDNSInterfaceMark;                            // ... then mark this address record for sending too
+                                       r2->ImmedAdditional = r2->resrec.InterfaceID;           // ... then mark this address record for sending too
 
        // If there's a record which is supposed to be unique that we're going to send, then make sure that we give
        // the whole RRSet as an atomic unit. That means that if we have any other records with the same name/type/class
@@ -3438,12 +2348,13 @@ mDNSlocal void SendResponses(mDNS *const m)
                        }
                else if (rr->ImmedAnswer)                                               // Else, just respond to a single query on single interface:
                        {
-                       rr->SendRNow = rr->ImmedAnswer;                         // Just respond on that interface
+                       rr->SendRNow        = rr->ImmedAnswer;          // Just respond on that interface
                        rr->ImmedAdditional = mDNSNULL;                         // No need to send as additional too
                        rr->LastMCTime      = m->timenow;
                        rr->LastMCInterface = rr->ImmedAnswer;
                        }
                SetNextAnnounceProbeTime(m, rr);
+               //if (rr->SendRNow) LogMsg("%-15.4a %s", &rr->v4Requester, GetRRDisplayString(m, rr));
                }
 
        // ***
@@ -3482,7 +2393,7 @@ mDNSlocal void SendResponses(mDNS *const m)
                                        {
                                        RData *OldRData     = rr->resrec.rdata;
                                        mDNSu16 oldrdlength = rr->resrec.rdlength;
-                                       // See if we should send a courtesy "goodbye" the old data before we replace it.
+                                       // See if we should send a courtesy "goodbye" for the old data before we replace it.
                                        // We compare with "InitialAnnounceCount-1" instead of "InitialAnnounceCount" because by the time
                                        // we get to this place in this routine we've we've already decremented rr->AnnounceCount
                                        if (ResourceRecordIsValidAnswer(rr) && rr->AnnounceCount < InitialAnnounceCount-1)
@@ -3537,7 +2448,16 @@ mDNSlocal void SendResponses(mDNS *const m)
                                                        rr->resrec.rrclass |= kDNSClass_UniqueRRSet;    // Temporarily set the cache flush bit so PutResourceRecord will set it
                                                }
                                        newptr = PutResourceRecord(&response, newptr, &response.h.numAdditionals, &rr->resrec);
-                                       if (newptr) responseptr = newptr;
+                                       if (newptr)
+                                               {
+                                               responseptr = newptr;
+                                               // If we successfully put this additional record in the packet, we record LastMCTime & LastMCInterface.
+                                               // This matters particularly in the case where we have more than one IPv6 (or IPv4) address, because otherwise,
+                                               // when we see our own multicast with the cache flush bit set, if we haven't set LastMCTime, then we'll get
+                                               // all concerned and re-announce our record again to make sure it doesn't get flushed from peer caches.
+                                               rr->LastMCTime      = m->timenow;
+                                               rr->LastMCInterface = intf->InterfaceID;
+                                               }
                                        rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet;                   // Make sure to clear cache flush bit back to normal state
                                        }
                                }
@@ -3549,8 +2469,8 @@ mDNSlocal void SendResponses(mDNS *const m)
                                numAnnounce,               numAnnounce               == 1 ? "" : "s",
                                numAnswer,                 numAnswer                 == 1 ? "" : "s",
                                response.h.numAdditionals, response.h.numAdditionals == 1 ? "" : "s", intf->InterfaceID);
-                       mDNSSendDNSMessage(m, &response, responseptr, intf->InterfaceID, MulticastDNSPort, &AllDNSLinkGroup_v4, MulticastDNSPort);
-                       mDNSSendDNSMessage(m, &response, responseptr, intf->InterfaceID, MulticastDNSPort, &AllDNSLinkGroup_v6, MulticastDNSPort);
+                       if (intf->IPv4Available) mDNSSendDNSMessage(m, &response, responseptr, intf->InterfaceID, &AllDNSLinkGroup_v4, MulticastDNSPort);
+                       if (intf->IPv6Available) mDNSSendDNSMessage(m, &response, responseptr, intf->InterfaceID, &AllDNSLinkGroup_v6, MulticastDNSPort);
                        if (!m->SuppressSending) m->SuppressSending = (m->timenow + mDNSPlatformOneSecond/10) | 1;      // OR with one to ensure non-zero
                        if (++pktcount >= 1000)
                                { LogMsg("SendResponses exceeded loop limit %d: giving up", pktcount); break; }
@@ -3578,14 +2498,10 @@ mDNSlocal void SendResponses(mDNS *const m)
                rr = m->CurrentRecord;
                m->CurrentRecord = rr->next;
 
-               if (rr->NewRData)
-                       {
-                       RData *OldRData = rr->resrec.rdata;
-                       SetNewRData(&rr->resrec, rr->NewRData, rr->newrdlength);        // Update our rdata
-                       rr->NewRData = mDNSNULL;                                                                        // Clear the NewRData pointer ...
-                       if (rr->UpdateCallback)
-                               rr->UpdateCallback(m, rr, OldRData);                                    // ... and let the client know
-                       }
+               if (rr->SendRNow)
+                       { LogMsg("SendResponses: No active interface to send: %s", GetRRDisplayString(m, rr)); rr->SendRNow = mDNSNULL; }
+
+               if (rr->NewRData) CompleteRDataUpdate(m,rr);    // Update our rdata, clear the NewRData pointer, and return memory to the client
 
                if (rr->resrec.RecordType == kDNSRecordTypeDeregistering)
                        CompleteDeregistration(m, rr);
@@ -3643,6 +2559,12 @@ mDNSlocal void SetNextCacheCheckTime(mDNS *const m, CacheRecord *const rr)
 
 mDNSlocal mStatus mDNS_Reconfirm_internal(mDNS *const m, CacheRecord *const rr, mDNSu32 interval)
        {
+       if (!rr->resrec.InterfaceID && !IsLocalDomain(&rr->resrec.name))
+               {
+               LogMsg("mDNS_Reconfirm_internal: Not implemented for unicast DNS");
+               return mStatus_UnsupportedErr;
+               }
+
        if (interval < kMinimumReconfirmTime)
                interval = kMinimumReconfirmTime;
        if (interval > 0x10000000)      // Make sure interval doesn't overflow when we multiply by four below
@@ -3669,7 +2591,7 @@ mDNSlocal mStatus mDNS_Reconfirm_internal(mDNS *const m, CacheRecord *const rr,
 mDNSlocal mDNSBool BuildQuestion(mDNS *const m, DNSMessage *query, mDNSu8 **queryptr, DNSQuestion *q,
        CacheRecord ***kalistptrptr, mDNSu32 *answerforecast)
        {
-       mDNSBool ucast = q->LargeAnswers || q->ThisQInterval <= InitialQuestionInterval*2;
+       mDNSBool ucast = (q->LargeAnswers || q->ThisQInterval <= InitialQuestionInterval*2) && m->CanReceiveUnicast;
        mDNSu16 ucbit = (mDNSu16)(ucast ? kDNSQClass_UnicastResponse : 0);
        const mDNSu8 *const limit = query->data + NormalMaxDNSMessageData;
        mDNSu8 *newptr = putQuestion(query, *queryptr, limit, &q->qname, q->qtype, (mDNSu16)(q->qclass | ucbit));
@@ -3695,8 +2617,7 @@ mDNSlocal mDNSBool BuildQuestion(mDNS *const m, DNSMessage *query, mDNSu8 **quer
                                rr->NextInKAList == mDNSNULL && ka != &rr->NextInKAList &&      // which is not already in the known answer list
                                rr->resrec.rdlength <= SmallRecordLimit &&                                      // which is small enough to sensibly fit in the packet
                                ResourceRecordAnswersQuestion(&rr->resrec, q) &&                        // which answers our question
-                               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
+                               rr->TimeRcvd + TicksTTL(rr)/2 - m->timenow >= 0)                        // and it is less than half-way to expiry
                                {
                                *ka = rr;       // Link this record into our known answer chain
                                ka = &rr->NextInKAList;
@@ -3882,13 +2803,32 @@ mDNSlocal void SendQueries(mDNS *const m)
                                                {
                                                q = rr->CRActiveQuestion;
                                                ExpireDupSuppressInfoOnInterface(q->DupSuppress, m->timenow - TicksTTL(rr)/20, rr->resrec.InterfaceID);
-                                               if      (q->SendQNow == mDNSNULL)               q->SendQNow = rr->resrec.InterfaceID;
+                                               if (q->Target.type) q->SendQNow = mDNSInterfaceMark;    // If unicast query, mark it
+                                               else if (q->SendQNow == mDNSNULL)               q->SendQNow = rr->resrec.InterfaceID;
                                                else if (q->SendQNow != rr->resrec.InterfaceID) q->SendQNow = mDNSInterfaceMark;
                                                }
 
+               // Scan our list of questions to see which unicast queries need to be sent
+               for (q = m->Questions; q; q=q->next)
+                       if (q->Target.type && (q->SendQNow || TimeToSendThisQuestion(q, m->timenow)))
+                               {
+                               DNSMessage query;
+                               mDNSu8       *qptr        = query.data;
+                               const mDNSu8 *const limit = query.data + sizeof(query.data);
+                               InitializeDNSMessage(&query.h, q->TargetQID, QueryFlags);
+                               qptr = putQuestion(&query, qptr, limit, &q->qname, q->qtype, q->qclass);
+                               mDNSSendDNSMessage(m, &query, qptr, mDNSInterface_Any, &q->Target, q->TargetPort);
+                               q->ThisQInterval *= 2;
+                               q->LastQTime     = m->timenow;
+                               q->LastQTxTime   = m->timenow;
+                               q->RecentAnswers = 0;
+                               q->SendQNow      = mDNSNULL;
+                               m->ExpectUnicastResponse = m->timenow;
+                               }
+       
                // Scan our list of questions to see which ones we're definitely going to send
                for (q = m->Questions; q; q=q->next)
-                       if (TimeToSendThisQuestion(q, m->timenow))
+                       if (!q->Target.type && TimeToSendThisQuestion(q, m->timenow))
                                {
                                q->SendQNow = mDNSInterfaceMark;                // Mark this question for sending on all interfaces
                                if (maxExistingQuestionInterval < q->ThisQInterval)
@@ -3900,7 +2840,8 @@ mDNSlocal void SendQueries(mDNS *const m)
                // (b) to update the state variables for all the questions we're going to send
                for (q = m->Questions; q; q=q->next)
                        {
-                       if (q->SendQNow || (ActiveQuestion(q) && q->ThisQInterval <= maxExistingQuestionInterval && AccelerateThisQuery(m,q)))
+                       if (q->SendQNow ||
+                               (!q->Target.type && ActiveQuestion(q) && q->ThisQInterval <= maxExistingQuestionInterval && AccelerateThisQuery(m,q)))
                                {
                                // If at least halfway to next query time, advance to next interval
                                // If less than halfway to next query time, treat this as logically a repeat of the last transmission, without advancing the interval
@@ -4021,7 +2962,7 @@ mDNSlocal void SendQueries(mDNS *const m)
                        for (rr = m->ResourceRecords; rr; rr=rr->next)
                                if (rr->SendRNow == intf->InterfaceID)
                                        {
-                                       mDNSBool ucast = rr->ProbeCount >= DefaultProbeCountForTypeUnique-1;
+                                       mDNSBool ucast = (rr->ProbeCount >= DefaultProbeCountForTypeUnique-1) && m->CanReceiveUnicast;
                                        mDNSu16 ucbit = (mDNSu16)(ucast ? kDNSQClass_UnicastResponse : 0);
                                        const mDNSu8 *const limit = query.data + ((query.h.numQuestions) ? NormalMaxDNSMessageData : AbsoluteMaxDNSMessageData);
                                        mDNSu8 *newptr = putQuestion(&query, queryptr, limit, &rr->resrec.name, kDNSQType_ANY, (mDNSu16)(rr->resrec.rrclass | ucbit));
@@ -4085,8 +3026,8 @@ mDNSlocal void SendQueries(mDNS *const m)
                                query.h.numQuestions,   query.h.numQuestions   == 1 ? "" : "s",
                                query.h.numAnswers,     query.h.numAnswers     == 1 ? "" : "s",
                                query.h.numAuthorities, query.h.numAuthorities == 1 ? "" : "s", intf->InterfaceID);
-                       mDNSSendDNSMessage(m, &query, queryptr, intf->InterfaceID, MulticastDNSPort, &AllDNSLinkGroup_v4, MulticastDNSPort);
-                       mDNSSendDNSMessage(m, &query, queryptr, intf->InterfaceID, MulticastDNSPort, &AllDNSLinkGroup_v6, MulticastDNSPort);
+                       if (intf->IPv4Available) mDNSSendDNSMessage(m, &query, queryptr, intf->InterfaceID, &AllDNSLinkGroup_v4, MulticastDNSPort);
+                       if (intf->IPv6Available) mDNSSendDNSMessage(m, &query, queryptr, intf->InterfaceID, &AllDNSLinkGroup_v6, MulticastDNSPort);
                        if (!m->SuppressSending) m->SuppressSending = (m->timenow + mDNSPlatformOneSecond/10) | 1;      // OR with one to ensure non-zero
                        if (++pktcount >= 1000)
                                { LogMsg("SendQueries exceeded loop limit %d: giving up", pktcount); break; }
@@ -4103,6 +3044,14 @@ mDNSlocal void SendQueries(mDNS *const m)
                        intf = next;
                        }
                }
+
+       // Final sanity check for debugging purposes
+               {
+               AuthRecord *rr;
+               for (rr = m->ResourceRecords; rr; rr=rr->next)
+                       if (rr->SendRNow)
+                               { LogMsg("SendQueries: No active interface to send: %s", GetRRDisplayString(m, rr)); rr->SendRNow = mDNSNULL; }
+               }
        }
 
 // ***************************************************************************
@@ -4294,7 +3243,7 @@ mDNSlocal void AnswerNewQuestion(mDNS *const m)
        if (m->lock_rrcache) LogMsg("AnswerNewQuestion ERROR! Cache already locked!");
        // This should be safe, because calling the client's question callback may cause the
        // question list to be modified, but should not ever cause the rrcache list to be modified.
-       // If the client's question callback deletes the question, then m->CurrentQuestion will
+       // If the client's question callback deletes the question, then m->CurrentQuestion will 
        // be advanced, and we'll exit out of the loop
        m->lock_rrcache = 1;
        if (m->CurrentQuestion) LogMsg("AnswerNewQuestion ERROR m->CurrentQuestion already set");
@@ -4431,7 +3380,11 @@ mDNSlocal CacheRecord *GetFreeCacheRR(mDNS *const m, mDNSu16 RDLength)
                        debugf("Possible denial-of-service attack in progress: m->rrcache_size %lu; m->rrcache_active %lu",
                                m->rrcache_size, m->rrcache_active);
                else
+                       {
+                       m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
                        m->MainCallback(m, mStatus_GrowCache);
+                       m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
+                       }
                }
        
        // If we still have no free records, recycle all the records we can.
@@ -4558,6 +3511,7 @@ mDNSlocal mDNSs32 GetNextScheduledEvent(const mDNS *const m)
        if (m->NewLocalOnlyRecords)     return(m->timenow);
        if (m->DiscardLocalOnlyRecords) return(m->timenow);
        if (m->SuppressSending)         return(m->SuppressSending);
+       if (e - m->uDNS_info.nextevent   > 0) e = m->uDNS_info.nextevent;
        if (e - m->NextCacheCheck        > 0) e = m->NextCacheCheck;
        if (e - m->NextScheduledQuery    > 0) e = m->NextScheduledQuery;
        if (e - m->NextScheduledProbe    > 0) e = m->NextScheduledProbe;
@@ -4590,6 +3544,7 @@ mDNSexport mDNSs32 mDNS_Execute(mDNS *const m)
        {
        mDNS_Lock(m);   // Must grab lock before trying to read m->timenow
 
+       
        if (m->timenow - m->NextScheduledEvent >= 0)
                {
                int i;
@@ -4681,6 +3636,7 @@ mDNSexport mDNSs32 mDNS_Execute(mDNS *const m)
        // callback function should call mDNS_Execute() (and ignore the return value, which may already be stale
        // by the time it gets to the timer callback function).
 
+       uDNS_Execute(m);
        mDNS_Unlock(m);         // Calling mDNS_Unlock is what gives m->NextScheduledEvent its new value
        return(m->NextScheduledEvent);
        }
@@ -4703,10 +3659,11 @@ mDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleepstate)
        mDNS_Lock(m);
 
        m->SleepState = sleepstate;
-       LogMsg("mDNSResponder %s at %ld", sleepstate ? "Sleeping" : "Waking", m->timenow);
+       LogMsg("%s at %ld", sleepstate ? "Sleeping" : "Waking", m->timenow);
 
        if (sleepstate)
                {
+               uDNS_SuspendLLQs(m);
                // Mark all the records we need to deregister and send them
                for (rr = m->ResourceRecords; rr; rr=rr->next)
                        if (rr->resrec.RecordType == kDNSRecordTypeShared && rr->AnnounceCount < InitialAnnounceCount)
@@ -4719,7 +3676,9 @@ mDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleepstate)
                mDNSu32 slot;
                CacheRecord *cr;
 
-               // 1. Retrigger all our questions
+               uDNS_RestartLLQs(m);
+
+        // 1. Retrigger all our questions
                for (q = m->Questions; q; q=q->next)                            // Scan our list of questions
                        if (ActiveQuestion(q))
                                {
@@ -5105,7 +4064,7 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con
                        // can't guarantee to receive all of the Known Answer packets that go with a particular query.
                        if (!(query->h.flags.b[0] & kDNSFlag0_TC))
                                for (q = m->Questions; q; q=q->next)
-                                       if (ActiveQuestion(q) && m->timenow - q->LastQTxTime > mDNSPlatformOneSecond / 4)
+                                       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))
@@ -5136,10 +4095,10 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con
                // For SRV records, automatically add the Address record(s) for the target host
                if (rr->resrec.rrtype == kDNSType_SRV)
                        for (rr2=m->ResourceRecords; rr2; rr2=rr2->next)                                        // Scan list of resource records
-                               if (RRIsAddressType(rr2) &&                                                                             // For all address records (A/AAAA) ...
+                               if (RRTypeIsAddressType(rr2->resrec.rrtype) &&                                  // For all address records (A/AAAA) ...
                                        ResourceRecordIsValidInterfaceAnswer(rr2, InterfaceID) &&       // ... which are valid for answer ...
-                                       rr->resrec.rdnamehash == rr2->resrec.namehash &&
-                                       SameDomainName(&rr->resrec.rdata->u.srv.target, &rr2->resrec.name))             // ... whose name is the name of the SRV target
+                                       rr->resrec.rdnamehash == rr2->resrec.namehash &&                        // ... whose name is the name of the SRV target
+                                       SameDomainName(&rr->resrec.rdata->u.srv.target, &rr2->resrec.name))
                                        AddRecordToResponseList(&nrp, rr2, rr);
                }
 
@@ -5174,7 +4133,13 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con
                                        {
                                        if (mDNSSameIPv6Address(rr->v6Requester, srcaddr->ip.v6)) rr->v6Requester = zerov6Addr;
                                        }
-                               if (mDNSIPv4AddressIsZero(rr->v4Requester) && mDNSIPv6AddressIsZero(rr->v6Requester)) rr->ImmedAnswer = mDNSNULL;
+                               if (mDNSIPv4AddressIsZero(rr->v4Requester) && mDNSIPv6AddressIsZero(rr->v6Requester))
+                                       {
+                                       rr->ImmedAnswer = mDNSNULL;
+#if MDNS_LOG_ANSWER_SUPPRESSION_TIMES
+                                       LogMsg("Suppressed after%4d: %s", m->timenow - rr->ImmedAnswerMarkTime, GetRRDisplayString(m, rr));
+#endif
+                                       }
                                }
                        }
 
@@ -5238,17 +4203,19 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con
        
                        if (SendMulticastResponse)
                                {
+#if MDNS_LOG_ANSWER_SUPPRESSION_TIMES
+                               rr->ImmedAnswerMarkTime = m->timenow;
+#endif
+                               m->NextScheduledResponse = m->timenow;
                                // If we're already planning to send this on another interface, just send it on all interfaces
                                if (rr->ImmedAnswer && rr->ImmedAnswer != InterfaceID)
                                        {
                                        rr->ImmedAnswer = mDNSInterfaceMark;
-                                       m->NextScheduledResponse = m->timenow;
                                        debugf("ProcessQuery: %##s (%s) : Will send on all interfaces", rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype));
                                        }
                                else
                                        {
                                        rr->ImmedAnswer = InterfaceID;                  // Record interface to send it on
-                                       m->NextScheduledResponse = m->timenow;
                                        if (srcaddr->type == mDNSAddrType_IPv4)
                                                {
                                                if      (mDNSIPv4AddressIsZero(rr->v4Requester))                rr->v4Requester = srcaddr->ip.v4;
@@ -5265,7 +4232,7 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con
                                {
                                if (query->h.flags.b[0] & kDNSFlag0_TC) delayresponse = mDNSPlatformOneSecond * 20;     // Divided by 50 = 400ms
                                else                                    delayresponse = mDNSPlatformOneSecond;          // Divided by 50 = 20ms
-                       }
+                               }
                        }
                else if (rr->NR_AdditionalTo && rr->NR_AdditionalTo->NR_AnswerTo == (mDNSu8*)~0)
                        {
@@ -5283,6 +4250,11 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con
        // ***
        if (delayresponse && (!m->SuppressSending || (m->SuppressSending - m->timenow) < (delayresponse + 49) / 50))
                {
+#if MDNS_LOG_ANSWER_SUPPRESSION_TIMES
+               mDNSs32 oldss = m->SuppressSending;
+               if (oldss && delayresponse)
+                       LogMsg("Current SuppressSending delay%5ld; require%5ld", m->SuppressSending - m->timenow, (delayresponse + 49) / 50);
+#endif
                // Pick a random delay:
                // We start with the base delay chosen above (typically either 1 second or 20 seconds),
                // and add a random value in the range 0-5 seconds (making 1-6 seconds or 20-25 seconds).
@@ -5298,10 +4270,14 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con
                // or 400-500ms in the case of multi-packet known-answer lists.
                m->SuppressSending = m->timenow + (delayresponse + (mDNSs32)mDNSRandom((mDNSu32)mDNSPlatformOneSecond*5) + 49) / 50;
                if (m->SuppressSending == 0) m->SuppressSending = 1;
+#if MDNS_LOG_ANSWER_SUPPRESSION_TIMES
+               if (oldss && delayresponse)
+                       LogMsg("Set     SuppressSending to   %5ld", m->SuppressSending - m->timenow);
+#endif
                }
 
        // ***
-       // *** 8. If query is from a legacy client, generate a unicast response too
+       // *** 8. If query is from a legacy client, or from a new client requesting a unicast reply, then generate a unicast response too
        // ***
        if (HaveUnicastAnswer)
                responseptr = GenerateUnicastResponse(query, end, InterfaceID, LegacyQuery, response, ResponseRecords);
@@ -5395,64 +4371,42 @@ exit:
        return(responseptr);
        }
 
-mDNSlocal mDNSBool AddressIsLocalSubnet(mDNS *const m, const mDNSInterfaceID InterfaceID, const mDNSAddr *addr)
-       {
-       NetworkInterfaceInfo *intf;
-
-       if (addr->type == mDNSAddrType_IPv4)
-               {
-               if (addr->ip.v4.b[0] == 169 && addr->ip.v4.b[1] == 254) return(mDNStrue);
-               for (intf = m->HostInterfaces; intf; intf = intf->next)
-                       if (intf->ip.type == addr->type && intf->InterfaceID == InterfaceID)
-                               if (((intf->ip.ip.v4.NotAnInteger ^ addr->ip.v4.NotAnInteger) & intf->mask.ip.v4.NotAnInteger) == 0)
-                                       return(mDNStrue);
-               }
-
-       if (addr->type == mDNSAddrType_IPv6)
-               {
-               if (addr->ip.v6.b[0] == 0xFE && addr->ip.v6.b[1] == 0x80) return(mDNStrue);
-               for (intf = m->HostInterfaces; intf; intf = intf->next)
-                       if (intf->ip.type == addr->type && intf->InterfaceID == InterfaceID)
-                               if ((((intf->ip.ip.v6.l[0] ^ addr->ip.v6.l[0]) & intf->mask.ip.v6.l[0]) == 0) &&
-                                       (((intf->ip.ip.v6.l[1] ^ addr->ip.v6.l[1]) & intf->mask.ip.v6.l[1]) == 0) &&
-                                       (((intf->ip.ip.v6.l[2] ^ addr->ip.v6.l[2]) & intf->mask.ip.v6.l[2]) == 0) &&
-                                       (((intf->ip.ip.v6.l[3] ^ addr->ip.v6.l[3]) & intf->mask.ip.v6.l[3]) == 0))
-                                               return(mDNStrue);
-               }
-
-       return(mDNSfalse);
-       }
-
 mDNSlocal void mDNSCoreReceiveQuery(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end,
        const mDNSAddr *srcaddr, const mDNSIPPort srcport, const mDNSAddr *dstaddr, mDNSIPPort dstport,
        const mDNSInterfaceID InterfaceID)
        {
-       if (mDNSAddrIsDNSMulticast(dstaddr) || AddressIsLocalSubnet(m, InterfaceID, srcaddr))
+       DNSMessage    response;
+       mDNSu8 *responseend    = mDNSNULL;
+       
+       if (!InterfaceID)
                {
-               DNSMessage    response;
-               const mDNSu8 *responseend    = mDNSNULL;
-               
-               verbosedebugf("Received Query from %#-15a:%d to %#-15a:%d on 0x%.8X with %2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s",
-                       srcaddr, (mDNSu16)srcport.b[0]<<8 | srcport.b[1],
-                       dstaddr, (mDNSu16)dstport.b[0]<<8 | dstport.b[1],
-                       InterfaceID,
+               LogMsg("Ignoring Query from %#-15a:%-5d to %#-15a:%-5d on 0x%.8X with %2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s",
+                       srcaddr, mDNSVal16(srcport), dstaddr, mDNSVal16(dstport), InterfaceID,
                        msg->h.numQuestions,   msg->h.numQuestions   == 1 ? ", " : "s,",
                        msg->h.numAnswers,     msg->h.numAnswers     == 1 ? ", " : "s,",
                        msg->h.numAuthorities, msg->h.numAuthorities == 1 ? "y,  " : "ies,",
                        msg->h.numAdditionals, msg->h.numAdditionals == 1 ? "" : "s");
-               
-               responseend = ProcessQuery(m, msg, end, srcaddr, InterfaceID,
-                       (srcport.NotAnInteger != MulticastDNSPort.NotAnInteger), mDNSAddrIsDNSMulticast(dstaddr), &response);
+               return;
+               }
        
-               if (responseend)        // If responseend is non-null, that means we built a unicast response packet
-                       {
-                       debugf("Unicast Response: %d Question%s, %d Answer%s, %d Additional%s to %#-15a:%d on %p/%ld",
-                               response.h.numQuestions,   response.h.numQuestions   == 1 ? "" : "s",
-                               response.h.numAnswers,     response.h.numAnswers     == 1 ? "" : "s",
-                               response.h.numAdditionals, response.h.numAdditionals == 1 ? "" : "s",
-                               srcaddr, (mDNSu16)srcport.b[0]<<8 | srcport.b[1], InterfaceID, srcaddr->type);
-                       mDNSSendDNSMessage(m, &response, responseend, InterfaceID, dstport, srcaddr, srcport);
-                       }
+       verbosedebugf("Received Query from %#-15a:%-5d to %#-15a:%-5d on 0x%.8X with %2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s",
+               srcaddr, mDNSVal16(srcport), dstaddr, mDNSVal16(dstport), InterfaceID,
+               msg->h.numQuestions,   msg->h.numQuestions   == 1 ? ", " : "s,",
+               msg->h.numAnswers,     msg->h.numAnswers     == 1 ? ", " : "s,",
+               msg->h.numAuthorities, msg->h.numAuthorities == 1 ? "y,  " : "ies,",
+               msg->h.numAdditionals, msg->h.numAdditionals == 1 ? "" : "s");
+       
+       responseend = ProcessQuery(m, msg, end, srcaddr, InterfaceID,
+               (srcport.NotAnInteger != MulticastDNSPort.NotAnInteger), mDNSAddrIsDNSMulticast(dstaddr), &response);
+
+       if (responseend)        // If responseend is non-null, that means we built a unicast response packet
+               {
+               debugf("Unicast Response: %d Question%s, %d Answer%s, %d Additional%s to %#-15a:%d on %p/%ld",
+                       response.h.numQuestions,   response.h.numQuestions   == 1 ? "" : "s",
+                       response.h.numAnswers,     response.h.numAnswers     == 1 ? "" : "s",
+                       response.h.numAdditionals, response.h.numAdditionals == 1 ? "" : "s",
+                       srcaddr, mDNSVal16(srcport), InterfaceID, srcaddr->type);
+               mDNSSendDNSMessage(m, &response, responseend, InterfaceID, srcaddr, srcport);
                }
        }
 
@@ -5460,9 +4414,11 @@ mDNSlocal void mDNSCoreReceiveQuery(mDNS *const m, const DNSMessage *const msg,
 // 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 mDNSCoreReceiveResponse(mDNS *const m,
-       const DNSMessage *const response, const mDNSu8 *end, const mDNSAddr *srcaddr, const mDNSAddr *dstaddr,
-       const mDNSInterfaceID InterfaceID)
+       const DNSMessage *const response, const mDNSu8 *end,
+       const mDNSAddr *srcaddr, const mDNSIPPort srcport, const mDNSAddr *dstaddr, mDNSIPPort dstport,
+       const mDNSInterfaceID InterfaceID, mDNSu8 ttl)
        {
+       static mDNSu32 NumPktsAccepted = 0, NumPktsIgnored = 0;
        int i;
        const mDNSu8 *ptr = LocateAnswers(response, end);       // We ignore questions (if any) in a DNS response packet
        CacheRecord *CacheFlushRecords = mDNSNULL;
@@ -5475,25 +4431,31 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
 
        (void)srcaddr;  // Currently used only for display in debugging message
 
-       verbosedebugf("Received Response from %#-15a addressed to %#-15a on %p with %2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s",
-               srcaddr, dstaddr, InterfaceID,
+       verbosedebugf("Received Response from %#-15a addressed to %#-15a on %p TTL %d with %2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s",
+               srcaddr, dstaddr, InterfaceID, ttl,
                response->h.numQuestions,   response->h.numQuestions   == 1 ? ", " : "s,",
                response->h.numAnswers,     response->h.numAnswers     == 1 ? ", " : "s,",
                response->h.numAuthorities, response->h.numAuthorities == 1 ? "y,  " : "ies,",
                response->h.numAdditionals, response->h.numAdditionals == 1 ? "" : "s");
 
-       // If we get a unicast response when we weren't expecting one, then we assume it is someone trying to spoof us
-       if (!mDNSAddrIsDNSMulticast(dstaddr))
-               if (!AddressIsLocalSubnet(m, InterfaceID, srcaddr) || (mDNSu32)(m->timenow - m->ExpectUnicastResponse) > (mDNSu32)(mDNSPlatformOneSecond*2))
-                       {
-                       debugf("** Ignored apparent spoof mDNS Response from %#-15a to %#-15a on %p with %2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s",
-                               srcaddr, dstaddr, InterfaceID,
-                               response->h.numQuestions,   response->h.numQuestions   == 1 ? ", " : "s,",
-                               response->h.numAnswers,     response->h.numAnswers     == 1 ? ", " : "s,",
-                               response->h.numAuthorities, response->h.numAuthorities == 1 ? "y,  " : "ies,",
-                               response->h.numAdditionals, response->h.numAdditionals == 1 ? "" : "s");
-                       return;
-                       }
+       // TTL should be 255
+       // In the case of overlayed subnets that aren't using RFC 3442, some packets may incorrectly
+       // go to the router first and then come back with a TTL of 254, so we allow that too.
+       // Anything lower than 254 is a pretty good sign of an off-net spoofing attack.
+       // Also, if we get a unicast response when we weren't expecting one, then we assume it is someone trying to spoof us
+       if (ttl < 254 || (!mDNSAddrIsDNSMulticast(dstaddr) && (mDNSu32)(m->timenow - m->ExpectUnicastResponse) > (mDNSu32)(mDNSPlatformOneSecond*2)))
+               {
+               mDNSBool ignoredlots = (++NumPktsIgnored > NumPktsAccepted + 10);
+               if (ignoredlots || NumPktsIgnored <= 10)
+                       LogMsg("Ignored apparent spoof mDNS Response with TTL %d from %#-15a:%-5d to %#-15a:%-5d on %p with %2d Q %2d Ans %2d Auth %2d Add",
+                               ttl, srcaddr, mDNSVal16(srcport), dstaddr, mDNSVal16(dstport), InterfaceID,
+                               response->h.numQuestions, response->h.numAnswers, response->h.numAuthorities, response->h.numAdditionals);
+               if (ignoredlots)
+                       LogMsg("WARNING: Have ignored %lu packets out of %lu; this may indicate an error in the platform support layer.",
+                               NumPktsIgnored, NumPktsIgnored + NumPktsAccepted);
+               return;
+               }
+       NumPktsAccepted++;
 
        for (i = 0; i < totalrecords && ptr && ptr < end; i++)
                {
@@ -5696,13 +4658,12 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
 
 mDNSexport void mDNSCoreReceive(mDNS *const m, DNSMessage *const msg, const mDNSu8 *const end,
        const mDNSAddr *const srcaddr, const mDNSIPPort srcport, const mDNSAddr *const dstaddr, const mDNSIPPort dstport,
-       const mDNSInterfaceID InterfaceID, mDNSu8 unusedttl)
+       const mDNSInterfaceID InterfaceID, mDNSu8 ttl)
        {
-       const mDNSu8 StdQ  = kDNSFlag0_QR_Query    | kDNSFlag0_OP_StdQuery;
-       const mDNSu8 StdR  = kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery;
-       const mDNSu8 QR_OP = (mDNSu8)(msg->h.flags.b[0] & kDNSFlag0_QROP_Mask);
-       
-       (void)unusedttl;
+       const mDNSu8 StdQ    = kDNSFlag0_QR_Query    | kDNSFlag0_OP_StdQuery;
+       const mDNSu8 StdR    = kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery;
+       const mDNSu8 UpdateR = kDNSFlag0_OP_Update   | kDNSFlag0_QR_Response;
+       const mDNSu8 QR_OP   = (mDNSu8)(msg->h.flags.b[0] & kDNSFlag0_QROP_Mask);
        
        // Read the integer parts which are in IETF byte-order (MSB first, LSB second)
        mDNSu8 *ptr = (mDNSu8 *)&msg->h.numQuestions;
@@ -5710,17 +4671,25 @@ mDNSexport void mDNSCoreReceive(mDNS *const m, DNSMessage *const msg, const mDNS
        msg->h.numAnswers     = (mDNSu16)((mDNSu16)ptr[2] <<  8 | ptr[3]);
        msg->h.numAuthorities = (mDNSu16)((mDNSu16)ptr[4] <<  8 | ptr[5]);
        msg->h.numAdditionals = (mDNSu16)((mDNSu16)ptr[6] <<  8 | ptr[7]);
-       
+
        if (!m) { LogMsg("mDNSCoreReceive ERROR m is NULL"); return; }
        
        // We use zero addresses and all-ones addresses at various places in the code to indicate special values like "no address"
        // If we accept and try to process a packet with zero or all-ones source address, that could really mess things up
        if (!mDNSAddressIsValid(srcaddr)) { debugf("mDNSCoreReceive ignoring packet from %#a", srcaddr); return; }
+
+       if (dstaddr->type == mDNSAddrType_IPv4 && dstaddr->ip.v4.NotAnInteger != AllDNSLinkGroup.NotAnInteger &&
+               (QR_OP == StdR || QR_OP == UpdateR ) && msg->h.id.NotAnInteger)
+               {
+               uDNS_ReceiveMsg(m, msg, end, srcaddr, srcport, dstaddr, dstport, InterfaceID, ttl);
+               return;
+               }
        
        mDNS_Lock(m);
        if      (QR_OP == StdQ) mDNSCoreReceiveQuery   (m, msg, end, srcaddr, srcport, dstaddr, dstport, InterfaceID);
-       else if (QR_OP == StdR) mDNSCoreReceiveResponse(m, msg, end, srcaddr,          dstaddr,          InterfaceID);
-       else debugf("Unknown DNS packet type %02X%02X (ignored)", msg->h.flags.b[0], msg->h.flags.b[1]);
+       else if (QR_OP == StdR) mDNSCoreReceiveResponse(m, msg, end, srcaddr, srcport, dstaddr, dstport, InterfaceID, ttl);
+       else LogMsg("Unknown DNS packet type %02X%02X from %#-15a:%-5d to %#-15a:%-5d on %p (ignored)",
+               msg->h.flags.b[0], msg->h.flags.b[1], srcaddr, mDNSVal16(srcport), dstaddr, mDNSVal16(dstport), InterfaceID);
 
        // Packet reception often causes a change to the task list:
        // 1. Inbound queries can cause us to need to send responses
@@ -5737,6 +4706,8 @@ mDNSexport void mDNSCoreReceive(mDNS *const m, DNSMessage *const msg, const mDNS
 #pragma mark - Searcher Functions
 #endif
 
+#define SameQTarget(A,B) (mDNSSameAddress(&(A)->Target, &(B)->Target) && (A)->TargetPort.NotAnInteger == (B)->TargetPort.NotAnInteger)
+
 mDNSlocal DNSQuestion *FindDuplicateQuestion(const mDNS *const m, const DNSQuestion *const question)
        {
        DNSQuestion *q;
@@ -5746,6 +4717,7 @@ mDNSlocal DNSQuestion *FindDuplicateQuestion(const mDNS *const m, const DNSQuest
        // further in the list.
        for (q = m->Questions; q && q != question; q=q->next)           // Scan our list of questions
                if (q->InterfaceID == question->InterfaceID &&                  // for another question with the same InterfaceID,
+                       SameQTarget(q, question)                &&                      // and same unicast/multicast target settings
                        q->qtype       == question->qtype       &&                      // type,
                        q->qclass      == question->qclass      &&                      // class,
                        q->qnamehash   == question->qnamehash   &&
@@ -5771,11 +4743,34 @@ mDNSlocal void UpdateQuestionDuplicates(mDNS *const m, const DNSQuestion *const
                        }
        }
 
+#define ValidQuestionTarget(Q) (((Q)->Target.type == mDNSAddrType_IPv4 || (Q)->Target.type == mDNSAddrType_IPv6) && \
+       ((Q)->TargetPort.NotAnInteger == UnicastDNSPort.NotAnInteger || (Q)->TargetPort.NotAnInteger == MulticastDNSPort.NotAnInteger))
+
 mDNSlocal mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const question)
        {
 #if TEST_LOCALONLY_FOR_EVERYTHING
-       question->InterfaceID = (mDNSInterfaceID)~0;
+       question->InterfaceID = mDNSInterface_LocalOnly;
 #endif
+
+       if (question->Target.type && !ValidQuestionTarget(question))
+               {
+               LogMsg("Warning! Target.type = %d port = %u (Client forgot to initialize before calling mDNS_StartQuery?)",
+                       question->Target.type, mDNSVal16(question->TargetPort));
+               question->Target.type = mDNSAddrType_None;
+               }
+
+       // If the client has specified an explicit InterfaceID,
+       // then we do a multicast query on that interface, even for unicast domains.
+    if (question->InterfaceID || IsLocalDomain(&question->qname))
+       question->uDNS_info.id = zeroID;
+    else return uDNS_StartQuery(m, question);
+
+       // The special interface ID "-2" means
+       // "do this query via multicast on all interfaces, even if it's apparently a unicast domain"
+       // After it's served its purpose by preventing a unicast query above, we now set it to mDNSInterface_Any.
+       if (question->InterfaceID == mDNSInterface_ForceMCast)
+               question->InterfaceID = mDNSInterface_Any;
+
        if (m->rrcache_size == 0)       // Can't do queries if we have no cache space allocated
                return(mStatus_NoCache);
        else
@@ -5783,7 +4778,7 @@ mDNSlocal mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const que
                int i;
                // Note: It important that new questions are appended at the *end* of the list, not prepended at the start
                DNSQuestion **q = &m->Questions;
-               if (question->InterfaceID == ((mDNSInterfaceID)~0)) q = &m->LocalOnlyQuestions;
+               if (question->InterfaceID == mDNSInterface_LocalOnly) q = &m->LocalOnlyQuestions;
                while (*q && *q != question) q=&(*q)->next;
 
                if (*q)
@@ -5794,7 +4789,7 @@ mDNSlocal mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const que
                        }
 
                // If this question is referencing a specific interface, make sure it exists
-               if (question->InterfaceID && question->InterfaceID != ((mDNSInterfaceID)~0))
+               if (question->InterfaceID && question->InterfaceID != mDNSInterface_LocalOnly)
                        {
                        NetworkInterfaceInfo *intf;
                        for (intf = m->HostInterfaces; intf; intf = intf->next)
@@ -5802,7 +4797,7 @@ mDNSlocal mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const que
                        if (!intf)
                                {
                                debugf("mDNS_StartQuery_internal: Question %##s InterfaceID %p not found", question->qname.c, question->InterfaceID);
-                               return(mStatus_BadReferenceErr);
+                               return(mStatus_BadInterfaceErr);
                                }
                        }
 
@@ -5843,7 +4838,7 @@ mDNSlocal mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const que
                                question->qname.c, DNSTypeName(question->qtype), question->InterfaceID, question, question->DuplicateOf);
 
                *q = question;
-               if (question->InterfaceID == ((mDNSInterfaceID)~0))
+               if (question->InterfaceID == mDNSInterface_LocalOnly)
                        {
                        if (!m->NewLocalOnlyQuestions) m->NewLocalOnlyQuestions = question;
                        }
@@ -5861,7 +4856,10 @@ mDNSlocal mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const ques
        {
        CacheRecord *rr;
        DNSQuestion **q = &m->Questions;
-       if (question->InterfaceID == ((mDNSInterfaceID)~0)) q = &m->LocalOnlyQuestions;
+
+    if (IsActiveUnicastQuery(question, &m->uDNS_info)) return uDNS_StopQuery(m, question);
+
+       if (question->InterfaceID == mDNSInterface_LocalOnly) q = &m->LocalOnlyQuestions;
        while (*q && *q != question) q=&(*q)->next;
        if (*q) *q = (*q)->next;
        else
@@ -5958,14 +4956,27 @@ mDNSexport mStatus mDNS_StartBrowse(mDNS *const m, DNSQuestion *const question,
        const domainname *const srv, const domainname *const domain,
        const mDNSInterfaceID InterfaceID, mDNSQuestionCallback *Callback, void *Context)
        {
-       question->ThisQInterval     = -1;                               // Indicate that query is not yet active
-       question->InterfaceID       = InterfaceID;
-       question->qtype             = kDNSType_PTR;
-       question->qclass            = kDNSClass_IN;
-       question->QuestionCallback  = Callback;
-       question->QuestionContext   = Context;
+       question->InterfaceID      = InterfaceID;
+       question->Target           = zeroAddr;
+       question->qtype            = kDNSType_PTR;
+       question->qclass           = kDNSClass_IN;
+       question->QuestionCallback = Callback;
+       question->QuestionContext  = Context;
        if (!ConstructServiceName(&question->qname, mDNSNULL, srv, domain)) return(mStatus_BadParamErr);
-       return(mDNS_StartQuery(m, question));
+
+       // If the client has specified an explicit InterfaceID,
+       // then we do a multicast query on that interface, even for unicast domains.
+    if (question->InterfaceID || IsLocalDomain(&question->qname))
+       {
+               question->LongLived = mDNSfalse;
+               question->uDNS_info.id = zeroID;
+               return(mDNS_StartQuery(m, question));
+               }
+       else
+               {
+               question->LongLived = mDNStrue;
+               return uDNS_StartQuery(m, question);
+               }
        }
 
 mDNSlocal void FoundServiceInfoSRV(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
@@ -6020,7 +5031,7 @@ mDNSlocal void FoundServiceInfoSRV(mDNS *const m, DNSQuestion *question, const R
                if (++query->Answers >= 100)
                        debugf("**** WARNING **** Have given %lu answers for %##s (SRV) %##s %u",
                                query->Answers, query->qSRV.qname.c, answer->rdata->u.srv.target.c,
-                               ((mDNSu16)answer->rdata->u.srv.port.b[0] << 8) | answer->rdata->u.srv.port.b[1]);
+                               mDNSVal16(answer->rdata->u.srv.port));
                query->ServiceInfoQueryCallback(m, query);
                }
        // CAUTION: MUST NOT do anything more with query after calling query->Callback(), because the client's
@@ -6036,6 +5047,7 @@ mDNSlocal void FoundServiceInfoTXT(mDNS *const m, DNSQuestion *question, const R
 
        query->GotTXT       = mDNStrue;
        query->info->TXTlen = answer->rdlength;
+       query->info->TXTinfo[0] = 0;            // In case answer->rdlength is zero
        mDNSPlatformMemCopy(answer->rdata->u.txt.c, query->info->TXTinfo, answer->rdlength);
 
        verbosedebugf("FoundServiceInfoTXT: %##s GotADD=%d", query->info->name.c, query->GotADD);
@@ -6102,32 +5114,36 @@ mDNSexport mStatus mDNS_StartResolveService(mDNS *const m,
        mStatus status;
        mDNS_Lock(m);
 
-       query->qSRV.ThisQInterval       = -1;           // This question not yet in the question list
+       query->qSRV.ThisQInterval       = -1;           // So that mDNS_StopResolveService() knows whether to cancel this question
        query->qSRV.InterfaceID         = info->InterfaceID;
+       query->qSRV.Target              = zeroAddr;
        AssignDomainName(query->qSRV.qname, info->name);
        query->qSRV.qtype               = kDNSType_SRV;
        query->qSRV.qclass              = kDNSClass_IN;
        query->qSRV.QuestionCallback    = FoundServiceInfoSRV;
        query->qSRV.QuestionContext     = query;
 
-       query->qTXT.ThisQInterval       = -1;           // This question not yet in the question list
+       query->qTXT.ThisQInterval       = -1;           // So that mDNS_StopResolveService() knows whether to cancel this question
        query->qTXT.InterfaceID         = info->InterfaceID;
+       query->qTXT.Target              = zeroAddr;
        AssignDomainName(query->qTXT.qname, info->name);
        query->qTXT.qtype               = kDNSType_TXT;
        query->qTXT.qclass              = kDNSClass_IN;
        query->qTXT.QuestionCallback    = FoundServiceInfoTXT;
        query->qTXT.QuestionContext     = query;
 
-       query->qAv4.ThisQInterval       = -1;           // This question not yet in the question list
+       query->qAv4.ThisQInterval       = -1;           // So that mDNS_StopResolveService() knows whether to cancel this question
        query->qAv4.InterfaceID         = info->InterfaceID;
+       query->qAv4.Target              = zeroAddr;
        query->qAv4.qname.c[0]          = 0;
        query->qAv4.qtype               = kDNSType_A;
        query->qAv4.qclass              = kDNSClass_IN;
        query->qAv4.QuestionCallback    = FoundServiceInfo;
        query->qAv4.QuestionContext     = query;
 
-       query->qAv6.ThisQInterval       = -1;           // This question not yet in the question list
+       query->qAv6.ThisQInterval       = -1;           // So that mDNS_StopResolveService() knows whether to cancel this question
        query->qAv6.InterfaceID         = info->InterfaceID;
+       query->qAv6.Target              = zeroAddr;
        query->qAv6.qname.c[0]          = 0;
        query->qAv6.qtype               = kDNSType_AAAA;
        query->qAv6.qclass              = kDNSClass_IN;
@@ -6160,27 +5176,31 @@ mDNSexport mStatus mDNS_StartResolveService(mDNS *const m,
 mDNSexport void    mDNS_StopResolveService (mDNS *const m, ServiceInfoQuery *query)
        {
        mDNS_Lock(m);
-       if (query->qSRV.ThisQInterval >= 0) mDNS_StopQuery_internal(m, &query->qSRV);
-       if (query->qTXT.ThisQInterval >= 0) mDNS_StopQuery_internal(m, &query->qTXT);
-       if (query->qAv4.ThisQInterval >= 0) mDNS_StopQuery_internal(m, &query->qAv4);
-       if (query->qAv6.ThisQInterval >= 0) mDNS_StopQuery_internal(m, &query->qAv6);
+       if (query->qSRV.ThisQInterval >= 0 || IsActiveUnicastQuery(&query->qSRV, &m->uDNS_info))
+               mDNS_StopQuery_internal(m, &query->qSRV);
+       if (query->qTXT.ThisQInterval >= 0 || IsActiveUnicastQuery(&query->qTXT, &m->uDNS_info))
+               mDNS_StopQuery_internal(m, &query->qTXT);
+       if (query->qAv4.ThisQInterval >= 0 || IsActiveUnicastQuery(&query->qAv4, &m->uDNS_info))
+               mDNS_StopQuery_internal(m, &query->qAv4);
+       if (query->qAv6.ThisQInterval >= 0 || IsActiveUnicastQuery(&query->qAv6, &m->uDNS_info))
+               mDNS_StopQuery_internal(m, &query->qAv6);
        mDNS_Unlock(m);
        }
 
-mDNSexport mStatus mDNS_GetDomains(mDNS *const m, DNSQuestion *const question, mDNS_DomainType DomainType,
+mDNSexport mStatus mDNS_GetDomains(mDNS *const m, DNSQuestion *const question, mDNS_DomainType DomainType, const domainname *dom,
        const mDNSInterfaceID InterfaceID, mDNSQuestionCallback *Callback, void *Context)
        {
-       MakeDomainNameFromDNSNameString(&question->qname, mDNS_DomainTypeNames[DomainType]);
        question->InterfaceID      = InterfaceID;
+       question->Target           = zeroAddr;
        question->qtype            = kDNSType_PTR;
        question->qclass           = kDNSClass_IN;
        question->QuestionCallback = Callback;
        question->QuestionContext  = Context;
-
-       // No sense doing this until we actually support unicast query/update
-       //return(mDNS_StartQuery(m, question));
-       (void)m; // Unused
-       return(mStatus_NoError);
+       if (DomainType > mDNS_DomainTypeRegistrationDefault) return(mStatus_BadParamErr);
+       if (!MakeDomainNameFromDNSNameString(&question->qname, mDNS_DomainTypeNames[DomainType])) return(mStatus_BadParamErr);
+       if (!dom) dom = (const domainname *)"\x5local";
+       if (!AppendDomainName(&question->qname, dom)) return(mStatus_BadParamErr);
+       return(mDNS_StartQuery(m, question));
        }
 
 // ***************************************************************************
@@ -6246,6 +5266,13 @@ mDNSexport mStatus mDNS_Update(mDNS *const m, AuthRecord *const rr, mDNSu32 newt
        const mDNSu16 newrdlength,
        RData *const newrdata, mDNSRecordUpdateCallback *Callback)
        {
+       
+       if (!rr->resrec.InterfaceID && !IsLocalDomain(&rr->resrec.name))
+               {
+               LogMsg("mDNS_Update: Not implemented for unicast DNS");
+               return mStatus_UnsupportedErr;
+               }
+
        if (!ValidateRData(rr->resrec.rrtype, newrdlength, newrdata))
                { LogMsg("Attempt to update record with invalid rdata: %s", GetRRDisplayString_rdb(m, &rr->resrec, &newrdata->u)); return(mStatus_Invalid); }
 
@@ -6263,26 +5290,43 @@ mDNSexport mStatus mDNS_Update(mDNS *const m, AuthRecord *const rr, mDNSu32 newt
                if (rr->UpdateCallback)
                        rr->UpdateCallback(m, rr, n);   // ...and let the client free this memory, if necessary
                }
-       
-       if (rr->AnnounceCount < ReannounceCount)
-               rr->AnnounceCount = ReannounceCount;
-       rr->ThisAPInterval       = DefaultAPIntervalForRecordType(rr->resrec.RecordType);
-       InitializeLastAPTime(m, rr);
+
        rr->NewRData             = newrdata;
        rr->newrdlength          = newrdlength;
        rr->UpdateCallback       = Callback;
-       if (!rr->UpdateBlocked && rr->UpdateCredits) rr->UpdateCredits--;
-       if (!rr->NextUpdateCredit) rr->NextUpdateCredit = (m->timenow + mDNSPlatformOneSecond * 60) | 1;
-       if (rr->AnnounceCount > rr->UpdateCredits + 1) rr->AnnounceCount = (mDNSu8)(rr->UpdateCredits + 1);
-       if (rr->UpdateCredits <= 5)
+       
+       if (rr->resrec.rroriginalttl == newttl && rr->resrec.rdlength == newrdlength && mDNSPlatformMemSame(rr->resrec.rdata->u.data, newrdata->u.data, newrdlength))
+               CompleteRDataUpdate(m, rr);
+       else
                {
-               mDNSs32 delay = 1 << (5 - rr->UpdateCredits);
-               if (!rr->UpdateBlocked) rr->UpdateBlocked = (m->timenow + delay * mDNSPlatformOneSecond) | 1;
-               rr->LastAPTime = rr->UpdateBlocked;
-               rr->ThisAPInterval *= 4;
-               LogMsg("Excessive update rate for %##s; delaying announcement by %d seconds", rr->resrec.name.c, delay);
+               domainlabel name;
+               domainname type, domain;
+               DeconstructServiceName(&rr->resrec.name, &name, &type, &domain);
+               if (rr->AnnounceCount < ReannounceCount)
+                       rr->AnnounceCount = ReannounceCount;
+               // iChat often does suprious record updates where no data has changed. For the _presence service type, using
+               // name/value pairs, the mDNSPlatformMemSame() check above catches this and correctly suppresses the wasteful
+               // update. For the _ichat service type, the XML encoding introduces spurious noise differences into the data
+               // even though there's no actual semantic change, so the mDNSPlatformMemSame() check doesn't help us.
+               // To work around this, we simply unilaterally limit all legacy _ichat-type updates to a single announcement.
+               if (SameDomainLabel(type.c, (mDNSu8*)"\x6_ichat")) rr->AnnounceCount = 1;
+               rr->ThisAPInterval       = DefaultAPIntervalForRecordType(rr->resrec.RecordType);
+               InitializeLastAPTime(m, rr);
+               while (rr->NextUpdateCredit && m->timenow - rr->NextUpdateCredit >= 0) GrantUpdateCredit(rr);
+               if (!rr->UpdateBlocked && rr->UpdateCredits) rr->UpdateCredits--;
+               if (!rr->NextUpdateCredit) rr->NextUpdateCredit = (m->timenow + kUpdateCreditRefreshInterval) | 1;
+               if (rr->AnnounceCount > rr->UpdateCredits + 1) rr->AnnounceCount = (mDNSu8)(rr->UpdateCredits + 1);
+               if (rr->UpdateCredits <= 5)
+                       {
+                       mDNSs32 delay = 1 << (5 - rr->UpdateCredits);
+                       if (!rr->UpdateBlocked) rr->UpdateBlocked = (m->timenow + delay * mDNSPlatformOneSecond) | 1;
+                       rr->LastAPTime = rr->UpdateBlocked;
+                       rr->ThisAPInterval *= 4;
+                       LogMsg("Excessive update rate for %##s; delaying announcement by %d second%s", rr->resrec.name.c, delay, delay > 1 ? "s" : "");
+                       }
+               rr->resrec.rroriginalttl = newttl;
                }
-       rr->resrec.rroriginalttl = newttl;
+
        mDNS_Unlock(m);
        return(mStatus_NoError);
        }
@@ -6299,7 +5343,7 @@ mDNSexport mStatus mDNS_Deregister(mDNS *const m, AuthRecord *const rr)
        return(status);
        }
 
-mDNSlocal void HostNameCallback(mDNS *const m, AuthRecord *const rr, mStatus result);
+mDNSexport void mDNS_HostNameCallback(mDNS *const m, AuthRecord *const rr, mStatus result);
 
 mDNSlocal NetworkInterfaceInfo *FindFirstAdvertisedInterface(mDNS *const m)
        {
@@ -6309,13 +5353,15 @@ mDNSlocal NetworkInterfaceInfo *FindFirstAdvertisedInterface(mDNS *const m)
        return(intf);
        }
 
-mDNSlocal void mDNS_AdvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set)
+mDNSlocal void AdvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set)
        {
        char buffer[256];
        NetworkInterfaceInfo *primary = FindFirstAdvertisedInterface(m);
        if (!primary) primary = set; // If no existing advertised interface, this new NetworkInterfaceInfo becomes our new primary
-       
-       mDNS_SetupResourceRecord(&set->RR_A,     mDNSNULL, set->InterfaceID, kDNSType_A,     kDefaultTTLforUnique, kDNSRecordTypeUnique,      HostNameCallback, set);
+
+       // Send dynamic update for non-linklocal IPv4 Addresses
+       uDNS_AdvertiseInterface(m, set);
+       mDNS_SetupResourceRecord(&set->RR_A,     mDNSNULL, set->InterfaceID, kDNSType_A,     kDefaultTTLforUnique, kDNSRecordTypeUnique,      mDNS_HostNameCallback, set);
        mDNS_SetupResourceRecord(&set->RR_PTR,   mDNSNULL, set->InterfaceID, kDNSType_PTR,   kDefaultTTLforUnique, kDNSRecordTypeKnownUnique, mDNSNULL, mDNSNULL);
        mDNS_SetupResourceRecord(&set->RR_HINFO, mDNSNULL, set->InterfaceID, kDNSType_HINFO, kDefaultTTLforUnique, kDNSRecordTypeUnique,      mDNSNULL, mDNSNULL);
 
@@ -6371,10 +5417,11 @@ mDNSlocal void mDNS_AdvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set)
                }
        }
 
-mDNSlocal void mDNS_DeadvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set)
+mDNSlocal void DeadvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set)
        {
        NetworkInterfaceInfo *intf;
-       // If we still have address records referring to this one, update them
+       
+    // If we still have address records referring to this one, update them
        NetworkInterfaceInfo *primary = FindFirstAdvertisedInterface(m);
        AuthRecord *A = primary ? &primary->RR_A : mDNSNULL;
        for (intf = m->HostInterfaces; intf; intf = intf->next)
@@ -6382,7 +5429,7 @@ mDNSlocal void mDNS_DeadvertiseInterface(mDNS *const m, NetworkInterfaceInfo *se
                        intf->RR_A.RRSet = A;
 
        // Unregister these records.
-       // When doing the mDNS_Close processing, we first call mDNS_DeadvertiseInterface for each interface, so by the time the platform
+       // When doing the mDNS_Close 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().
@@ -6391,48 +5438,68 @@ mDNSlocal void mDNS_DeadvertiseInterface(mDNS *const m, NetworkInterfaceInfo *se
        if (set->RR_HINFO.resrec.RecordType) mDNS_Deregister_internal(m, &set->RR_HINFO, mDNS_Dereg_normal);
        }
 
-mDNSexport void mDNS_GenerateFQDN(mDNS *const m)
+mDNSlocal void GenerateFQDN(mDNS *const m, const char *domain, mDNSBool local)
        {
        domainname newname;
        mDNS_Lock(m);
 
        newname.c[0] = 0;
-       if (!AppendDomainLabel(&newname, &m->hostlabel))  LogMsg("ERROR! Cannot create dot-local hostname");
-       if (!AppendLiteralLabelString(&newname, "local")) LogMsg("ERROR! Cannot create dot-local hostname");
-       if (!SameDomainName(&m->hostname, &newname))
+       if (!AppendDomainLabel(&newname, &m->hostlabel))  LogMsg("ERROR: GenerateFQDN:  Cannot create hostname");
+       if (!AppendDNSNameString(&newname, domain)) LogMsg("ERROR: GenerateFQDN:  Cannot create hostname");
+               
+       if ((local && !SameDomainName(&m->hostname, &newname)) ||
+               (!local && !SameDomainName(&m->uDNS_info.hostname, &newname)))
                {
                NetworkInterfaceInfo *intf;
                AuthRecord *rr;
 
-               m->hostname = newname;
+               if (local) m->hostname = newname;
+               else       m->uDNS_info.hostname = newname;
 
+               //!!!KRS for unicast, we can do the deadvertisements/new adverts in the same update message
                // 1. Stop advertising our address records on all interfaces
                for (intf = m->HostInterfaces; intf; intf = intf->next)
-                       if (intf->Advertise) mDNS_DeadvertiseInterface(m, intf);
+                       if (intf->Advertise)
+                               local ? DeadvertiseInterface(m, intf) : uDNS_DeadvertiseInterface(m, intf);
 
                // 2. Start advertising our address records using the new name
                for (intf = m->HostInterfaces; intf; intf = intf->next)
-                       if (intf->Advertise) mDNS_AdvertiseInterface(m, intf);
+                       if (intf->Advertise)
+                               local ? AdvertiseInterface(m, intf) : uDNS_AdvertiseInterface(m, intf);
 
                // 3. Make sure that any SRV records (and the like) that reference our
                // host name in their rdata get updated to reference this new host name
-               for (rr = m->ResourceRecords;  rr; rr=rr->next) if (rr->HostTarget) SetTargetToHostName(m, rr);
-               for (rr = m->DuplicateRecords; rr; rr=rr->next) if (rr->HostTarget) SetTargetToHostName(m, rr);
+               if (local)
+                       {
+                       for (rr = m->ResourceRecords;  rr; rr=rr->next) if (rr->HostTarget) SetTargetToHostName(m, rr);
+                       for (rr = m->DuplicateRecords; rr; rr=rr->next) if (rr->HostTarget) SetTargetToHostName(m, rr);
+                       }
+               else uDNS_UpdateServiceTargets(m);
                }
+               mDNS_Unlock(m);
+       }
 
-       mDNS_Unlock(m);
+mDNSexport void mDNS_GenerateFQDN(mDNS *const m)
+       {
+       GenerateFQDN(m, "local.", mDNStrue);
        }
 
-mDNSlocal void HostNameCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
+mDNSexport void mDNS_GenerateGlobalFQDN(mDNS *const m)
        {
-       (void)rr;       // Unused parameter
+    if (!m->uDNS_info.NameRegDomain[0]) return;
+    GenerateFQDN(m, m->uDNS_info.NameRegDomain, mDNSfalse);
+       }
 
+mDNSexport void mDNS_HostNameCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
+       {
+       (void)rr;       // Unused parameter
+       
        #if MDNS_DEBUGMSGS
                {
                char *msg = "Unknown result";
                if      (result == mStatus_NoError)      msg = "Name registered";
                else if (result == mStatus_NameConflict) msg = "Name conflict";
-               debugf("HostNameCallback: %##s (%s) %s (%ld)", rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype), msg, result);
+               debugf("mDNS_HostNameCallback: %##s (%s) %s (%ld)", rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype), msg, result);
                }
        #endif
 
@@ -6440,24 +5507,45 @@ mDNSlocal void HostNameCallback(mDNS *const m, AuthRecord *const rr, mStatus res
                {
                // Notify the client that the host name is successfully registered
                if (m->MainCallback)
+                       {
+                       m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
                        m->MainCallback(m, result);
+                       m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
+                       }
                }
        else if (result == mStatus_NameConflict)
                {
                domainlabel oldlabel = m->hostlabel;
-
+               mDNSBool local = (IsLocalDomain(&rr->resrec.name) || rr->resrec.InterfaceID);
                // 1. First give the client callback a chance to pick a new name
                if (m->MainCallback)
+                       {
+                       m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
                        m->MainCallback(m, mStatus_NameConflict);
+                       m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
+                       }
 
                // 2. If the client callback didn't do it, add (or increment) an index ourselves
                if (SameDomainLabel(m->hostlabel.c, oldlabel.c))
                        IncrementLabelSuffix(&m->hostlabel, mDNSfalse);
-
+               
                // 3. Generate the FQDNs from the hostlabel,
                // and make sure all SRV records, etc., are updated to reference our new hostname
-               mDNS_GenerateFQDN(m);
+               if (!local)
+                       {
+                       //!!!KRS clean this up
+                       char regdomain[MAX_ESCAPED_DOMAIN_NAME];
+                       ConvertDomainNameToCString_unescaped((domainname *)(rr->resrec.name.c + rr->resrec.name.c[0] + 1), regdomain);
+                       mDNS_GenerateGlobalFQDN(m);
+                       LogMsg("Host Name %s.%s already in use; new name %s.%s selected for this host", oldlabel.c, regdomain, m->hostlabel.c, regdomain);
+                       }
+               else
+                       {
+                       mDNS_GenerateFQDN(m);
+                       LogMsg("Link-Local Host Name %#s.local. already in use; new name %#s.local. selected for this host.", oldlabel.c, m->hostlabel.c);
+                       }
                }
+       else LogMsg("mDNS_HostNameCallback: Unknown error %d for registration of record %s", result,  rr->resrec.name.c);
        }
 
 mDNSlocal void UpdateInterfaceProtocols(mDNS *const m, NetworkInterfaceInfo *active)
@@ -6468,8 +5556,8 @@ mDNSlocal void UpdateInterfaceProtocols(mDNS *const m, NetworkInterfaceInfo *act
        for (intf = m->HostInterfaces; intf; intf = intf->next)
                if (intf->InterfaceID == active->InterfaceID)
                        {
-                       if (intf->ip.type == mDNSAddrType_IPv4 && intf->TxAndRx) active->IPv4Available = mDNStrue;
-                       if (intf->ip.type == mDNSAddrType_IPv6 && intf->TxAndRx) active->IPv6Available = mDNStrue;
+                       if (intf->ip.type == mDNSAddrType_IPv4 && intf->McastTxRx) active->IPv4Available = mDNStrue;
+                       if (intf->ip.type == mDNSAddrType_IPv6 && intf->McastTxRx) active->IPv6Available = mDNStrue;
                        }
        }
 
@@ -6481,8 +5569,8 @@ mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *s
        
        // Assume this interface will be active
        set->InterfaceActive = mDNStrue;
-       set->IPv4Available   = (set->ip.type == mDNSAddrType_IPv4 && set->TxAndRx);
-       set->IPv6Available   = (set->ip.type == mDNSAddrType_IPv6 && set->TxAndRx);
+       set->IPv4Available   = (set->ip.type == mDNSAddrType_IPv4 && set->McastTxRx);
+       set->IPv6Available   = (set->ip.type == mDNSAddrType_IPv6 && set->McastTxRx);
 
        while (*p)
                {
@@ -6498,8 +5586,8 @@ mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *s
                        {
                        set->InterfaceActive = mDNSfalse;
                        if (set->ip.type == (*p)->ip.type) FirstOfType = mDNSfalse;
-                       if (set->ip.type == mDNSAddrType_IPv4 && set->TxAndRx) (*p)->IPv4Available = mDNStrue;
-                       if (set->ip.type == mDNSAddrType_IPv6 && set->TxAndRx) (*p)->IPv6Available = mDNStrue;
+                       if (set->ip.type == mDNSAddrType_IPv4 && set->McastTxRx) (*p)->IPv4Available = mDNStrue;
+                       if (set->ip.type == mDNSAddrType_IPv6 && set->McastTxRx) (*p)->IPv6Available = mDNStrue;
                        }
 
                p=&(*p)->next;
@@ -6512,7 +5600,7 @@ mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *s
                set->InterfaceActive ?
                        "not represented in list; marking active and retriggering queries" :
                        "already represented in list; marking inactive for now");
-
+       
        // In some versions of OS X the IPv6 address remains on an interface even when the interface is turned off,
        // giving the false impression that there's an active representative of this interface when there really isn't.
        // Therefore, when registering an interface, we want to re-trigger our questions and re-probe our Resource Records,
@@ -6549,7 +5637,7 @@ mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *s
                }
 
        if (set->Advertise)
-               mDNS_AdvertiseInterface(m, set);
+               AdvertiseInterface(m, set);
 
        mDNS_Unlock(m);
        return(mStatus_NoError);
@@ -6630,8 +5718,10 @@ mDNSexport void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *se
 
        // If we were advertising on this interface, deregister those address and reverse-lookup records now
        if (set->Advertise)
-               mDNS_DeadvertiseInterface(m, set);
-
+               {
+               DeadvertiseInterface(m, set);
+               uDNS_DeadvertiseInterface(m, set);
+               }
        // 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,
        // giving the false impression that there's an active representative of this interface when there really isn't.
@@ -6676,7 +5766,7 @@ mDNSlocal void ServiceCallback(mDNS *const m, AuthRecord *const rr, mStatus resu
        
        if (result == mStatus_MemFree)
                {
-               // If the PTR record or any of the subtype PTR records are still in the process of deregistering,
+               // If the PTR record or any of the subtype PTR record are still in the process of deregistering,
                // don't pass on the NameConflict/MemFree message until every record is finished cleaning up.
                mDNSu32 i;
                if (sr->RR_PTR.resrec.RecordType != kDNSRecordTypeUnregistered) return;
@@ -6695,7 +5785,7 @@ mDNSlocal void ServiceCallback(mDNS *const m, AuthRecord *const rr, mStatus resu
 
 // 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. "_printer._tcp.")
+// Type is service type (e.g. "_ipp._tcp.")
 // Domain is fully qualified domain name (i.e. ending with a null label)
 // We always register a TXT, even if it is empty (so that clients are not
 // left waiting forever looking for a nonexistent record.)
@@ -6724,7 +5814,7 @@ mDNSexport mStatus mDNS_RegisterService(mDNS *const m, ServiceRecordSet *sr,
        mDNS_SetupResourceRecord(&sr->RR_PTR, mDNSNULL, InterfaceID, kDNSType_PTR, kDefaultTTLforShared, kDNSRecordTypeShared,   ServiceCallback, sr);
        mDNS_SetupResourceRecord(&sr->RR_SRV, mDNSNULL, InterfaceID, kDNSType_SRV, kDefaultTTLforUnique, kDNSRecordTypeUnique,   ServiceCallback, sr);
        mDNS_SetupResourceRecord(&sr->RR_TXT, mDNSNULL, InterfaceID, kDNSType_TXT, kDefaultTTLforUnique, kDNSRecordTypeUnique,   ServiceCallback, sr);
-       
+
        // If the client is registering an oversized TXT record,
        // it is the client's responsibility to alloate a ServiceRecordSet structure that is large enough for it
        if (sr->RR_TXT.resrec.rdata->MaxRDLength < txtlen)
@@ -6753,12 +5843,9 @@ mDNSexport mStatus mDNS_RegisterService(mDNS *const m, ServiceRecordSet *sr,
        // already set the first label of the record name to the subtype being registered
        for (i=0; i<NumSubTypes; i++)
                {
-               domainname st;
-               AssignDomainName(st, sr->SubTypes[i].resrec.name);
-               st.c[1+st.c[0]] = 0;                    // Only want the first label, not the whole FQDN (particularly for mDNS_RenameAndReregisterService())
-               AppendDomainName(&st, type);
+               domainlabel s = *(domainlabel*)&sr->SubTypes[i].resrec.name;
                mDNS_SetupResourceRecord(&sr->SubTypes[i], mDNSNULL, InterfaceID, kDNSType_PTR, kDefaultTTLforShared, kDNSRecordTypeShared, ServiceCallback, sr);
-               if (ConstructServiceName(&sr->SubTypes[i].resrec.name, mDNSNULL, &st, domain) == mDNSNULL) return(mStatus_BadParamErr);
+               if (ConstructServiceName(&sr->SubTypes[i].resrec.name, &s, type, domain) == mDNSNULL) return(mStatus_BadParamErr);
                AssignDomainName(sr->SubTypes[i].resrec.rdata->u.name, sr->RR_SRV.resrec.name);
                sr->SubTypes[i].Additional1 = &sr->RR_SRV;
                sr->SubTypes[i].Additional2 = &sr->RR_TXT;
@@ -6771,7 +5858,7 @@ mDNSexport mStatus mDNS_RegisterService(mDNS *const m, ServiceRecordSet *sr,
 
        // Setting HostTarget tells DNS that the target of this SRV is to be automatically kept in sync with our host name
        if (sr->Host.c[0]) AssignDomainName(sr->RR_SRV.resrec.rdata->u.srv.target, sr->Host);
-       else sr->RR_SRV.HostTarget = mDNStrue;
+       else { sr->RR_SRV.HostTarget = mDNStrue; sr->RR_SRV.resrec.rdata->u.srv.target.c[0] = '\0'; }
 
        // 4. Set up the TXT record rdata,
        // and set DependentOn because we're depending on the SRV record to find and resolve conflicts for us
@@ -6784,6 +5871,11 @@ mDNSexport mStatus mDNS_RegisterService(mDNS *const m, ServiceRecordSet *sr,
                }
        sr->RR_TXT.DependentOn = &sr->RR_SRV;
 
+       // If the client has specified an explicit InterfaceID,
+       // then we do a multicast registration  on that interface, even for unicast domains.
+    if (!InterfaceID && !IsLocalDomain(&sr->RR_SRV.resrec.name))
+               return uDNS_RegisterService(m, sr);
+
        mDNS_Lock(m);
        err = mDNS_Register_internal(m, &sr->RR_SRV);
        if (!err) err = mDNS_Register_internal(m, &sr->RR_TXT);
@@ -6795,8 +5887,9 @@ mDNSexport mStatus mDNS_RegisterService(mDNS *const m, ServiceRecordSet *sr,
        if (!err) err = mDNS_Register_internal(m, &sr->RR_ADV);
        for (i=0; i<NumSubTypes; i++) if (!err) err = mDNS_Register_internal(m, &sr->SubTypes[i]);
        if (!err) err = mDNS_Register_internal(m, &sr->RR_PTR);
-       mDNS_Unlock(m);
 
+       mDNS_Unlock(m);
+       
        if (err) mDNS_DeregisterService(m, sr);
        return(err);
        }
@@ -6804,8 +5897,17 @@ mDNSexport mStatus mDNS_RegisterService(mDNS *const m, ServiceRecordSet *sr,
 mDNSexport mStatus mDNS_AddRecordToService(mDNS *const m, ServiceRecordSet *sr,
        ExtraResourceRecord *extra, RData *rdata, mDNSu32 ttl)
        {
-       mStatus result = mStatus_UnknownErr;
-       ExtraResourceRecord **e = &sr->Extras;
+       ExtraResourceRecord **e;
+       mStatus status;
+
+       if (!sr->RR_SRV.resrec.InterfaceID && !IsLocalDomain(&sr->RR_SRV.resrec.name))
+               {
+               LogMsg("mDNS_AddRecordToService: Not implemented for unicast DNS");
+               return mStatus_UnsupportedErr;
+               }
+
+       mDNS_Lock(m);
+       e = &sr->Extras;
        while (*e) e = &(*e)->next;
 
        // If TTL is unspecified, make it the same as the service's TXT and SRV default
@@ -6818,42 +5920,59 @@ mDNSexport mStatus mDNS_AddRecordToService(mDNS *const m, ServiceRecordSet *sr,
        
        debugf("mDNS_AddRecordToService adding record to %##s", extra->r.resrec.name.c);
        
-       result = mDNS_Register(m, &extra->r);
-       if (!result) *e = extra;
-       return result;
+       status = mDNS_Register_internal(m, &extra->r);
+       if (status == mStatus_NoError) *e = extra;
+       mDNS_Unlock(m);
+       return(status);
        }
 
 mDNSexport mStatus mDNS_RemoveRecordFromService(mDNS *const m, ServiceRecordSet *sr, ExtraResourceRecord *extra)
        {
-       ExtraResourceRecord **e = &sr->Extras;
+       ExtraResourceRecord **e;
+       mStatus status;
+
+       if (!sr->RR_SRV.resrec.InterfaceID && !IsLocalDomain(&sr->RR_SRV.resrec.name))
+               {
+               LogMsg("mDNS_AddRecordToService: Not implemented for unicast DNS");
+               return mStatus_UnsupportedErr;
+               }
+
+       mDNS_Lock(m);
+       e = &sr->Extras;
        while (*e && *e != extra) e = &(*e)->next;
        if (!*e)
                {
                debugf("mDNS_RemoveRecordFromService failed to remove record from %##s", extra->r.resrec.name.c);
-               return(mStatus_BadReferenceErr);
+               status = mStatus_BadReferenceErr;
                }
-
-       debugf("mDNS_RemoveRecordFromService removing record from %##s", extra->r.resrec.name.c);
-       
-       *e = (*e)->next;
-       return(mDNS_Deregister(m, &extra->r));
+       else
+               {
+               debugf("mDNS_RemoveRecordFromService removing record from %##s", extra->r.resrec.name.c);
+               *e = (*e)->next;
+               status = mDNS_Deregister_internal(m, &extra->r, mDNS_Dereg_normal);
+               }
+       mDNS_Unlock(m);
+       return(status);
        }
 
 mDNSexport mStatus mDNS_RenameAndReregisterService(mDNS *const m, ServiceRecordSet *const sr, const domainlabel *newname)
        {
-       domainlabel name;
+       // NOTE: Don't need to use mDNS_Lock(m) here, because this code is just using public routines
+       // mDNS_RegisterService() and mDNS_AddRecordToService(), which do the right locking internally.
+       domainlabel name1, name2;
        domainname type, domain;
        domainname *host = mDNSNULL;
        ExtraResourceRecord *extras = sr->Extras;
        mStatus err;
 
-       DeconstructServiceName(&sr->RR_SRV.resrec.name, &name, &type, &domain);
+       DeconstructServiceName(&sr->RR_SRV.resrec.name, &name1, &type, &domain);
        if (!newname)
                {
-               IncrementLabelSuffix(&name, mDNStrue);
-               newname = &name;
+               name2 = name1;
+               IncrementLabelSuffix(&name2, mDNStrue);
+               newname = &name2;
                }
-       debugf("Reregistering as %#s", newname->c);
+       LogMsg("Service \"%##s\" renamed to \"%#s\"", sr->RR_SRV.resrec.name.c, newname->c);
        if (sr->RR_SRV.HostTarget == mDNSfalse && sr->Host.c[0]) host = &sr->Host;
        
        err = mDNS_RegisterService(m, sr, newname, &type, &domain,
@@ -6879,6 +5998,9 @@ mDNSexport mStatus mDNS_RenameAndReregisterService(mDNS *const m, ServiceRecordS
 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
 mDNSexport mStatus mDNS_DeregisterService(mDNS *const m, ServiceRecordSet *sr)
        {
+    if (!sr->RR_SRV.resrec.InterfaceID && !IsLocalDomain(&sr->RR_SRV.resrec.name))
+               return uDNS_DeregisterService(m, sr);
+
        if (sr->RR_PTR.resrec.RecordType == kDNSRecordTypeUnregistered)
                {
                debugf("Service set for %##s already deregistered", sr->RR_PTR.resrec.name.c);
@@ -6963,7 +6085,7 @@ mDNSexport mStatus mDNS_AdvertiseDomains(mDNS *const m, AuthRecord *rr,
 #pragma mark - Startup and Shutdown
 #endif
 
-mDNSexport void mDNS_GrowCache(mDNS *const m, CacheRecord *storage, mDNSu32 numrecords)
+mDNSlocal void mDNS_GrowCache_internal(mDNS *const m, CacheRecord *storage, mDNSu32 numrecords)
        {
        if (storage && numrecords)
                {
@@ -6975,6 +6097,13 @@ mDNSexport void mDNS_GrowCache(mDNS *const m, CacheRecord *storage, mDNSu32 numr
                }
        }
 
+mDNSexport void mDNS_GrowCache(mDNS *const m, CacheRecord *storage, mDNSu32 numrecords)
+       {
+       mDNS_Lock(m);
+       mDNS_GrowCache_internal(m, storage, numrecords);
+       mDNS_Unlock(m);
+       }
+
 mDNSexport mStatus mDNS_Init(mDNS *const m, mDNS_PlatformSupport *const p,
        CacheRecord *rrcachestorage, mDNSu32 rrcachesize,
        mDNSBool AdvertiseLocalAddresses, mDNSCallback *Callback, void *Context)
@@ -6988,6 +6117,7 @@ mDNSexport mStatus mDNS_Init(mDNS *const m, mDNS_PlatformSupport *const p,
        
        m->p                       = p;
        m->KnownBugs               = 0;
+       m->CanReceiveUnicast       = mDNSfalse;         // Assume we can't receive unicasts, unless platform layer tells us otherwise
        m->AdvertiseLocalAddresses = AdvertiseLocalAddresses;
        m->mDNSPlatformStatus      = mStatus_Waiting;
        m->MainCallback            = Callback;
@@ -7036,7 +6166,7 @@ mDNSexport mStatus mDNS_Init(mDNS *const m, mDNS_PlatformSupport *const p,
                m->rrcache_used[slot] = 0;
                }
 
-       mDNS_GrowCache(m, rrcachestorage, rrcachesize);
+       mDNS_GrowCache_internal(m, rrcachestorage, rrcachesize);
 
        // Fields below only required for mDNS Responder...
        m->hostlabel.c[0]          = 0;
@@ -7055,6 +6185,7 @@ mDNSexport mStatus mDNS_Init(mDNS *const m, mDNS_PlatformSupport *const p,
        m->NumFailedProbes         = 0;
        m->SuppressProbes          = 0;
 
+       uDNS_Init(m);
        result = mDNSPlatformInit(m);
 
        return(result);
@@ -7064,7 +6195,13 @@ mDNSexport void mDNSCoreInitComplete(mDNS *const m, mStatus result)
        {
        m->mDNSPlatformStatus = result;
        if (m->MainCallback)
+               {
+               mDNS_Lock(m);
+               m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
                m->MainCallback(m, mStatus_NoError);
+               m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
+               mDNS_Unlock(m);
+               }
        }
 
 mDNSexport void mDNS_Close(mDNS *const m)
@@ -7074,7 +6211,7 @@ mDNSexport void mDNS_Close(mDNS *const m)
        mDNSu32 slot;
        NetworkInterfaceInfo *intf;
        mDNS_Lock(m);
-
+       
        m->mDNS_shutdown = mDNStrue;
 
        rrcache_totalused = m->rrcache_totalused;
@@ -7099,7 +6236,7 @@ mDNSexport void mDNS_Close(mDNS *const m)
        
        for (intf = m->HostInterfaces; intf; intf = intf->next)
                if (intf->Advertise)
-                       mDNS_DeadvertiseInterface(m, intf);
+                       DeadvertiseInterface(m, intf);
 
        // Make sure there are nothing but deregistering records remaining in the list
        if (m->CurrentRecord) LogMsg("mDNS_Close ERROR m->CurrentRecord already set");
@@ -7115,6 +6252,8 @@ mDNSexport void mDNS_Close(mDNS *const m)
                        }
                }
 
+       uDNS_SuspendLLQs(m);
+
        if (m->ResourceRecords) debugf("mDNS_Close: Sending final packets for deregistering records");
        else debugf("mDNS_Close: No deregistering records remain");
 
index 4381c67adaa018c02e62644213d99584fb4d1bf4..df404f738763c0734aacf804647aca2fb44e6e3c 100755 (executable)
@@ -3,6 +3,8 @@
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
     Change History (most recent first):
 
 $Log: mDNSClientAPI.h,v $
-Revision 1.114.2.10  2005/01/28 05:02:05  cheshire
-<rdar://problem/3770559> SUPan: Replace IP TTL 255 check with local-subnet check
+Revision 1.177  2004/06/05 00:04:26  cheshire
+<rdar://problem/3668639>: wide-area domains should be returned in reg. domain enumeration
+
+Revision 1.176  2004/06/04 08:58:29  ksekar
+<rdar://problem/3668624>: Keychain integration for secure dynamic update
+
+Revision 1.175  2004/06/04 00:15:06  cheshire
+Move misplaced brackets
+
+Revision 1.174  2004/06/03 23:30:16  cheshire
+Remove extraneous blank lines and white space
+
+Revision 1.173  2004/06/03 03:09:58  ksekar
+<rdar://problem/3668626>: Garbage Collection for Dynamic Updates
+
+Revision 1.172  2004/06/01 23:46:50  ksekar
+<rdar://problem/3675149>: DynDNS: dynamically look up LLQ/Update ports
+
+Revision 1.171  2004/05/28 23:42:37  ksekar
+<rdar://problem/3258021>: Feature: DNS server->client notification on record changes (#7805)
 
-Revision 1.114.2.9  2004/04/22 03:17:35  cheshire
+Revision 1.170  2004/05/18 23:51:25  cheshire
+Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
+
+Revision 1.169  2004/05/13 04:54:20  ksekar
+Unified list copy/free code.  Added symetric list for
+
+Revision 1.168  2004/05/12 22:03:09  ksekar
+Made GetSearchDomainList a true platform-layer call (declaration moved
+from mDNSMacOSX.h to mDNSClientAPI.h), impelemted to return "local"
+only on non-OSX platforms.  Changed call to return a copy of the list
+to avoid shared memory issues.  Added a routine to free the list.
+
+Revision 1.167  2004/04/22 04:07:01  cheshire
+Fix from Bob Bradley: Don't try to do inline functions on compilers that don't support it
+
+Revision 1.166  2004/04/22 03:15:56  cheshire
 Fix use of "struct __attribute__((__packed__))" so it only applies on GCC >= 2.9
 
-Revision 1.114.2.8  2004/03/30 06:55:37  cheshire
-Gave name to anonymous struct, to avoid errors on certain compilers.
-(Thanks to ramaprasad.kr@hp.com for reporting this.)
+Revision 1.165  2004/04/22 03:05:28  cheshire
+kDNSClass_ANY should be kDNSQClass_ANY
+
+Revision 1.164  2004/04/21 02:55:03  cheshire
+Update comments describing 'InterfaceActive' field
+
+Revision 1.163  2004/04/21 02:49:11  cheshire
+To reduce future confusion, renamed 'TxAndRx' to 'McastTxRx'
+
+Revision 1.162  2004/04/15 00:51:28  bradley
+Minor tweaks for Windows and C++ builds. Added casts for signed/unsigned integers and 64-bit pointers.
+Prefix some functions with mDNS to avoid conflicts. Disable benign warnings on Microsoft compilers.
+
+Revision 1.161  2004/04/14 23:09:28  ksekar
+Support for TSIG signed dynamic updates.
+
+Revision 1.160  2004/04/09 17:40:26  cheshire
+Remove unnecessary "Multicast" field -- it duplicates the semantics of the existing McastTxRx field
+
+Revision 1.159  2004/04/09 16:37:15  cheshire
+Suggestion from Bob Bradley:
+Move NumCacheRecordsForInterfaceID() to DNSCommon.c so it's available to all platform layers
+
+Revision 1.158  2004/04/02 19:38:33  cheshire
+Update comment about typical RR TTLs
+
+Revision 1.157  2004/04/02 19:35:53  cheshire
+Add clarifying comments about legal mDNSInterfaceID values
+
+Revision 1.156  2004/04/02 19:19:48  cheshire
+Add code to do optional logging of multi-packet KA list time intervals
+
+Revision 1.155  2004/03/24 00:29:45  ksekar
+Make it safe to call StopQuery in a unicast question callback
+
+Revision 1.154  2004/03/20 01:05:49  cheshire
+Test __LP64__ and __ILP64__ to compile properly on a wider range of 64-bit architectures
+
+Revision 1.153  2004/03/13 01:57:33  ksekar
+<rdar://problem/3192546>: DynDNS: Dynamic update of service records
 
-Revision 1.114.2.7  2004/03/09 02:31:27  cheshire
+Revision 1.152  2004/03/09 02:27:16  cheshire
 Remove erroneous underscore in 'packed_struct' (makes no difference now, but might in future)
 
-Revision 1.114.2.6  2004/03/02 02:55:25  cheshire
+Revision 1.151  2004/03/02 03:21:56  cheshire
 <rdar://problem/3549576> Properly support "_services._dns-sd._udp" meta-queries
 
-Revision 1.114.2.5  2004/02/18 23:35:17  cheshire
-<rdar://problem/3488559>: Hard code domain enumeration functions to return ".local" only
-Also make mDNS_StopGetDomains() a no-op too, so that we don't get warning messages in syslog
+Revision 1.150  2004/02/21 02:06:24  cheshire
+Can't use anonymous unions -- they're non-standard and don't work on all compilers
+
+Revision 1.149  2004/02/06 23:04:19  ksekar
+Basic Dynamic Update support via mDNS_Register (dissabled via
+UNICAST_REGISTRATION #define)
+
+Revision 1.148  2004/02/03 19:47:36  ksekar
+Added an asyncronous state machine mechanism to uDNS.c, including
+calls to find the parent zone for a domain name.  Changes include code
+in repository previously dissabled via "#if 0 //incomplete".  Codepath
+is currently unused, and will be called to create update records, etc.
+
+Revision 1.147  2004/02/03 18:57:35  cheshire
+Update comment for "IsLocalDomain()"
+
+Revision 1.146  2004/01/30 02:20:24  bradley
+Map inline to __inline when building with Microsoft C compilers since they do not support C99 inline.
+
+Revision 1.145  2004/01/29 02:59:17  ksekar
+Unicast DNS: Changed from a resource record oriented question/response
+matching to packet based matching.  New callback architecture allows
+collections of records in a response to be processed differently
+depending on the nature of the request, and allows the same structure
+to be used for internal and client-driven queries with different processing needs.
+
+Revision 1.144  2004/01/28 20:20:45  ksekar
+Unified ActiveQueries and ActiveInternalQueries lists, using a flag to
+demux them.  Check-in includes work-in-progress code, #ifdef'd out.
+
+Revision 1.143  2004/01/28 03:41:00  cheshire
+<rdar://problem/3541946>: Need ability to do targeted queries as well as multicast queries
+
+Revision 1.142  2004/01/28 02:30:07  ksekar
+Added default Search Domains to unicast browsing, controlled via
+Networking sharing prefs pane.  Stopped sending unicast messages on
+every interface.  Fixed unicast resolving via mach-port API.
+
+Revision 1.141  2004/01/27 20:15:22  cheshire
+<rdar://problem/3541288>: Time to prune obsolete code for listening on port 53
+
+Revision 1.140  2004/01/24 23:37:08  cheshire
+At Kiren's suggestion, made functions to convert mDNSOpaque16s to/from integer values
+
+Revision 1.139  2004/01/24 08:46:26  bradley
+Added InterfaceID<->Index platform interfaces since they are now used by all platforms for the DNS-SD APIs.
+
+Revision 1.138  2004/01/24 04:59:15  cheshire
+Fixes so that Posix/Linux, OS9, Windows, and VxWorks targets build again
+
+Revision 1.137  2004/01/24 03:40:56  cheshire
+Move mDNSAddrIsDNSMulticast() from DNSCommon.h to mDNSClientAPI.h so clients can use it
+
+Revision 1.136  2004/01/24 03:38:27  cheshire
+Fix minor syntactic error: Headers should use "extern" declarations, not "mDNSexport"
+
+Revision 1.135  2004/01/23 23:23:15  ksekar
+Added TCP support for truncated unicast messages.
+
+Revision 1.134  2004/01/22 03:54:11  cheshire
+Create special meta-interface 'mDNSInterface_ForceMCast' (-2),
+which means "do this query via multicast, even if it's apparently a unicast domain"
+
+Revision 1.133  2004/01/22 03:48:41  cheshire
+Make sure uDNS client doesn't accidentally use query ID zero
+
+Revision 1.132  2004/01/22 03:43:08  cheshire
+Export constants like mDNSInterface_LocalOnly so that the client layers can use them
+
+Revision 1.131  2004/01/21 21:53:18  cheshire
+<rdar://problem/3448144>: Don't try to receive unicast responses if we're not the first to bind to the UDP port
+
+Revision 1.130  2003/12/14 05:05:29  cheshire
+Add comments explaining mDNS_Init_NoCache and mDNS_Init_ZeroCacheSize
+
+Revision 1.129  2003/12/13 03:05:27  ksekar
+<rdar://problem/3192548>: DynDNS: Unicast query of service records
+
+Revision 1.128  2003/12/01 21:44:23  cheshire
+Add mStatus_BadInterfaceErr = -65552 for consistency with dns_sd.h
+
+Revision 1.127  2003/12/01 18:26:37  cheshire
+Also pack the OpaqueXX union types. Otherwise, on some systems, mDNSOpaque16 is four bytes!
+
+Revision 1.126  2003/12/01 18:23:48  cheshire
+<rdar://problem/3464646>: Scalar size problem in mDNS code on some 64-bit architectures
+
+Revision 1.125  2003/11/22 00:18:27  cheshire
+Add compile-time asserts to verify correct sizes of mDNSu32, mDNSOpaque16, etc.
 
-Revision 1.114.2.4  2004/01/28 23:29:20  cheshire
-Fix structure packing (only affects third-party Darwin developers)
+Revision 1.124  2003/11/20 22:59:54  cheshire
+Changed runtime checks in mDNS.c to be compile-time checks in mDNSClientAPI.h
+Thanks to Bob Bradley for suggesting the ingenious compiler trick to make this work.
 
-Revision 1.114.2.3  2003/12/05 00:03:34  cheshire
-<rdar://problem/3487869> Use buffer size MAX_ESCAPED_DOMAIN_NAME instead of 256
+Revision 1.123  2003/11/20 22:53:01  cheshire
+Add comment about MAX_ESCAPED_DOMAIN_LABEL
 
-Revision 1.114.2.2  2003/12/04 23:30:00  cheshire
-Add "#define MAX_ESCAPED_DOMAIN_NAME 1005", needed for Posix folder to build
+Revision 1.122  2003/11/20 20:49:53  cheshire
+Another fix from HP: Use packedstruct macro to ensure proper packing for on-the-wire packet structures
 
-Revision 1.114.2.1  2003/12/03 11:07:58  cheshire
-<rdar://problem/3457718>: Stop and start of a service uses old ip address (with old port number)
+Revision 1.121  2003/11/20 05:01:38  cheshire
+Update comments; add explanation of Advertise/DontAdvertiseLocalAddresses
+
+Revision 1.120  2003/11/14 20:59:08  cheshire
+Clients can't use AssignDomainName macro because mDNSPlatformMemCopy is defined in mDNSPlatformFunctions.h.
+Best solution is just to combine mDNSClientAPI.h and mDNSPlatformFunctions.h into a single file.
+
+Revision 1.119  2003/11/14 19:47:52  cheshire
+Define symbol MAX_ESCAPED_DOMAIN_NAME to indicate recommended buffer size for ConvertDomainNameToCString
+
+Revision 1.118  2003/11/14 19:18:34  cheshire
+Move AssignDomainName macro to mDNSClientAPI.h to that client layers can use it too
+
+Revision 1.117  2003/11/08 23:32:24  cheshire
+Gave name to anonymous struct, to avoid errors on certain compilers.
+(Thanks to ramaprasad.kr@hp.com for reporting this.)
+
+Revision 1.116  2003/11/07 03:32:56  cheshire
+<rdar://problem/3472153> mDNSResponder delivers answers in inconsistent order
+This is the real fix. Checkin 1.312 was overly simplistic; Calling GetFreeCacheRR() can sometimes
+purge records from the cache, causing tail pointer *rp to be stale on return. The correct fix is
+to maintain a system-wide tail pointer for each cache slot, and then if neccesary GetFreeCacheRR()
+can update this pointer, so that mDNSCoreReceiveResponse() appends records in the right place.
+
+Revision 1.115  2003/09/23 00:53:54  cheshire
+NumFailedProbes should be unsigned
 
 Revision 1.114  2003/08/29 19:44:15  cheshire
 <rdar://problem/3400967> Traffic reduction: Eliminate synchronized QUs when a new service appears
@@ -166,7 +349,7 @@ Revision 1.87  2003/07/22 23:57:20  cheshire
 Move platform-layer function prototypes from mDNSClientAPI.h to mDNSPlatformFunctions.h where they belong
 
 Revision 1.86  2003/07/20 03:52:02  ksekar
-Bug #: <rdar://problem/3320722>: Feature: New Rendezvous APIs (#7875) (mDNSResponder component)
+<rdar://problem/3320722>: Feature: New Rendezvous APIs (#7875) (mDNSResponder component)
 Added error type for incompatibility between daemon and client versions
 
 Revision 1.85  2003/07/19 03:23:13  cheshire
@@ -323,12 +506,11 @@ Revision 1.43  2003/04/25 01:45:56  cheshire
 
 Revision 1.42  2003/04/15 20:58:31  jgraessl
 
-Bug #: 3229014
-Added a hash to lookup records in the cache.
+<rdar://problem/3229014> Added a hash to lookup records in the cache.
 
 Revision 1.41  2003/04/15 18:09:13  jgraessl
 
-Bug #: 3228892
+<rdar://problem/3228892>
 Reviewed by: Stuart Cheshire
 Added code to keep track of when the next cache item will expire so we can
 call TidyRRCache only when necessary.
@@ -353,25 +535,25 @@ Revision 1.37  2003/03/14 21:34:11  cheshire
 Increase size of cache rdata from 512 to 768
 
 Revision 1.36  2003/03/05 03:38:35  cheshire
-Bug #: 3185731 Bogus error message in console: died or deallocated, but no record of client can be found!
+<rdar://problem/3185731> Bogus error message in console: died or deallocated, but no record of client can be found!
 Fixed by leaving client in list after conflict, until client explicitly deallocates
 
 Revision 1.35  2003/02/21 02:47:54  cheshire
-Bug #: 3099194 mDNSResponder needs performance improvements
+<rdar://problem/3099194> mDNSResponder needs performance improvements
 Several places in the code were calling CacheRRActive(), which searched the entire
 question list every time, to see if this cache resource record answers any question.
 Instead, we now have a field "CRActiveQuestion" in the resource record structure
 
 Revision 1.34  2003/02/21 01:54:08  cheshire
-Bug #: 3099194 mDNSResponder needs performance improvements
+<rdar://problem/3099194> mDNSResponder needs performance improvements
 Switched to using new "mDNS_Execute" model (see "Implementer Notes.txt")
 
 Revision 1.33  2003/02/20 06:48:32  cheshire
-Bug #: 3169535 Xserve RAID needs to do interface-specific registrations
+<rdar://problem/3169535> Xserve RAID needs to do interface-specific registrations
 Reviewed by: Josh Graessley, Bob Bradley
 
 Revision 1.32  2003/01/31 03:35:59  cheshire
-Bug #: 3147097 mDNSResponder sometimes fails to find the correct results
+<rdar://problem/3147097> mDNSResponder sometimes fails to find the correct results
 When there were *two* active questions in the list, they were incorrectly
 finding *each other* and *both* being marked as duplicates of another question
 
@@ -386,7 +568,7 @@ Revision 1.30  2003/01/29 01:47:08  cheshire
 Rename 'Active' to 'CRActive' or 'InterfaceActive' for improved clarity
 
 Revision 1.29  2003/01/28 05:23:43  cheshire
-Bug #: 3147097 mDNSResponder sometimes fails to find the correct results
+<rdar://problem/3147097> mDNSResponder sometimes fails to find the correct results
 Add 'Active' flag for interfaces
 
 Revision 1.28  2003/01/28 01:35:56  cheshire
@@ -394,9 +576,9 @@ Revise comment about ThisQInterval to reflect new semantics
 
 Revision 1.27  2003/01/13 23:49:42  jgraessl
 Merged changes for the following fixes in to top of tree:
-3086540  computer name changes not handled properly
-3124348  service name changes are not properly handled
-3124352  announcements sent in pairs, failing chattiness test
+<rdar://problem/3086540>  computer name changes not handled properly
+<rdar://problem/3124348>  service name changes are not properly handled
+<rdar://problem/3124352>  announcements sent in pairs, failing chattiness test
 
 Revision 1.26  2002/12/23 22:13:28  jgraessl
 
@@ -407,7 +589,7 @@ Revision 1.25  2002/09/21 20:44:49  zarzycki
 Added APSL info
 
 Revision 1.24  2002/09/19 23:47:35  cheshire
-Added mDNS_RegisterNoSuchService() function for assertion of non-existence
+Added mDNS_RegisterNoSuchService() function for assertion of non-existance
 of a particular named service
 
 Revision 1.23  2002/09/19 21:25:34  cheshire
@@ -430,7 +612,7 @@ Merge in license terms from Quinn's copy, in preparation for Darwin release
 #include <stdarg.h>            // stdarg.h is required for for va_list support for the mDNS_vsnprintf declaration
 #include "mDNSDebug.h"
 
-#ifdef __cplusplus
+#ifdef __cplusplus
        extern "C" {
 #endif
 
@@ -506,7 +688,9 @@ typedef enum                                // From RFC 1035
        kDNSType_TXT,                   // 16 Arbitrary text string
 
        kDNSType_AAAA = 28,             // 28 IPv6 address
-       kDNSType_SRV = 33,              // 33 Service record
+       kDNSType_SRV  = 33,             // 33 Service record
+       kDNSType_OPT  = 41,     // EDNS0 OPT record
+       kDNSType_TSIG = 250,    // 250 Transaction Signature
 
        kDNSQType_ANY = 255             // Not a DNS type, but a DNS query type, meaning "all types"
        } DNS_TypeValues;
@@ -523,9 +707,21 @@ typedef   signed char  mDNSs8;
 typedef unsigned char  mDNSu8;
 typedef   signed short mDNSs16;
 typedef unsigned short mDNSu16;
-#if _LP64
+
+// <http://gcc.gnu.org/onlinedocs/gcc-3.3.3/cpp/Common-Predefined-Macros.html> says
+//   __LP64__ _LP64
+//   These macros are defined, with value 1, if (and only if) the compilation is
+//   for a target where long int and pointer both use 64-bits and int uses 32-bit.
+// <http://www.intel.com/software/products/compilers/clin/docs/ug/lin1077.htm> says
+//   Macro Name __LP64__ Value 1
+// A quick Google search for "defined(__LP64__)" OR "#ifdef __LP64__" gives 2590 hits and
+// a search for "#if __LP64__" gives only 12, so I think we'll go with the majority and use defined()
+#if defined(_LP64) || defined(__LP64__)
 typedef   signed int   mDNSs32;
 typedef unsigned int   mDNSu32;
+#elif defined(_ILP64) || defined(__ILP64__)
+typedef   signed int32 mDNSs32;
+typedef unsigned int32 mDNSu32;
 #else
 typedef   signed long  mDNSs32;
 typedef unsigned long  mDNSu32;
@@ -548,7 +744,7 @@ typedef packedunion { mDNSu8 b[4]; mDNSu32 NotAnInteger; } mDNSOpaque32;
 typedef packedunion { mDNSu8 b[16]; mDNSu16 w[8]; mDNSu32 l[4]; } mDNSOpaque128;
 
 typedef mDNSOpaque16  mDNSIPPort;              // An IP port is a two-byte opaque identifier (not an integer)
-typedef mDNSOpaque32  mDNSv4Addr;              // An IP address is a four-byte opaque identifier (not an integer)
+typedef mDNSOpaque32  mDNSv4Addr;              // An IP address is a four-byte opaque identifier (not an integer)
 typedef mDNSOpaque128 mDNSv6Addr;              // An IPv6 address is a 16-byte opaque identifier (not an integer)
 
 enum
@@ -595,13 +791,20 @@ enum
        //                        = -65550,
        mStatus_Incompatible      = -65551,
        mStatus_BadInterfaceErr   = -65552,
-
-       // -65553 - -65789 currently unused
+       mStatus_Refused           = -65553,
+       mStatus_NoSuchRecord      = -65554,
+    mStatus_NoAuth            = -65555,
+       // -65556 - -65789 currently unused
 
        // Non-error values:
        mStatus_GrowCache         = -65790,
        mStatus_ConfigChanged     = -65791,
-       mStatus_MemFree           = -65792              // 0xFFFE FF00
+       mStatus_MemFree           = -65792,             // 0xFFFE FF00
+
+       // tcp connection status
+       mStatus_ConnectionPending = -65793,
+       mStatus_ConnectionFailed =  -65794,
+       mStatus_ConnectionEstablished = -65795
        };
 
 typedef mDNSs32 mStatus;
@@ -631,6 +834,36 @@ typedef struct { mDNSu8 c[256]; } UTF8str255;              // Null-terminated C string
 #define MAX_ESCAPED_DOMAIN_LABEL 254
 #define MAX_ESCAPED_DOMAIN_NAME 1005
 
+// ***************************************************************************
+#if 0
+#pragma mark - DNS Message structures
+#endif
+
+#define mDNS_numZones   numQuestions
+#define mDNS_numPrereqs numAnswers
+#define mDNS_numUpdates numAuthorities
+
+typedef packedstruct
+       {
+       mDNSOpaque16 id;
+       mDNSOpaque16 flags;
+       mDNSu16 numQuestions;
+       mDNSu16 numAnswers;
+       mDNSu16 numAuthorities;
+       mDNSu16 numAdditionals;
+       } DNSMessageHeader;
+
+// We can send and receive packets up to 9000 bytes (Ethernet Jumbo Frame size, if that ever becomes widely used)
+// However, in the normal case we try to limit packets to 1500 bytes so that we don't get IP fragmentation on standard Ethernet
+// 40 (IPv6 header) + 8 (UDP header) + 12 (DNS message header) + 1440 (DNS message body) = 1500 total
+#define AbsoluteMaxDNSMessageData 8940
+#define NormalMaxDNSMessageData 1440
+typedef packedstruct
+       {
+       DNSMessageHeader h;                                             // Note: Size 12 bytes
+       mDNSu8 data[AbsoluteMaxDNSMessageData]; // 40 (IPv6) + 8 (UDP) + 12 (DNS header) + 8940 (data) = 9000
+       } DNSMessage;
+
 // ***************************************************************************
 #if 0
 #pragma mark - Resource Record structures
@@ -653,7 +886,7 @@ typedef struct { mDNSu8 c[256]; } UTF8str255;               // Null-terminated C string
 // -- The majority of Resource Records are of this type
 // -- If two entities on the network have RRs with the same name but different RDATA, this is a conflict
 // -- Responses may be sent immediately, because only one host should be responding to any particular query
-// -- These RRs typically have low TTLs (e.g. ten seconds)
+// -- These RRs typically have low TTLs (e.g. a few minutes)
 // -- On startup and after topology changes, a host issues queries to verify uniqueness
 
 // * Known Unique Resource Records are treated like Unique Resource Records, except that mDNS does
@@ -698,9 +931,10 @@ enum
 
        kDNSRecordTypeAdvisory         = 0x04,  // Like Shared, but no goodbye packet
        kDNSRecordTypeShared           = 0x08,  // Shared means record name does not have to be unique -- use random delay on responses
+
        kDNSRecordTypeVerified         = 0x10,  // Unique means mDNS should check that name is unique (and then send immediate responses)
        kDNSRecordTypeKnownUnique      = 0x20,  // Known Unique means mDNS can assume name is unique without checking
-
+                                               // For Dynamic Update records, Known Unique means the record must already exist on the server.
        kDNSRecordTypeUniqueMask       = (kDNSRecordTypeUnique | kDNSRecordTypeVerified | kDNSRecordTypeKnownUnique),
        kDNSRecordTypeActiveMask       = (kDNSRecordTypeAdvisory | kDNSRecordTypeShared | kDNSRecordTypeVerified | kDNSRecordTypeKnownUnique),
 
@@ -713,8 +947,27 @@ enum
        kDNSRecordTypePacketUniqueMask = 0x20   // True for PacketAddUnique and PacketAnsUnique
        };
 
-typedef packedstruct { mDNSu16 priority; mDNSu16 weight; mDNSIPPort port; domainname target; } rdataSRV;
-typedef packedstruct { mDNSu16 preference; domainname exchange; } rdataMX;
+typedef packedstruct { mDNSu16 priority; mDNSu16 weight; mDNSIPPort port; domainname target;   } rdataSRV;
+typedef packedstruct { mDNSu16 preference;                                domainname exchange; } rdataMX;
+typedef packedstruct { domainname mname; domainname rname; mDNSOpaque32 serial; mDNSOpaque32 refresh;
+                       mDNSOpaque32 retry; mDNSOpaque32 expire; mDNSOpaque32 min;              } rdataSOA;
+
+typedef packedstruct
+       {
+       mDNSu16 vers;
+    mDNSu16 llqOp;
+       mDNSu16 err;
+       mDNSu8 id[8];
+       mDNSu32 lease;
+       } LLQOptData;
+
+// NOTE: rdataOpt format may be repeated an arbitrary number of times in a single resource record
+typedef packedstruct
+       {
+       mDNSu16 opt;
+       mDNSu16 optlen;
+       union { LLQOptData llq; mDNSu32 lease; } OptData;
+       } rdataOpt;
 
 // StandardAuthRDSize is 264 (256+8), which is large enough to hold a maximum-sized SRV record
 // MaximumRDSize is 8K the absolute maximum we support (at least for now)
@@ -738,10 +991,12 @@ typedef union
        mDNSu8      data[StandardAuthRDSize];
        mDNSv4Addr  ip;                 // For 'A' record
        mDNSv6Addr  ipv6;               // For 'AAAA' record
-       domainname  name;               // For PTR and CNAME records
+       domainname  name;               // For PTR, NS, and CNAME records
        UTF8str255  txt;                // For TXT record
        rdataSRV    srv;                // For SRV record
        rdataMX     mx;                 // For MX record
+    rdataSOA    soa;        // For SOA record
+    rdataOpt    opt;        // For eDNS0 opt record
        } RDataBody;
 
 typedef struct
@@ -758,7 +1013,7 @@ typedef struct DNSQuestion_struct DNSQuestion;
 typedef struct mDNS_struct mDNS;
 typedef struct mDNS_PlatformSupport_struct mDNS_PlatformSupport;
 
-// Note: Within an mDNSRecordCallback mDNS all API calls are legal except mDNS_Init(), mDNS_Close(), mDNS_Execute() 
+// Note: Within an mDNSRecordCallback mDNS all API calls are legal except mDNS_Init(), mDNS_Close(), mDNS_Execute()
 typedef void mDNSRecordCallback(mDNS *const m, AuthRecord *const rr, mStatus result);
 
 // Note:
@@ -774,7 +1029,7 @@ struct ResourceRecord_struct
                                                                                // For records received off the wire, InterfaceID is *always* set to the receiving interface
                                                                                // For our authoritative records, InterfaceID is usually zero, except for those few records
                                                                                // that are interface-specific (e.g. address records, especially linklocal addresses)
-       domainname      name;                           
+       domainname      name;
        mDNSu16         rrtype;
        mDNSu16         rrclass;
        mDNSu32         rroriginalttl;          // In seconds
@@ -786,6 +1041,34 @@ struct ResourceRecord_struct
        RData           *rdata;                         // Pointer to storage for this rdata
        };
 
+enum
+       {
+       regState_FetchingZoneData  = 1,     // getting info - update not sent
+       regState_Pending           = 2,     // update sent, reply not received
+       regState_Registered        = 3,     // update sent, reply received
+       regState_DeregPending      = 4,     // dereg sent, reply not received
+       regState_DeregDeferred     = 5,     // dereg requested while in Pending state - send dereg AFTER registration is confirmed
+       regState_Cancelled         = 6,     // update not sent, reg. cancelled by client
+       regState_TargetChange      = 7,     // host name change update pending
+       regState_Unregistered      = 8,     // not in any list
+       regState_Refresh           = 9      // outstanding refresh message
+       };
+
+typedef mDNSu16 regState_t;
+
+typedef struct
+       {
+    regState_t   state;
+    mDNSOpaque16 id;
+    domainname   zone;   // the zone that is updated
+    mDNSAddr     ns;     // primary name server for the record's zone    !!!KRS not technically correct to cache longer than TTL
+    mDNSIPPort   port;   // port on which server accepts dynamic updates
+    mDNSBool     add;    // !!!KRS this should really be an enumerated state
+    struct uDNS_AuthInfo *AuthInfo;  // authentication info (may be null)
+    mDNSBool     lease;  // dynamic update contains (should contain) lease option
+    mDNSs32      expire; // expiration of lease (-1 for static)
+       } uDNS_RegInfo;
+
 struct AuthRecord_struct
        {
        // For examples of how to set up this structure for use in mDNS_Register(),
@@ -795,8 +1078,9 @@ struct AuthRecord_struct
 
        AuthRecord     *next;                           // Next in list; first element of structure for efficiency reasons
        ResourceRecord  resrec;
+    uDNS_RegInfo uDNS_info;
 
-       // Persistent metadata for Authoritative Records
+    // Persistent metadata for Authoritative Records
        AuthRecord     *Additional1;            // Recommended additional record to include in response
        AuthRecord     *Additional2;            // Another additional
        AuthRecord     *DependentOn;            // This record depends on another for its uniqueness checking
@@ -811,6 +1095,9 @@ struct AuthRecord_struct
        mDNSu8          AnnounceCount;          // Number of announcements remaining (kDNSRecordTypeShared)
        mDNSu8          IncludeInProbe;         // Set if this RR is being put into a probe right now
        mDNSInterfaceID ImmedAnswer;            // Someone on this interface issued a query we need to answer (all-ones for all interfaces)
+#if MDNS_LOG_ANSWER_SUPPRESSION_TIMES
+       mDNSs32         ImmedAnswerMarkTime;
+#endif
        mDNSInterfaceID ImmedAdditional;        // Hint that we might want to also send this record, just to be helpful
        mDNSInterfaceID SendRNow;                       // The interface this query is being sent on right now
        mDNSv4Addr      v4Requester;            // Recent v4 query for this record, or all-ones if more than one recent query
@@ -867,16 +1154,28 @@ typedef struct
 
 typedef struct NetworkInterfaceInfo_struct NetworkInterfaceInfo;
 
+typedef struct
+       {
+    AuthRecord RR_A;
+    mDNSBool registered;                // True if a name for the interface is globally registered
+    domainname regname;                 // the name registered to the update server
+       } uDNS_NetworkInterfaceInfo;
+
+// A NetworkInterfaceInfo_struct serves two purposes:
+// 1. It holds the address, PTR and HINFO records to advertise a given IP address on a given physical interface
+// 2. It tells mDNSCore which physical interfaces are available; each physical interface has its own unique InterfaceID.
+//    Since there may be multiple IP addresses on a single physical interface,
+//    there may be multiple NetworkInterfaceInfo_structs with the same InterfaceID.
+//    In this case, to avoid sending the same packet n times, when there's more than one
+//    struct with the same InterfaceID, mDNSCore picks one member of the set to be the
+//    active representative of the set; all others have the 'InterfaceActive' flag unset.
+
 struct NetworkInterfaceInfo_struct
        {
        // Internal state fields. These are used internally by mDNSCore; the client layer needn't be concerned with them.
        NetworkInterfaceInfo *next;
 
-       mDNSBool        InterfaceActive;        // InterfaceActive is set if interface is sending & receiving packets
-                                                                               // InterfaceActive is clear if interface is here to represent an address with A
-                                                                               // and/or AAAA records, but there is already an earlier representative for this
-                                                                               // physical interface which will be used for the actual sending & receiving
-                                                                               // packets (this status may change as interfaces are added and removed)
+       mDNSBool        InterfaceActive;        // Set if interface is sending & receiving packets (see comment above)
        mDNSBool        IPv4Available;          // If InterfaceActive, set if v4 available on this InterfaceID
        mDNSBool        IPv6Available;          // If InterfaceActive, set if v6 available on this InterfaceID
 
@@ -885,13 +1184,13 @@ struct NetworkInterfaceInfo_struct
        AuthRecord RR_PTR;                                      // PTR (reverse lookup) record
        AuthRecord RR_HINFO;
 
+    uDNS_NetworkInterfaceInfo uDNS_info;
+
        // Client API fields: The client must set up these fields *before* calling mDNS_RegisterInterface()
-       mDNSInterfaceID InterfaceID;
-       mDNSAddr        ip;
-       mDNSAddr        mask;
-       char            ifname[16];
-       mDNSBool        Advertise;                      // Set Advertise to false if you are only searching on this interface
-       mDNSBool        TxAndRx;                        // Set to false if not sending and receiving packets on this interface
+       mDNSInterfaceID InterfaceID;            // Identifies physical interface; MUST NOT be 0, -1, or -2
+       mDNSAddr        ip;                                     // The IPv4 or IPv6 address to advertise
+       mDNSBool        Advertise;                      // False if you are only searching on this interface
+       mDNSBool        McastTxRx;                      // Send/Receive multicast on this { InterfaceID, address family } ?
        };
 
 typedef struct ExtraResourceRecord_struct ExtraResourceRecord;
@@ -904,7 +1203,7 @@ struct ExtraResourceRecord_struct
        // that this extra memory is available, which would result in any fields after the AuthRecord getting smashed
        };
 
-// Note: Within an mDNSServiceCallback mDNS all API calls are legal except mDNS_Init(), mDNS_Close(), mDNS_Execute() 
+// Note: Within an mDNSServiceCallback mDNS all API calls are legal except mDNS_Init(), mDNS_Close(), mDNS_Execute()
 typedef struct ServiceRecordSet_struct ServiceRecordSet;
 typedef void mDNSServiceCallback(mDNS *const m, ServiceRecordSet *const sr, mStatus result);
 struct ServiceRecordSet_struct
@@ -912,7 +1211,9 @@ struct ServiceRecordSet_struct
        // Internal state fields. These are used internally by mDNSCore; the client layer needn't be concerned with them.
        // No fields need to be set up by the client prior to calling mDNS_RegisterService();
        // all required data is passed as parameters to that function.
-       mDNSServiceCallback *ServiceCallback;
+    ServiceRecordSet    *next;
+    uDNS_RegInfo        uDNS_info;
+    mDNSServiceCallback *ServiceCallback;
        void                *ServiceContext;
        ExtraResourceRecord *Extras;    // Optional list of extra AuthRecords attached to this service registration
        mDNSu32              NumSubTypes;
@@ -945,7 +1246,78 @@ typedef struct
        mDNSs32               Type;                             // v4 or v6?
        } DupSuppressInfo;
 
-// Note: Within an mDNSQuestionCallback mDNS all API calls are legal except mDNS_Init(), mDNS_Close(), mDNS_Execute() 
+typedef enum
+       {
+       LLQ_UnInit            = 0,
+       LLQ_GetZoneInfo       = 1,
+       LLQ_InitialRequest    = 2,
+       LLQ_SecondaryRequest  = 3,
+       LLQ_Established       = 4,
+       LLQ_Refresh           = 5,
+       LLQ_Retry             = 6,
+    LLQ_Suspended         = 7,
+    // safe to re-start LLQ before this point
+       LLQ_Static            = 16,
+       LLQ_Poll              = 17,
+       LLQ_Error             = 18,
+       LLQ_Cancelled         = 19
+       } LLQ_State;
+
+typedef struct
+       {
+    LLQ_State state;
+    mDNSAddr servAddr;
+    mDNSIPPort servPort;
+    DNSQuestion *question;
+    mDNSu32 origLease;  // seconds (relative)
+    mDNSs32 retry;  // ticks (absolute)
+    mDNSs32 expire; // ticks (absolute)
+    mDNSs16 ntries;
+    mDNSu8 id[8];
+    mDNSBool deriveRemovesOnResume;
+       } LLQ_Info;
+
+// LLQ constants
+#define kDNSOpt_LLQ       1 //!!!KRS
+#define kDNSOpt_Lease  2 //!!!KRS
+#define kLLQ_Vers      0 // prerelease
+#define kLLQ_DefLease  7200 // 2 hours
+#define kUpdate_DefLease 7200
+#define kLLQ_MAX_TRIES 3    // retry an operation 3 times max
+#define kLLQ_INIT_RESEND 2 // resend an un-ack'd packet after 2 seconds, then double for each additional
+#define kLLQ_DEF_RETRY 1800 // retry a failed operation after 30 minutes
+// LLQ Operation Codes
+#define kLLQ_Setup     1
+#define kLLQ_Refresh   2
+
+#define LLQ_OPT_SIZE (2 * sizeof(mDNSu16)) + sizeof(LLQOptData)
+#define LEASE_OPT_SIZE (2 * sizeof(mDNSu16)) + sizeof(mDNSs32)
+
+// LLQ Errror Codes
+enum
+       {
+       LLQErr_NoError = 0,
+       LLQErr_ServFull = 1,
+       LLQErr_Static = 2,
+       LLQErr_FormErr = 3,
+       LLQErr_NoSuchLLQ = 4,
+       LLQErr_BadVers = 5,
+       LLQErr_UnknownErr = 6
+       };
+
+typedef void (*InternalResponseHndlr)(mDNS *const m, DNSMessage *msg, const  mDNSu8 *end, DNSQuestion *question, void *internalContext);
+typedef struct
+    {
+    mDNSOpaque16          id;
+    mDNSs32               timestamp;
+    mDNSBool              internal;
+    InternalResponseHndlr responseCallback;   // NULL if internal field is false
+    LLQ_Info              *llq;               // NULL for 1-shot queries
+    CacheRecord           *knownAnswers;
+    void *context;
+    } uDNS_QuestionInfo;
+
+// Note: Within an mDNSQuestionCallback mDNS all API calls are legal except mDNS_Init(), mDNS_Close(), mDNS_Execute()
 typedef void mDNSQuestionCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord);
 struct DNSQuestion_struct
        {
@@ -967,14 +1339,20 @@ struct DNSQuestion_struct
        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
        mDNSs32               LastQTxTime;              // Last time this Q was sent on one (but not necessarily all) interfaces
+    uDNS_QuestionInfo     uDNS_info;
 
        // Client API fields: The client must set up these fields *before* calling mDNS_StartQuery()
-       mDNSInterfaceID       InterfaceID;              // Non-zero if you want to issue link-local queries only on a single specific IP interface
+       mDNSInterfaceID       InterfaceID;              // Non-zero if you want to issue queries only on a single specific IP interface
+       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
        domainname            qname;
        mDNSu16               qtype;
        mDNSu16               qclass;
        mDNSQuestionCallback *QuestionCallback;
        void                 *QuestionContext;
+    mDNSBool              LongLived;        // Set by client for calls to mDNS_StartQuery to indicate LLQs to unicast layer.
+                                            // Set by mDNS.c in mDNS_StartBrowse.
        };
 
 typedef struct
@@ -989,7 +1367,7 @@ typedef struct
        mDNSu8          TXTinfo[2048];          // Additional demultiplexing information (e.g. LPR queue name)
        } ServiceInfo;
 
-// Note: Within an mDNSServiceInfoQueryCallback mDNS all API calls are legal except mDNS_Init(), mDNS_Close(), mDNS_Execute() 
+// Note: Within an mDNSServiceInfoQueryCallback mDNS all API calls are legal except mDNS_Init(), mDNS_Close(), mDNS_Execute()
 typedef struct ServiceInfoQuery_struct ServiceInfoQuery;
 typedef void mDNSServiceInfoQueryCallback(mDNS *const m, ServiceInfoQuery *query);
 struct ServiceInfoQuery_struct
@@ -1027,6 +1405,29 @@ enum
        mDNS_KnownBug_PhantomInterfaces = 1
        };
 
+typedef struct
+    {
+    mDNSs32          nextevent;
+    DNSQuestion      *ActiveQueries;     //!!!KRS this should be a hashtable (hash on messageID)
+    DNSQuestion      *CurrentQuery;      // pointer to ActiveQueries list being examined in a loop.  Functions that remove
+                                         // elements from the ActiveQueries list must update this pointer (if non-NULL) as necessary.
+                                         //!!!KRS do the same for registration lists
+    ServiceRecordSet *ServiceRegistrations;
+    AuthRecord       *RecordRegistrations;
+    mDNSu16          NextMessageID;
+    mDNSAddr         Servers[32];        //!!!KRS this should be a dynamically allocated linked list
+    domainname       hostname;           // global name for dynamic registration of address records
+    char             NameRegDomain[MAX_ESCAPED_DOMAIN_NAME];
+                                         // domain in which above hostname is registered
+                                         // currently set by the platform layer at startup
+                                         // do not set if services / address records are not to be globally registered to an update server
+                                         // !!!KRS this must go away once we can learn the reg domain from the network or prefs
+    char             ServiceRegDomain[MAX_ESCAPED_DOMAIN_NAME];
+                                         // if set, all services that don't explicitly specify a domain upon registration will be
+                                         // registered in this domain.  if not set, .local will be used by default
+    struct uDNS_AuthInfo *AuthInfoList;  // list of domains required authentication for updates.  !!!KRS this shoudl be a hashtable
+    } uDNS_GlobalInfo;
+
 struct mDNS_struct
        {
        // Internal state fields. These hold the main internal state of mDNSCore;
@@ -1036,6 +1437,7 @@ struct mDNS_struct
 
        mDNS_PlatformSupport *p;                        // Pointer to platform-specific data of indeterminite size
        mDNSu32  KnownBugs;
+       mDNSBool CanReceiveUnicast;
        mDNSBool AdvertiseLocalAddresses;
        mStatus mDNSPlatformStatus;
        mDNSCallback *MainCallback;
@@ -1070,10 +1472,10 @@ struct mDNS_struct
        DNSQuestion *Questions;                         // List of all registered questions, active and inactive
        DNSQuestion *NewQuestions;                      // Fresh questions not yet answered from cache
        DNSQuestion *CurrentQuestion;           // Next question about to be examined in AnswerLocalQuestions()
-       DNSQuestion *LocalOnlyQuestions;        // Questions with InterfaceID set to ~0 ("local only")
+       DNSQuestion *LocalOnlyQuestions;        // Questions with InterfaceID set to mDNSInterface_LocalOnly
        DNSQuestion *NewLocalOnlyQuestions;     // Fresh local-only questions not yet answered
        mDNSu32 rrcache_size;                           // Total number of available cache entries
-       mDNSu32 rrcache_totalused;                      // Number of cache entries currently occupied
+       mDNSu32 rrcache_totalused;                      // Number of cache entries currently occupied
        mDNSu32 rrcache_active;                         // Number of cache entries currently occupied by records that answer active questions
        mDNSu32 rrcache_report;
        CacheRecord *rrcache_free;
@@ -1085,18 +1487,21 @@ 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  hostname;                           // Host Name, e.g. "Foo.local."
-       UTF8str255 HIHardware;
+    UTF8str255 HIHardware;
        UTF8str255 HISoftware;
        AuthRecord *ResourceRecords;
        AuthRecord *DuplicateRecords;           // Records currently 'on hold' because they are duplicates of existing records
-       AuthRecord *LocalOnlyRecords;           // Local records registered with InterfaceID set to ~0 ("local only")
+       AuthRecord *LocalOnlyRecords;           // Local records registered with InterfaceID set to mDNSInterface_LocalOnly
        AuthRecord *NewLocalOnlyRecords;        // Fresh local-only records not yet delivered to local-only questions
        mDNSBool    DiscardLocalOnlyRecords;// Set when we have "remove" events we need to deliver to local-only questions
        AuthRecord *CurrentRecord;                      // Next AuthRecord about to be examined
        NetworkInterfaceInfo *HostInterfaces;
        mDNSs32 ProbeFailTime;
-       mDNSs32 NumFailedProbes;
+       mDNSu32 NumFailedProbes;
        mDNSs32 SuppressProbes;
+
+    // unicast-specific data
+    uDNS_GlobalInfo uDNS_info;
        };
 
 // ***************************************************************************
@@ -1109,7 +1514,11 @@ extern const mDNSv4Addr      zeroIPAddr;
 extern const mDNSv6Addr      zerov6Addr;
 extern const mDNSv4Addr      onesIPv4Addr;
 extern const mDNSv6Addr      onesIPv6Addr;
-extern const mDNSInterfaceID mDNSInterface_Any;
+extern const mDNSAddr        zeroAddr;
+
+extern const mDNSInterfaceID mDNSInterface_Any;                                // Zero
+extern const mDNSInterfaceID mDNSInterface_LocalOnly;          // (mDNSInterfaceID)-1;
+extern const mDNSInterfaceID mDNSInterface_ForceMCast;         // (mDNSInterfaceID)-2;
 
 extern const mDNSIPPort      UnicastDNSPort;
 extern const mDNSIPPort      MulticastDNSPort;
@@ -1119,14 +1528,79 @@ extern const mDNSv6Addr      AllDNSLinkGroupv6;
 extern const mDNSAddr        AllDNSLinkGroup_v4;
 extern const mDNSAddr        AllDNSLinkGroup_v6;
 
+extern const mDNSOpaque16 zeroID;
+extern const mDNSOpaque16 QueryFlags;
+extern const mDNSOpaque16 ResponseFlags;
+extern const mDNSOpaque16 UpdateReqFlags;
+extern const mDNSOpaque16 UpdateRespFlags;
+
+// ***************************************************************************
+#if 0
+#pragma mark - Inline functions
+#endif
+
+#if (defined(_MSC_VER))
+       #define mDNSinline static __inline
+#elif ((__GNUC__ > 2) || ((__GNUC__ == 2) && (__GNUC_MINOR__ >= 9)))
+       #define mDNSinline static inline
+#endif
+
+// If we're not doing inline functions, then this header needs to have the extern declarations
+#if !defined(mDNSinline)
+extern mDNSu16      mDNSVal16(mDNSOpaque16 x);
+extern mDNSu32      mDNSVal32(mDNSOpaque32 x);
+extern mDNSOpaque16 mDNSOpaque16fromIntVal(mDNSu16 v);
+extern mDNSOpaque32 mDNSOpaque32fromIntVal(mDNSu32 v);
+#endif
+
+// If we're compiling the particular C file that instantiates our inlines, then we
+// define "mDNSinline" (to empty string) so that we generate code in the following section
+#if (!defined(mDNSinline) && mDNS_InstantiateInlines)
+#define mDNSinline
+#endif
+
+#ifdef mDNSinline
+
+mDNSinline mDNSu16 mDNSVal16(mDNSOpaque16 x) { return((mDNSu16)((mDNSu16)x.b[0] <<  8 | (mDNSu16)x.b[1])); }
+mDNSinline mDNSu32 mDNSVal32(mDNSOpaque32 x) { return((mDNSu32)((mDNSu32)x.b[0] << 24 | (mDNSu32)x.b[1] << 16 | (mDNSu32)x.b[2] << 8 | (mDNSu32)x.b[3])); }
+
+mDNSinline mDNSOpaque16 mDNSOpaque16fromIntVal(mDNSu16 v)
+       {
+       mDNSOpaque16 x;
+       x.b[0] = (mDNSu8)(v >> 8);
+       x.b[1] = (mDNSu8)(v & 0xFF);
+       return(x);
+       }
+
+mDNSinline mDNSOpaque32 mDNSOpaque32fromIntVal(mDNSu32 v)
+       {
+       mDNSOpaque32 x;
+       x.b[0] = (mDNSu8) (v >> 24)        ;
+       x.b[1] = (mDNSu8)((v >> 16) & 0xFF);
+       x.b[2] = (mDNSu8)((v >> 8 ) & 0xFF);
+       x.b[3] = (mDNSu8)((v      ) & 0xFF);
+       return x;
+       }
+
+#endif
+
 // ***************************************************************************
 #if 0
 #pragma mark - Main Client Functions
 #endif
 
-// Every client should call mDNS_Init, passing in storage for the mDNS object, mDNS_PlatformSupport object, and rrcache.
-// The rrcachesize parameter is the size of (i.e. number of entries in) the rrcache array passed in.
-// Most clients use mDNS_Init_AdvertiseLocalAddresses. This causes mDNSCore to automatically
+// Every client should call mDNS_Init, passing in storage for the mDNS object and the mDNS_PlatformSupport object.
+//
+// Clients that are only advertising services should use mDNS_Init_NoCache and mDNS_Init_ZeroCacheSize.
+// Clients that plan to perform queries (mDNS_StartQuery, mDNS_StartBrowse, mDNS_StartResolveService, etc.)
+// need to provide storage for the resource record cache, or the query calls will return 'mStatus_NoCache'.
+// The rrcachestorage parameter is the address of memory for the resource record cache, and
+// the rrcachesize parameter is the number of entries in the CacheRecord array passed in.
+// (i.e. the size of the cache memory needs to be sizeof(CacheRecord) * rrcachesize).
+// OS X 10.3 Panther uses an initial cache size of 64 entries, and then mDNSCore sends an
+// mStatus_GrowCache message if it needs more.
+//
+// Most clients should use mDNS_Init_AdvertiseLocalAddresses. This causes mDNSCore to automatically
 // create the correct address records for all the hosts interfaces. If you plan to advertise
 // services being offered by the local machine, this is almost always what you want.
 // There are two cases where you might use mDNS_Init_DontAdvertiseLocalAddresses:
@@ -1176,7 +1650,7 @@ extern mDNSs32 mDNS_Execute   (mDNS *const m);
 
 extern mStatus mDNS_Register  (mDNS *const m, AuthRecord *const rr);
 extern mStatus mDNS_Update    (mDNS *const m, AuthRecord *const rr, mDNSu32 newttl,
-                                                               const mDNSu16 newrdlength, 
+                                                               const mDNSu16 newrdlength,
                                                                RData *const newrdata, mDNSRecordUpdateCallback *Callback);
 extern mStatus mDNS_Deregister(mDNS *const m, AuthRecord *const rr);
 
@@ -1250,11 +1724,9 @@ typedef enum
        mDNS_DomainTypeRegistrationDefault = 3
        } mDNS_DomainType;
 
-extern mStatus mDNS_GetDomains(mDNS *const m, DNSQuestion *const question, mDNS_DomainType DomainType, const mDNSInterfaceID InterfaceID, mDNSQuestionCallback *Callback, void *Context);
-// In the Panther mDNSResponder we don't do unicast queries yet, so there's no point trying to do domain enumeration
-// mDNS_GetDomains() and mDNS_StopGetDomains() are set to be no-ops so that clients don't try to do browse/register operations that will fail
-//#define        mDNS_StopGetDomains mDNS_StopQuery
-#define        mDNS_StopGetDomains(m,q) ((void)(m),(void)(q))
+extern mStatus mDNS_GetDomains(mDNS *const m, DNSQuestion *const question, mDNS_DomainType DomainType, const domainname *dom,
+                                                               const mDNSInterfaceID InterfaceID, mDNSQuestionCallback *Callback, void *Context);
+#define        mDNS_StopGetDomains mDNS_StopQuery
 extern mStatus mDNS_AdvertiseDomains(mDNS *const m, AuthRecord *rr, mDNS_DomainType DomainType, const mDNSInterfaceID InterfaceID, char *domname);
 #define        mDNS_StopAdvertiseDomains mDNS_Deregister
 
@@ -1277,6 +1749,7 @@ extern mStatus mDNS_AdvertiseDomains(mDNS *const m, AuthRecord *rr, mDNS_DomainT
 // Comparison functions
 extern mDNSBool SameDomainLabel(const mDNSu8 *a, const mDNSu8 *b);
 extern mDNSBool SameDomainName(const domainname *const d1, const domainname *const d2);
+extern mDNSBool IsLocalDomain(const domainname *d);     // returns true for domains that by default should be looked up using link-local multicast
 
 // Get total length of domain name, in native DNS format, including terminal root label
 //   (e.g. length of "com." is 5 (length byte, three data bytes, final zero)
@@ -1337,13 +1810,77 @@ extern mDNSBool DeconstructServiceName(const domainname *const fqdn, domainlabel
 
 extern mDNSu32 mDNS_vsnprintf(char *sbuffer, mDNSu32 buflen, const char *fmt, va_list arg);
 extern mDNSu32 mDNS_snprintf(char *sbuffer, mDNSu32 buflen, const char *fmt, ...) IS_A_PRINTF_STYLE_FUNCTION(3,4);
+extern mDNSu32 NumCacheRecordsForInterfaceID(const mDNS *const m, mDNSInterfaceID id);
 extern char *DNSTypeName(mDNSu16 rrtype);
 extern char *GetRRDisplayString_rdb(mDNS *const m, const ResourceRecord *rr, RDataBody *rd);
 #define GetRRDisplayString(m, rr) GetRRDisplayString_rdb((m), &(rr)->resrec, &(rr)->resrec.rdata->u)
 extern mDNSBool mDNSSameAddress(const mDNSAddr *ip1, const mDNSAddr *ip2);
-extern mDNSBool mDNSAddrIsDNSMulticast(const mDNSAddr *ip);
 extern void IncrementLabelSuffix(domainlabel *name, mDNSBool RichText);
 
+// ***************************************************************************
+#if 0
+#pragma mark - Authentication Support
+#endif
+
+#define HMAC_LEN    64
+#define HMAC_IPAD   0x36
+#define HMAC_OPAD   0x5c
+#define MD5_LEN     16
+
+// padded keys for inned/outer hash rounds
+typedef struct
+       {
+    mDNSu8 ipad[HMAC_LEN];
+    mDNSu8 opad[HMAC_LEN];
+       } HMAC_Key;
+
+// Internal data structure to maintain authentication information for an update domain
+typedef struct uDNS_AuthInfo
+       {
+    domainname zone;
+    domainname keyname;
+    HMAC_Key key;
+    struct uDNS_AuthInfo *next;
+       } uDNS_AuthInfo;
+
+// Platform Support for computing MD5
+// mDNSPlatformUTC returns the time, in seconds, since Jan 1st 1970 UTC and is required for generating TSIG records
+
+extern mDNSs32  mDNSPlatformUTC(void);
+
+// Client Calls
+// mDNS_UpdateDomainRequiresAuthentication tells the core to authenticate (via TSIG with an HMAC_MD5 hash)
+// when dynamically updating a given zone (and its subdomains).  The key used in authentication must be in
+// domain name format.  The shared secret must be a base64 encoded string with the base64 parameter set to
+// true, or binary data with the base64 parameter set to false.  The length is the size of the secret in
+// bytes.  (A minimum size of 16 bytes (128 bits) is recommended for an MD5 hash as per RFC 2485).
+// The This routine is normally called once for each secure domain at startup, though it can be called at any time.
+
+// mDNS_ClearAuthenticationList clears from the core's internal structures all domains previously passed to
+// mDNS_UpdateDomainRequiresAuthentication.
+
+extern mStatus mDNS_UpdateDomainRequiresAuthentication(mDNS *m, domainname *zone, domainname *key,
+       mDNSu8 *sharedSecret, mDNSu32 ssLen, mDNSBool base64);
+
+extern void mDNS_ClearAuthenticationList(mDNS *m);
+
+// Routines called by the core, exported by DNSDigest.c
+
+// Convert a base64 encoded key into a binary byte stream
+extern mDNSs32 DNSDigest_Base64ToBin(const char *src, mDNSu8 *target, mDNSu32 targsize);
+
+// Convert an arbitrary binary key (of any length) into an HMAC key (stored in AuthInfo struct)
+extern void DNSDigest_ConstructHMACKey(uDNS_AuthInfo *info, mDNSu8 *key, mDNSu32 len);
+
+// sign a DNS message.  The message must be compete, with all values in network byte order.  end points to the end
+// of the message, and is modified by this routine.  numAdditionals is a pointer to the number of additional
+// records in HOST byte order, which is incremented upon successful completion of this routine.  The function returns
+// the new end pointer on success, and NULL on failure.
+extern mDNSu8 *DNSDigest_SignMessage(DNSMessage *msg, mDNSu8 **end, mDNSu16 *numAdditionals, uDNS_AuthInfo *info);
+
+// MD5 hash function used by the core for signing TSIG records (impemented in DNSDigest.c)
+extern mStatus DNSDigest_MD5(const DNSMessage *msg, mDNSu32 msglen, mDNSOpaque16 *digest);
+
 // ***************************************************************************
 #if 0
 #pragma mark - PlatformSupport interface
@@ -1354,34 +1891,13 @@ extern void IncrementLabelSuffix(domainlabel *name, mDNSBool RichText);
 // The definitions are placed here because sometimes clients do use these calls indirectly, via other supported client operations.
 // For example, AssignDomainName is a macro defined using mDNSPlatformMemCopy()
 
-typedef packedstruct
-       {
-       mDNSOpaque16 id;
-       mDNSOpaque16 flags;
-       mDNSu16 numQuestions;
-       mDNSu16 numAnswers;
-       mDNSu16 numAuthorities;
-       mDNSu16 numAdditionals;
-       } DNSMessageHeader;
-
-// We can send and receive packets up to 9000 bytes (Ethernet Jumbo Frame size, if that ever becomes widely used)
-// However, in the normal case we try to limit packets to 1500 bytes so that we don't get IP fragmentation on standard Ethernet
-// 40 (IPv6 header) + 8 (UDP header) + 12 (DNS message header) + 1440 (DNS message body) = 1500 total
-#define AbsoluteMaxDNSMessageData 8940
-#define NormalMaxDNSMessageData 1440
-typedef packedstruct
-       {
-       DNSMessageHeader h;                                             // Note: Size 12 bytes
-       mDNSu8 data[AbsoluteMaxDNSMessageData]; // 40 (IPv6) + 8 (UDP) + 12 (DNS header) + 8940 (data) = 9000
-       } DNSMessage;
-
 // Every platform support module must provide the following functions.
 // mDNSPlatformInit() typically opens a communication endpoint, and starts listening for mDNS packets.
 // When Setup is complete, the platform support layer calls mDNSCoreInitComplete().
 // mDNSPlatformSendUDP() sends one UDP packet
 // When a packet is received, the PlatformSupport code calls mDNSCoreReceive()
 // mDNSPlatformClose() tidies up on exit
-// Note: mDNSPlatformMemAllocate/mDNSPlatformMemFree are only required for handling oversized resource records.
+// Note: mDNSPlatformMemAllocate/mDNSPlatformMemFree are only required for handling oversized resource records and unicast DNS.
 // If your target platform has a well-defined specialized application, and you know that all the records it uses
 // are InlineCacheRDSize or less, then you can just make a simple mDNSPlatformMemAllocate() stub that always returns
 // NULL. InlineCacheRDSize is a compile-time constant, which is set by default to 64. If you need to handle records
@@ -1390,7 +1906,7 @@ typedef packedstruct
 extern mStatus  mDNSPlatformInit        (mDNS *const m);
 extern void     mDNSPlatformClose       (mDNS *const m);
 extern mStatus  mDNSPlatformSendUDP(const mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end,
-       mDNSInterfaceID InterfaceID, mDNSIPPort srcport, const mDNSAddr *dst, mDNSIPPort dstport);
+mDNSInterfaceID InterfaceID, const mDNSAddr *dst, mDNSIPPort dstport);
 
 extern void     mDNSPlatformLock        (const mDNS *const m);
 extern void     mDNSPlatformUnlock      (const mDNS *const m);
@@ -1404,11 +1920,65 @@ extern void *   mDNSPlatformMemAllocate (mDNSu32 len);
 extern void     mDNSPlatformMemFree     (void *mem);
 extern mStatus  mDNSPlatformTimeInit    (mDNSs32 *timenow);
 
+// Platform support modules should provide the following functions to map between opaque interface IDs
+// and interface indexes in order to support the DNS-SD API. If your target platform does not support
+// multiple interfaces and/or does not support the DNS-SD API, these functions can be empty.
+extern mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(const mDNS *const m, mDNSu32 index);
+extern mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(const mDNS *const m, mDNSInterfaceID id);
+
+// Every platform support module must provide the following functions if it is to support unicast DNS
+// and Dynamic Update.
+// All TCP socket operations implemented by the platform layer MUST NOT BLOCK.
+// mDNSPlatformTCPConnect initiates a TCP connection with a peer, adding the socket descriptor to the
+// main event loop.  The return value indicates whether the connection succeeded, failed, or is pending
+// (i.e. the call would block.)  On return, the descriptor parameter is set to point to the connected socket.
+// The TCPConnectionCallback is subsequently invoked when the connection
+// completes (in which case the ConnectionEstablished parameter is true), or data is available for
+// reading on the socket (indicated by the ConnectionEstablished parameter being false.)  If the connection
+// asyncronously fails, the TCPConnectionCallback should be invoked as usual, with the error being
+// returned in subsequent calls to PlatformReadTCP or PlatformWriteTCP.  (This allows for platforms
+// with limited asyncronous error detection capabilities.)  PlatformReadTCP and PlatformWriteTCP must
+// return the number of bytes read/written, 0 if the call would block, and -1 if an error.
+// PlatformTCPCloseConnection must close the connection to the peer and remove the descriptor from the
+// event loop.  CloseConnectin may be called at any time, including in a ConnectionCallback.
+
+typedef void (*TCPConnectionCallback)(int sd, void *context, mDNSBool ConnectionEstablished);
+extern mStatus mDNSPlatformTCPConnect(const mDNSAddr *dst, mDNSOpaque16 dstport, mDNSInterfaceID InterfaceID,
+                                                                                 TCPConnectionCallback callback, void *context, int *descriptor);
+extern void mDNSPlatformTCPCloseConnection(int sd);
+extern int mDNSPlatformReadTCP(int sd, void *buf, int buflen);
+extern int mDNSPlatformWriteTCP(int sd, const char *msg, int len);
+
+// Platforms that support unicast browsing and dynamic update registration for clients who do not specify a domain
+// in browse/registration calls must implement these routines to get the "default" browse/registration list.
+// The Get() functions must return a linked list of DNameListElem structs, allocated via mDNSPlatformMemAllocate.
+// Platforms may implement the Get() calls via the mDNS_CopyDNameList() helper routine.
+// Callers should free lists obtained via the Get() calls with th mDNS_FreeDNameList routine, provided by the core.
+
+typedef struct DNameListElem
+       {
+    domainname name;
+    struct DNameListElem *next;
+    } DNameListElem;
+
+extern DNameListElem *mDNSPlatformGetSearchDomainList(void);
+extern DNameListElem *mDNSPlatformGetRegDomainList(void);
+
+// Helper functions provided by the core
+extern DNameListElem *mDNS_CopyDNameList(const DNameListElem *orig);
+extern void mDNS_FreeDNameList(DNameListElem *list);
+
 // The core mDNS code provides these functions, for the platform support code to call at appropriate times
 //
 // mDNS_GenerateFQDN() is called once on startup (typically from mDNSPlatformInit())
 // and then again on each subsequent change of the dot-local host name.
 //
+// !!!KRS
+// mDNS_GenerateGlobalFQDN() is called to register a domain name via Dynamic DNS update.  It should be
+// called on startup (after acquiring an IP address and DNS server) and on each change to the machine name
+// or registration domain.  The domain parameter is the domain in which the address record is to be registered,
+// e.g. "mycompany.com".  The full name is formed by appending this domain to the machine's host label.
+//
 // mDNS_RegisterInterface() is used by the platform support layer to inform mDNSCore of what
 // physical and/or logical interfaces are available for sending and receiving packets.
 // Typically it is called on startup for each available interface, but register/deregister may be
@@ -1418,6 +1988,16 @@ extern mStatus  mDNSPlatformTimeInit    (mDNSs32 *timenow);
 // -- Name-to-address records (A/AAAA)
 // -- Address-to-name records (PTR)
 // -- Host information (HINFO)
+// IMPORTANT: The specified mDNSInterfaceID MUST NOT be 0, -1, or -2; these values have special meaning
+//
+// mDNS_SetDynamicRegistrationDomain is used to enable dynamic update registrations of address records
+// in the specified domain.
+//
+// mDNS_RegisterDNS() is used by the platform support layer to provide the core with the addresses of
+// available domain name servers for unicast queries/updates.  RegisterDNS() should be called once for
+// each name server, typically at startup, or when a new name server becomes available.  DeregiterDNS()
+// must be called whenever a registered name server becomes unavailable.  DeregisterDNSList deregisters
+// all registered servers.  mDNS_DNSRegistered() returns true if one or more servers are registered in the core.
 //
 // mDNSCoreInitComplete() is called when the platform support layer is finished.
 // Typically this is at the end of mDNSPlatformInit(), but may be later
@@ -1430,14 +2010,21 @@ extern mStatus  mDNSPlatformTimeInit    (mDNSs32 *timenow);
 // not lightweight second-by-second CPU power management modes.)
 
 extern void     mDNS_GenerateFQDN(mDNS *const m);
+extern  void    mDNS_GenerateGlobalFQDN(mDNS *const m);
 extern mStatus  mDNS_RegisterInterface  (mDNS *const m, NetworkInterfaceInfo *set);
 extern void     mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *set);
+extern void     mDNS_RegisterDNS(mDNS *const m, mDNSv4Addr *const dnsAddr);
+extern void     mDNS_DeregisterDNS(mDNS *const m, mDNSv4Addr *const dnsAddr);
+extern void     mDNS_DeregisterDNSList(mDNS *const m);
+extern mDNSBool mDNS_DNSRegistered(mDNS *const m);
 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 *const dstaddr, const mDNSIPPort dstport, const mDNSInterfaceID InterfaceID, mDNSu8 ttl);
 extern void     mDNSCoreMachineSleep(mDNS *const m, mDNSBool wake);
 
+extern mDNSBool mDNSAddrIsDNSMulticast(const mDNSAddr *ip);
+
 // ***************************************************************************
 #if 0
 #pragma mark - Compile-Time assertion checks
@@ -1469,7 +2056,7 @@ struct mDNS_CompileTimeAssertionChecks
 
 // ***************************************************************************
 
-#ifdef __cplusplus
+#ifdef __cplusplus
        }
 #endif
 
index 65b6daf479bc29e3a40571fb19fccd953f19bff8..bcb0851c6e47d10f01dc93da0f661563937cb885 100755 (executable)
@@ -3,6 +3,8 @@
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
     Change History (most recent first):
 
 $Log: mDNSDebug.h,v $
+Revision 1.23  2004/05/18 23:51:25  cheshire
+Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
+
+Revision 1.22  2004/04/22 04:27:42  cheshire
+Spacing tidyup
+
+Revision 1.21  2004/04/14 23:21:41  ksekar
+Removed accidental checkin of MALLOC_DEBUGING flag in 1.20
+
+Revision 1.20  2004/04/14 23:09:28  ksekar
+Support for TSIG signed dynamic updates.
+
+Revision 1.19  2004/03/15 18:57:59  cheshire
+Undo last checkin that accidentally made verbose debugging the default for all targets
+
+Revision 1.18  2004/03/13 01:57:33  ksekar
+<rdar://problem/3192546>: DynDNS: Dynamic update of service records
+
+Revision 1.17  2004/01/28 21:14:23  cheshire
+Reconcile debug_mode and gDebugLogging into a single flag (mDNS_DebugMode)
+
+Revision 1.16  2003/12/09 01:30:06  rpantos
+Fix usage of ARGS... macros to build properly on Windows.
+
+Revision 1.15  2003/12/08 20:55:26  rpantos
+Move some definitions here from mDNSMacOSX.h.
+
 Revision 1.14  2003/08/12 19:56:24  cheshire
 Update to APSL 2.0
 
@@ -56,6 +85,8 @@ Merge in license terms from Quinn's copy, in preparation for Darwin release
 // Set MDNS_DEBUGMSGS to 1 to generate normal debugging messages
 // Set MDNS_DEBUGMSGS to 2 to generate verbose debugging messages
 // MDNS_DEBUGMSGS is normally set in the project options (or makefile) but can also be set here if desired
+// (If you edit the file here to turn on MDNS_DEBUGMSGS while you're debugging some code, be careful
+// not to accidentally check-in that change by mistake when you check in your other changes.)
 
 //#define MDNS_DEBUGMSGS 2
 
@@ -80,9 +111,9 @@ Merge in license terms from Quinn's copy, in preparation for Darwin release
 #define debugf debugf_
 extern void debugf_(const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(1,2);
 #else // If debug breaks are off, use a preprocessor trick to optimize those calls out of the code
-       #if( defined( __GNUC__ ) )
+       #if (defined(__GNUC__))
                #define debugf( ARGS... ) ((void)0)
-       #elif( defined( __MWERKS__ ) )
+       #elif (defined(__MWERKS__))
                #define debugf( ... )
        #else
                #define debugf 1 ? ((void)0) : (void)
@@ -93,9 +124,9 @@ extern void debugf_(const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(1,2);
 #define verbosedebugf verbosedebugf_
 extern void verbosedebugf_(const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(1,2);
 #else
-       #if( defined( __GNUC__ ) )
+       #if (defined(__GNUC__))
                #define verbosedebugf( ARGS... ) ((void)0)
-       #elif( defined( __MWERKS__ ) )
+       #elif (defined(__MWERKS__))
                #define verbosedebugf( ... )
        #else
                #define verbosedebugf 1 ? ((void)0) : (void)
@@ -103,7 +134,42 @@ extern void verbosedebugf_(const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(1
 #endif
 
 // LogMsg is used even in shipping code, to write truly serious error messages to syslog (or equivalent)
+extern int     mDNS_DebugMode; // If non-zero, LogMsg() writes to stderr instead of syslog
 extern void LogMsg(const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(1,2);
+extern void LogMsgIdent(const char *ident, const char *format, ...);
+extern void LogMsgNoIdent(const char *format, ...);
+
+// Set this symbol to 1 to do extra debug checks on malloc() and free()
+// Set this symbol to 2 to write a log message for every malloc() and free()
+#define MACOSX_MDNS_MALLOC_DEBUGGING 0
+
+#if MACOSX_MDNS_MALLOC_DEBUGGING >= 1
+extern void *mallocL(char *msg, unsigned int size);
+extern void freeL(char *msg, void *x);
+#else
+#define mallocL(X,Y) malloc(Y)
+#define freeL(X,Y) free(Y)
+#endif
+
+#if MACOSX_MDNS_MALLOC_DEBUGGING >= 2
+#define LogMalloc LogMsg
+#else
+       #if (defined( __GNUC__ ))
+               #define LogMalloc(ARGS...) ((void)0)
+       #elif (defined( __MWERKS__ ))
+               #define LogMalloc( ... )
+       #else
+               #define LogMalloc 1 ? ((void)0) : (void)
+       #endif
+#endif
+
+#define LogAllOperations 0
+
+#if LogAllOperations
+#define LogOperation LogMsg
+#else
+#define        LogOperation debugf
+#endif
 
 #ifdef __cplusplus
        }
diff --git a/mDNSCore/mDNSEmbeddedAPI.h b/mDNSCore/mDNSEmbeddedAPI.h
deleted file mode 100755 (executable)
index 3b53374..0000000
+++ /dev/null
@@ -1,1470 +0,0 @@
-/*
- * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- * 
- * @APPLE_LICENSE_HEADER_END@
-
-    Change History (most recent first):
-
-$Log: mDNSEmbeddedAPI.h,v $
-Revision 1.114.2.9  2004/04/22 03:17:35  cheshire
-Fix use of "struct __attribute__((__packed__))" so it only applies on GCC >= 2.9
-
-Revision 1.114.2.8  2004/03/30 06:55:37  cheshire
-Gave name to anonymous struct, to avoid errors on certain compilers.
-(Thanks to ramaprasad.kr@hp.com for reporting this.)
-
-Revision 1.114.2.7  2004/03/09 02:31:27  cheshire
-Remove erroneous underscore in 'packed_struct' (makes no difference now, but might in future)
-
-Revision 1.114.2.6  2004/03/02 02:55:25  cheshire
-<rdar://problem/3549576> Properly support "_services._dns-sd._udp" meta-queries
-
-Revision 1.114.2.5  2004/02/18 23:35:17  cheshire
-<rdar://problem/3488559>: Hard code domain enumeration functions to return ".local" only
-Also make mDNS_StopGetDomains() a no-op too, so that we don't get warning messages in syslog
-
-Revision 1.114.2.4  2004/01/28 23:29:20  cheshire
-Fix structure packing (only affects third-party Darwin developers)
-
-Revision 1.114.2.3  2003/12/05 00:03:34  cheshire
-<rdar://problem/3487869> Use buffer size MAX_ESCAPED_DOMAIN_NAME instead of 256
-
-Revision 1.114.2.2  2003/12/04 23:30:00  cheshire
-Add "#define MAX_ESCAPED_DOMAIN_NAME 1005", needed for Posix folder to build
-
-Revision 1.114.2.1  2003/12/03 11:07:58  cheshire
-<rdar://problem/3457718>: Stop and start of a service uses old ip address (with old port number)
-
-Revision 1.114  2003/08/29 19:44:15  cheshire
-<rdar://problem/3400967> Traffic reduction: Eliminate synchronized QUs when a new service appears
-1. Use m->RandomQueryDelay to impose a random delay in the range 0-500ms on queries
-   that already have at least one unique answer in the cache
-2. For these queries, go straight to QM, skipping QU
-
-Revision 1.113  2003/08/21 19:31:58  cheshire
-Cosmetic: Swap order of fields
-
-Revision 1.112  2003/08/21 19:27:36  cheshire
-<rdar://problem/3387878> Traffic reduction: No need to announce record for longer than TTL
-
-Revision 1.111  2003/08/21 02:21:50  cheshire
-<rdar://problem/3386473> Efficiency: Reduce repeated queries
-
-Revision 1.110  2003/08/20 23:39:31  cheshire
-<rdar://problem/3344098> Review syslog messages, and remove as appropriate
-
-Revision 1.109  2003/08/19 22:24:10  cheshire
-Comment change
-
-Revision 1.108  2003/08/19 22:20:00  cheshire
-<rdar://problem/3376721> Don't use IPv6 on interfaces that have a routable IPv4 address configured
-More minor refinements
-
-Revision 1.107  2003/08/19 06:48:25  cheshire
-<rdar://problem/3376552> Guard against excessive record updates
-Each record starts with 10 UpdateCredits.
-Every update consumes one UpdateCredit.
-UpdateCredits are replenished at a rate of one one per minute, up to a maximum of 10.
-As the number of UpdateCredits declines, the number of announcements is similarly scaled back.
-When fewer than 5 UpdateCredits remain, the first announcement is also delayed by an increasing amount.
-
-Revision 1.106  2003/08/19 04:49:28  cheshire
-<rdar://problem/3368159> Interaction between v4, v6 and dual-stack hosts not working quite right
-1. A dual-stack host should only suppress its own query if it sees the same query from other hosts on BOTH IPv4 and IPv6.
-2. When we see the first v4 (or first v6) member of a group, we re-trigger questions and probes on that interface.
-3. When we see the last v4 (or v6) member of a group go away, we revalidate all the records received on that interface.
-
-Revision 1.105  2003/08/19 02:33:37  cheshire
-Update comments
-
-Revision 1.104  2003/08/19 02:31:11  cheshire
-<rdar://problem/3378386> mDNSResponder overenthusiastic with final expiration queries
-Final expiration queries now only mark the question for sending on the particular interface
-pertaining to the record that's expiring.
-
-Revision 1.103  2003/08/18 19:05:44  cheshire
-<rdar://problem/3382423> UpdateRecord not working right
-Added "newrdlength" field to hold new length of updated rdata
-
-Revision 1.102  2003/08/16 03:39:00  cheshire
-<rdar://problem/3338440> InterfaceID -1 indicates "local only"
-
-Revision 1.101  2003/08/15 20:16:02  cheshire
-<rdar://problem/3366590> mDNSResponder takes too much RPRVT
-We want to avoid touching the rdata pages, so we don't page them in.
-1. RDLength was stored with the rdata, which meant touching the page just to find the length.
-   Moved this from the RData to the ResourceRecord object.
-2. To avoid unnecessarily touching the rdata just to compare it,
-   compute a hash of the rdata and store the hash in the ResourceRecord object.
-
-Revision 1.100  2003/08/14 19:29:04  cheshire
-<rdar://problem/3378473> Include cache records in SIGINFO output
-Moved declarations of DNSTypeName() and GetRRDisplayString to mDNSEmbeddedAPI.h so daemon.c can use them
-
-Revision 1.99  2003/08/14 02:17:05  cheshire
-<rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
-
-Revision 1.98  2003/08/12 19:56:23  cheshire
-Update to APSL 2.0
-
-Revision 1.97  2003/08/12 14:59:27  cheshire
-<rdar://problem/3374490> Rate-limiting blocks some legitimate responses
-When setting LastMCTime also record LastMCInterface. When checking LastMCTime to determine
-whether to suppress the response, also check LastMCInterface to see if it matches.
-
-Revision 1.96  2003/08/12 13:57:04  cheshire
-<rdar://problem/3323817> Improve cache performance
-Changed the number of hash table slots from 37 to 499
-
-Revision 1.95  2003/08/09 00:55:02  cheshire
-<rdar://problem/3366553> mDNSResponder is taking 20-30% of the CPU
-Don't scan the whole cache after every packet.
-
-Revision 1.94  2003/08/09 00:35:29  cheshire
-
-Revision 1.93  2003/08/08 18:55:48  cheshire
-<rdar://problem/3370365> Guard against time going backwards
-
-Revision 1.92  2003/08/08 18:36:04  cheshire
-<rdar://problem/3344154> Only need to revalidate on interface removal on platforms that have the PhantomInterfaces bug
-
-Revision 1.91  2003/08/06 21:33:39  cheshire
-Fix compiler warnings on PocketPC 2003 (Windows CE)
-
-Revision 1.90  2003/08/06 20:30:17  cheshire
-Add structure definition for rdataMX (not currently used, but good to have it for completeness)
-
-Revision 1.89  2003/08/06 18:58:19  cheshire
-Update comments
-
-Revision 1.88  2003/07/24 23:45:44  cheshire
-To eliminate compiler warnings, changed definition of mDNSBool from
-"unsigned char" to "int", since "int" is in fact truly the type that C uses
-for the result of comparison operators (a<b) and logical operators (a||b)
-
-Revision 1.87  2003/07/22 23:57:20  cheshire
-Move platform-layer function prototypes from mDNSEmbeddedAPI.h to mDNSPlatformFunctions.h where they belong
-
-Revision 1.86  2003/07/20 03:52:02  ksekar
-Bug #: <rdar://problem/3320722>: Feature: New Rendezvous APIs (#7875) (mDNSResponder component)
-Added error type for incompatibility between daemon and client versions
-
-Revision 1.85  2003/07/19 03:23:13  cheshire
-<rdar://problem/2986147> mDNSResponder needs to receive and cache larger records
-
-Revision 1.84  2003/07/18 23:52:12  cheshire
-To improve consistency of field naming, global search-and-replace:
-NextProbeTime    -> NextScheduledProbe
-NextResponseTime -> NextScheduledResponse
-
-Revision 1.83  2003/07/18 00:29:59  cheshire
-<rdar://problem/3268878> Remove mDNSResponder version from packet header and use HINFO record instead
-
-Revision 1.82  2003/07/17 17:35:04  cheshire
-<rdar://problem/3325583> Rate-limit responses, to guard against packet flooding
-
-Revision 1.81  2003/07/16 05:01:36  cheshire
-Add fields 'LargeAnswers' and 'ExpectUnicastResponse' in preparation for
-<rdar://problem/3315761> Need to implement "unicast response" request, using top bit of qclass
-
-Revision 1.80  2003/07/15 01:55:12  cheshire
-<rdar://problem/3315777> Need to implement service registration with subtypes
-
-Revision 1.79  2003/07/13 02:28:00  cheshire
-<rdar://problem/3325166> SendResponses didn't all its responses
-Delete all references to RRInterfaceActive -- it's now superfluous
-
-Revision 1.78  2003/07/13 01:47:53  cheshire
-Fix one error and one warning in the Windows build
-
-Revision 1.77  2003/07/11 01:32:38  cheshire
-Syntactic cleanup (no change to funcationality): Now that we only have one host name,
-rename field "hostname1" to "hostname", and field "RR_A1" to "RR_A".
-
-Revision 1.76  2003/07/11 01:28:00  cheshire
-<rdar://problem/3161289> No more local.arpa
-
-Revision 1.75  2003/07/02 21:19:45  cheshire
-<rdar://problem/3313413> Update copyright notices, etc., in source code comments
-
-Revision 1.74  2003/07/02 02:41:23  cheshire
-<rdar://problem/2986146> mDNSResponder needs to start with a smaller cache and then grow it as needed
-
-Revision 1.73  2003/06/10 04:24:39  cheshire
-<rdar://problem/3283637> React when we observe other people query unsuccessfully for a record that's in our cache
-Some additional refinements:
-Don't try to do this for unicast-response queries
-better tracking of Qs and KAs in multi-packet KA lists
-
-Revision 1.72  2003/06/10 01:46:27  cheshire
-Add better comments explaining how these data structures are intended to be used from the client layer
-
-Revision 1.71  2003/06/07 06:45:05  cheshire
-<rdar://problem/3283666> No need for multiple machines to all be sending the same queries
-
-Revision 1.70  2003/06/07 04:50:53  cheshire
-<rdar://problem/3283637> React when we observe other people query unsuccessfully for a record that's in our cache
-
-Revision 1.69  2003/06/07 04:22:17  cheshire
-Add MsgBuffer for error log and debug messages
-
-Revision 1.68  2003/06/07 01:46:38  cheshire
-<rdar://problem/3283540> When query produces zero results, call mDNS_Reconfirm() on any antecedent records
-
-Revision 1.67  2003/06/07 01:22:14  cheshire
-<rdar://problem/3283516> mDNSResponder needs an mDNS_Reconfirm() function
-
-Revision 1.66  2003/06/07 00:59:43  cheshire
-<rdar://problem/3283454> Need some randomness to spread queries on the network
-
-Revision 1.65  2003/06/06 21:41:11  cheshire
-For consistency, mDNS_StopQuery() should return an mStatus result, just like all the other mDNSCore routines
-
-Revision 1.64  2003/06/06 21:38:55  cheshire
-Renamed 'NewData' as 'FreshData' (The data may not be new data, just a refresh of data that we
-already had in our cache. This refreshes our TTL on the data, but the data itself stays the same.)
-
-Revision 1.63  2003/06/06 17:20:14  cheshire
-For clarity, rename question fields name/rrtype/rrclass as qname/qtype/qclass
-(Global search-and-replace; no functional change to code execution.)
-
-Revision 1.62  2003/06/04 01:25:33  cheshire
-<rdar://problem/3274950> Cannot perform multi-packet known-answer suppression messages
-Display time interval between first and subsequent queries
-
-Revision 1.61  2003/06/03 05:02:16  cheshire
-<rdar://problem/3277080> Duplicate registrations not handled as efficiently as they should be
-
-Revision 1.60  2003/05/31 00:09:49  cheshire
-<rdar://problem/3274862> Add ability to discover what services are on a network
-
-Revision 1.59  2003/05/29 06:11:35  cheshire
-<rdar://problem/3272214>:      Report if there appear to be too many "Resolve" callbacks
-
-Revision 1.58  2003/05/29 05:48:06  cheshire
-Minor fix for when generating printf warnings: mDNS_snprintf arguments are now 3,4
-
-Revision 1.57  2003/05/26 03:21:27  cheshire
-Tidy up address structure naming:
-mDNSIPAddr         => mDNSv4Addr (for consistency with mDNSv6Addr)
-mDNSAddr.addr.ipv4 => mDNSAddr.ip.v4
-mDNSAddr.addr.ipv6 => mDNSAddr.ip.v6
-
-Revision 1.56  2003/05/26 03:01:27  cheshire
-<rdar://problem/3268904> sprintf/vsprintf-style functions are unsafe; use snprintf/vsnprintf instead
-
-Revision 1.55  2003/05/26 00:47:30  cheshire
-Comment clarification
-
-Revision 1.54  2003/05/24 16:39:48  cheshire
-<rdar://problem/3268631> SendResponses also needs to handle multihoming better
-
-Revision 1.53  2003/05/23 02:15:37  cheshire
-Fixed misleading use of the term "duplicate suppression" where it should have
-said "known answer suppression". (Duplicate answer suppression is something
-different, and duplicate question suppression is yet another thing, so the use
-of the completely vague term "duplicate suppression" was particularly bad.)
-
-Revision 1.52  2003/05/22 02:29:22  cheshire
-<rdar://problem/2984918> SendQueries needs to handle multihoming better
-Complete rewrite of SendQueries. Works much better now :-)
-
-Revision 1.51  2003/05/21 20:14:55  cheshire
-Fix comments and warnings
-
-Revision 1.50  2003/05/14 07:08:36  cheshire
-<rdar://problem/3159272> mDNSResponder should be smarter about reconfigurations
-Previously, when there was any network configuration change, mDNSResponder
-would tear down the entire list of active interfaces and start again.
-That was very disruptive, and caused the entire cache to be flushed,
-and caused lots of extra network traffic. Now it only removes interfaces
-that have really gone, and only adds new ones that weren't there before.
-
-Revision 1.49  2003/05/07 01:49:36  cheshire
-Remove "const" in ConstructServiceName prototype
-
-Revision 1.48  2003/05/07 00:18:44  cheshire
-Fix typo: "kDNSQClass_Mask" should be "kDNSClass_Mask"
-
-Revision 1.47  2003/05/06 00:00:46  cheshire
-<rdar://problem/3248914> Rationalize naming of domainname manipulation functions
-
-Revision 1.46  2003/04/30 20:39:09  cheshire
-Add comment
-
-Revision 1.45  2003/04/29 00:40:50  cheshire
-Fix compiler warnings
-
-Revision 1.44  2003/04/26 02:41:56  cheshire
-<rdar://problem/3241281> Change timenow from a local variable to a structure member
-
-Revision 1.43  2003/04/25 01:45:56  cheshire
-<rdar://problem/3240002> mDNS_RegisterNoSuchService needs to include a host name
-
-Revision 1.42  2003/04/15 20:58:31  jgraessl
-
-Bug #: 3229014
-Added a hash to lookup records in the cache.
-
-Revision 1.41  2003/04/15 18:09:13  jgraessl
-
-Bug #: 3228892
-Reviewed by: Stuart Cheshire
-Added code to keep track of when the next cache item will expire so we can
-call TidyRRCache only when necessary.
-
-Revision 1.40  2003/03/29 01:55:19  cheshire
-<rdar://problem/3212360> mDNSResponder sometimes suffers false self-conflicts when it sees its own packets
-Solution: Major cleanup of packet timing and conflict handling rules
-
-Revision 1.39  2003/03/27 03:30:55  cheshire
-<rdar://problem/3210018> Name conflicts not handled properly, resulting in memory corruption, and eventual crash
-Problem was that HostNameCallback() was calling mDNS_DeregisterInterface(), which is not safe in a callback
-Fixes:
-1. Make mDNS_DeregisterInterface() safe to call from a callback
-2. Make HostNameCallback() use mDNS_DeadvertiseInterface() instead
-   (it never really needed to deregister the interface at all)
-
-Revision 1.38  2003/03/15 04:40:36  cheshire
-Change type called "mDNSOpaqueID" to the more descriptive name "mDNSInterfaceID"
-
-Revision 1.37  2003/03/14 21:34:11  cheshire
-<rdar://problem/3176950> Can't setup and print to Lexmark PS printers via Airport Extreme
-Increase size of cache rdata from 512 to 768
-
-Revision 1.36  2003/03/05 03:38:35  cheshire
-Bug #: 3185731 Bogus error message in console: died or deallocated, but no record of client can be found!
-Fixed by leaving client in list after conflict, until client explicitly deallocates
-
-Revision 1.35  2003/02/21 02:47:54  cheshire
-Bug #: 3099194 mDNSResponder needs performance improvements
-Several places in the code were calling CacheRRActive(), which searched the entire
-question list every time, to see if this cache resource record answers any question.
-Instead, we now have a field "CRActiveQuestion" in the resource record structure
-
-Revision 1.34  2003/02/21 01:54:08  cheshire
-Bug #: 3099194 mDNSResponder needs performance improvements
-Switched to using new "mDNS_Execute" model (see "Implementer Notes.txt")
-
-Revision 1.33  2003/02/20 06:48:32  cheshire
-Bug #: 3169535 Xserve RAID needs to do interface-specific registrations
-Reviewed by: Josh Graessley, Bob Bradley
-
-Revision 1.32  2003/01/31 03:35:59  cheshire
-Bug #: 3147097 mDNSResponder sometimes fails to find the correct results
-When there were *two* active questions in the list, they were incorrectly
-finding *each other* and *both* being marked as duplicates of another question
-
-Revision 1.31  2003/01/29 02:46:37  cheshire
-Fix for IPv6:
-A physical interface is identified solely by its InterfaceID (not by IP and type).
-On a given InterfaceID, mDNSCore may send both v4 and v6 multicasts.
-In cases where the requested outbound protocol (v4 or v6) is not supported on
-that InterfaceID, the platform support layer should simply discard that packet.
-
-Revision 1.30  2003/01/29 01:47:08  cheshire
-Rename 'Active' to 'CRActive' or 'InterfaceActive' for improved clarity
-
-Revision 1.29  2003/01/28 05:23:43  cheshire
-Bug #: 3147097 mDNSResponder sometimes fails to find the correct results
-Add 'Active' flag for interfaces
-
-Revision 1.28  2003/01/28 01:35:56  cheshire
-Revise comment about ThisQInterval to reflect new semantics
-
-Revision 1.27  2003/01/13 23:49:42  jgraessl
-Merged changes for the following fixes in to top of tree:
-3086540  computer name changes not handled properly
-3124348  service name changes are not properly handled
-3124352  announcements sent in pairs, failing chattiness test
-
-Revision 1.26  2002/12/23 22:13:28  jgraessl
-
-Reviewed by: Stuart Cheshire
-Initial IPv6 support for mDNSResponder.
-
-Revision 1.25  2002/09/21 20:44:49  zarzycki
-Added APSL info
-
-Revision 1.24  2002/09/19 23:47:35  cheshire
-Added mDNS_RegisterNoSuchService() function for assertion of non-existence
-of a particular named service
-
-Revision 1.23  2002/09/19 21:25:34  cheshire
-mDNS_snprintf() doesn't need to be in a separate file
-
-Revision 1.22  2002/09/19 04:20:43  cheshire
-Remove high-ascii characters that confuse some systems
-
-Revision 1.21  2002/09/17 01:06:35  cheshire
-Change mDNS_AdvertiseLocalAddresses to be a parameter to mDNS_Init()
-
-Revision 1.20  2002/09/16 18:41:41  cheshire
-Merge in license terms from Quinn's copy, in preparation for Darwin release
-
-*/
-
-#ifndef __mDNSClientAPI_h
-#define __mDNSClientAPI_h
-
-#include <stdarg.h>            // stdarg.h is required for for va_list support for the mDNS_vsnprintf declaration
-#include "mDNSDebug.h"
-
-#ifdef __cplusplus
-       extern "C" {
-#endif
-
-// ***************************************************************************
-// Function scope indicators
-
-// If you see "mDNSlocal" before a function name in a C file, it means the function is not callable outside this file
-#ifndef mDNSlocal
-#define mDNSlocal static
-#endif
-// If you see "mDNSexport" before a symbol in a C file, it means the symbol is exported for use by clients
-// For every "mDNSexport" in a C file, there needs to be a corresponding "extern" declaration in some header file
-// (When a C file #includes a header file, the "extern" declarations tell the compiler:
-// "This symbol exists -- but not necessarily in this C file.")
-#ifndef mDNSexport
-#define mDNSexport
-#endif
-
-// ***************************************************************************
-// Structure packing macro
-
-// If we're not using GNUC, it's not fatal.
-// Most compilers naturally pack the on-the-wire structures correctly anyway, so a plain "struct" is usually fine.
-// In the event that structures are not packed correctly, mDNS_Init() will detect this and report an error, so the
-// developer will know what's wrong, and can investigate what needs to be done on that compiler to provide proper packing.
-#ifndef packedstruct
- #if ((__GNUC__ > 2) || ((__GNUC__ == 2) && (__GNUC_MINOR__ >= 9)))
-  #define packedstruct struct __attribute__((__packed__))
-  #define packedunion  union  __attribute__((__packed__))
- #else
-  #define packedstruct struct
-  #define packedunion  union
- #endif
-#endif
-
-// ***************************************************************************
-#if 0
-#pragma mark - DNS Resource Record class and type constants
-#endif
-
-typedef enum                                                   // From RFC 1035
-       {
-       kDNSClass_IN               = 1,         // Internet
-       kDNSClass_CS               = 2,         // CSNET
-       kDNSClass_CH               = 3,         // CHAOS
-       kDNSClass_HS               = 4,         // Hesiod
-       kDNSClass_NONE             = 254,       // Used in DNS UPDATE [RFC 2136]
-
-       kDNSClass_Mask             = 0x7FFF,// Multicast DNS uses the bottom 15 bits to identify the record class...
-       kDNSClass_UniqueRRSet      = 0x8000,// ... and the top bit indicates that all other cached records are now invalid
-
-       kDNSQClass_ANY             = 255,       // Not a DNS class, but a DNS query class, meaning "all classes"
-       kDNSQClass_UnicastResponse = 0x8000     // Top bit set in a question means "unicast response acceptable"
-       } DNS_ClassValues;
-
-typedef enum                           // From RFC 1035
-       {
-       kDNSType_A = 1,                 //  1 Address
-       kDNSType_NS,                    //  2 Name Server
-       kDNSType_MD,                    //  3 Mail Destination
-       kDNSType_MF,                    //  4 Mail Forwarder
-       kDNSType_CNAME,                 //  5 Canonical Name
-       kDNSType_SOA,                   //  6 Start of Authority
-       kDNSType_MB,                    //  7 Mailbox
-       kDNSType_MG,                    //  8 Mail Group
-       kDNSType_MR,                    //  9 Mail Rename
-       kDNSType_NULL,                  // 10 NULL RR
-       kDNSType_WKS,                   // 11 Well-known-service
-       kDNSType_PTR,                   // 12 Domain name pointer
-       kDNSType_HINFO,                 // 13 Host information
-       kDNSType_MINFO,                 // 14 Mailbox information
-       kDNSType_MX,                    // 15 Mail Exchanger
-       kDNSType_TXT,                   // 16 Arbitrary text string
-
-       kDNSType_AAAA = 28,             // 28 IPv6 address
-       kDNSType_SRV = 33,              // 33 Service record
-
-       kDNSQType_ANY = 255             // Not a DNS type, but a DNS query type, meaning "all types"
-       } DNS_TypeValues;
-
-// ***************************************************************************
-#if 0
-#pragma mark - Simple types
-#endif
-
-// mDNS defines its own names for these common types to simplify portability across
-// multiple platforms that may each have their own (different) names for these types.
-typedef          int   mDNSBool;
-typedef   signed char  mDNSs8;
-typedef unsigned char  mDNSu8;
-typedef   signed short mDNSs16;
-typedef unsigned short mDNSu16;
-#if _LP64
-typedef   signed int   mDNSs32;
-typedef unsigned int   mDNSu32;
-#else
-typedef   signed long  mDNSs32;
-typedef unsigned long  mDNSu32;
-#endif
-
-// 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;
-
-// 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
-// register for the sake of efficiency, and compared for equality or inequality, but don't forget --
-// just because it is in a register doesn't mean it is an integer. Operations like greater than,
-// less than, add, multiply, increment, decrement, etc., are undefined for opaque identifiers,
-// and if you make the mistake of trying to do those using the NotAnInteger field, then you'll
-// find you get code that doesn't work consistently on big-endian and little-endian machines.
-typedef packedunion { mDNSu8 b[2]; mDNSu16 NotAnInteger; } mDNSOpaque16;
-typedef packedunion { mDNSu8 b[4]; mDNSu32 NotAnInteger; } mDNSOpaque32;
-typedef packedunion { mDNSu8 b[16]; mDNSu16 w[8]; mDNSu32 l[4]; } mDNSOpaque128;
-
-typedef mDNSOpaque16  mDNSIPPort;              // An IP port is a two-byte opaque identifier (not an integer)
-typedef mDNSOpaque32  mDNSv4Addr;              // An IP address is a four-byte opaque identifier (not an integer)
-typedef mDNSOpaque128 mDNSv6Addr;              // An IPv6 address is a 16-byte opaque identifier (not an integer)
-
-enum
-       {
-       mDNSAddrType_None    = 0,
-       mDNSAddrType_IPv4    = 4,
-       mDNSAddrType_IPv6    = 6,
-       mDNSAddrType_Unknown = ~0       // Special marker value used in known answer list recording
-       };
-
-typedef struct
-       {
-       mDNSs32 type;
-       union { mDNSv6Addr v6; mDNSv4Addr v4; } ip;
-       } mDNSAddr;
-
-enum { mDNSfalse = 0, mDNStrue = 1 };
-
-#define mDNSNULL 0L
-
-enum
-       {
-       mStatus_Waiting           = 1,
-       mStatus_NoError           = 0,
-
-       // mDNS return values are in the range FFFE FF00 (-65792) to FFFE FFFF (-65537)
-       // The top end of the range (FFFE FFFF) is used for error codes;
-       // the bottom end of the range (FFFE FF00) is used for non-error values;
-
-       // Error codes:
-       mStatus_UnknownErr        = -65537,             // 0xFFFE FFFF
-       mStatus_NoSuchNameErr     = -65538,
-       mStatus_NoMemoryErr       = -65539,
-       mStatus_BadParamErr       = -65540,
-       mStatus_BadReferenceErr   = -65541,
-       mStatus_BadStateErr       = -65542,
-       mStatus_BadFlagsErr       = -65543,
-       mStatus_UnsupportedErr    = -65544,
-       mStatus_NotInitializedErr = -65545,
-       mStatus_NoCache           = -65546,
-       mStatus_AlreadyRegistered = -65547,
-       mStatus_NameConflict      = -65548,
-       mStatus_Invalid           = -65549,
-       //                        = -65550,
-       mStatus_Incompatible      = -65551,
-       mStatus_BadInterfaceErr   = -65552,
-
-       // -65553 - -65789 currently unused
-
-       // Non-error values:
-       mStatus_GrowCache         = -65790,
-       mStatus_ConfigChanged     = -65791,
-       mStatus_MemFree           = -65792              // 0xFFFE FF00
-       };
-
-typedef mDNSs32 mStatus;
-
-// RFC 1034/1035 specify that a domain label consists of a length byte plus up to 63 characters
-#define MAX_DOMAIN_LABEL 63
-typedef struct { mDNSu8 c[ 64]; } domainlabel;         // One label: length byte and up to 63 characters
-
-// RFC 1034/1035 specify that a domain name, including length bytes, data bytes, and terminating zero, may be up to 255 bytes long
-#define MAX_DOMAIN_NAME 255
-typedef struct { mDNSu8 c[256]; } domainname;          // Up to 255 bytes of length-prefixed domainlabels
-
-typedef struct { mDNSu8 c[256]; } UTF8str255;          // Null-terminated C string
-
-// The longest legal textual form of a DNS name is 1005 bytes, including the C-string terminating NULL at the end.
-// Explanation:
-// When a native domainname object is converted to printable textual form using ConvertDomainNameToCString(),
-// non-printing characters are represented in the conventional DNS way, as '\ddd', where ddd is a three-digit decimal number.
-// The longest legal domain name is 255 bytes, in the form of four labels as shown below:
-// Length byte, 63 data bytes, length byte, 63 data bytes, length byte, 63 data bytes, length byte, 61 data bytes, zero byte.
-// Each label is encoded textually as characters followed by a trailing dot.
-// If every character has to be represented as a four-byte escape sequence, then this makes the maximum textual form four labels
-// plus the C-string terminating NULL as shown below:
-// 63*4+1 + 63*4+1 + 63*4+1 + 61*4+1 + 1 = 1005.
-// Note that MAX_ESCAPED_DOMAIN_LABEL is not normally used: If you're only decoding a single label, escaping is usually not required.
-// It is for domain names, where dots are used as label separators, that proper escaping is vital.
-#define MAX_ESCAPED_DOMAIN_LABEL 254
-#define MAX_ESCAPED_DOMAIN_NAME 1005
-
-// ***************************************************************************
-#if 0
-#pragma mark - Resource Record structures
-#endif
-
-// Authoritative Resource Records:
-// There are four basic types: Shared, Advisory, Unique, Known Unique
-
-// * Shared Resource Records do not have to be unique
-// -- Shared Resource Records are used for DNS-SD service PTRs
-// -- It is okay for several hosts to have RRs with the same name but different RDATA
-// -- We use a random delay on responses to reduce collisions when all the hosts respond to the same query
-// -- These RRs typically have moderately high TTLs (e.g. one hour)
-// -- These records are announced on startup and topology changes for the benefit of passive listeners
-// -- These records send a goodbye packet when deregistering
-//
-// * Advisory Resource Records are like Shared Resource Records, except they don't send a goodbye packet
-//
-// * Unique Resource Records should be unique among hosts within any given mDNS scope
-// -- The majority of Resource Records are of this type
-// -- If two entities on the network have RRs with the same name but different RDATA, this is a conflict
-// -- Responses may be sent immediately, because only one host should be responding to any particular query
-// -- These RRs typically have low TTLs (e.g. ten seconds)
-// -- On startup and after topology changes, a host issues queries to verify uniqueness
-
-// * Known Unique Resource Records are treated like Unique Resource Records, except that mDNS does
-// not have to verify their uniqueness because this is already known by other means (e.g. the RR name
-// is derived from the host's IP or Ethernet address, which is already known to be a unique identifier).
-
-// Summary of properties of different record types:
-// Probe?    Does this record type send probes before announcing?
-// Conflict? Does this record type react if we observe an apparent conflict?
-// Goodbye?  Does this record type send a goodbye packet on departure?
-//
-//               Probe? Conflict? Goodbye? Notes
-// Unregistered                            Should not appear in any list (sanity check value)
-// Shared         No      No       Yes     e.g. Service PTR record
-// Deregistering  No      No       Yes     Shared record about to announce its departure and leave the list
-// Advisory       No      No       No
-// Unique         Yes     Yes      No      Record intended to be unique -- will probe to verify
-// Verified       Yes     Yes      No      Record has completed probing, and is verified unique
-// KnownUnique    No      Yes      No      Record is assumed by other means to be unique
-
-// Valid lifecycle of a record:
-// Unregistered ->                   Shared      -> Deregistering -(goodbye)-> Unregistered
-// Unregistered ->                   Advisory                               -> Unregistered
-// Unregistered -> Unique -(probe)-> Verified                               -> Unregistered
-// Unregistered ->                   KnownUnique                            -> Unregistered
-
-// Each Authoritative kDNSRecordType has only one bit set. This makes it easy to quickly see if a record
-// is one of a particular set of types simply by performing the appropriate bitwise masking operation.
-
-// Cache Resource Records (received from the network):
-// There are four basic types: Answer, Unique Answer, Additional, Unique Additional
-// Bit 7 (the top bit) of kDNSRecordType is always set for Cache Resource Records; always clear for Authoritative Resource Records
-// Bit 6 (value 0x40) is set for answer records; clear for additional records
-// Bit 5 (value 0x20) is set for records received with the kDNSClass_UniqueRRSet
-
-enum
-       {
-       kDNSRecordTypeUnregistered     = 0x00,  // Not currently in any list
-       kDNSRecordTypeDeregistering    = 0x01,  // Shared record about to announce its departure and leave the list
-
-       kDNSRecordTypeUnique           = 0x02,  // Will become a kDNSRecordTypeVerified when probing is complete
-
-       kDNSRecordTypeAdvisory         = 0x04,  // Like Shared, but no goodbye packet
-       kDNSRecordTypeShared           = 0x08,  // Shared means record name does not have to be unique -- use random delay on responses
-       kDNSRecordTypeVerified         = 0x10,  // Unique means mDNS should check that name is unique (and then send immediate responses)
-       kDNSRecordTypeKnownUnique      = 0x20,  // Known Unique means mDNS can assume name is unique without checking
-
-       kDNSRecordTypeUniqueMask       = (kDNSRecordTypeUnique | kDNSRecordTypeVerified | kDNSRecordTypeKnownUnique),
-       kDNSRecordTypeActiveMask       = (kDNSRecordTypeAdvisory | kDNSRecordTypeShared | kDNSRecordTypeVerified | kDNSRecordTypeKnownUnique),
-
-       kDNSRecordTypePacketAdd        = 0x80,  // Received in the Additional Section of a DNS Response
-       kDNSRecordTypePacketAddUnique  = 0xA0,  // Received in the Additional Section of a DNS Response with kDNSClass_UniqueRRSet set
-       kDNSRecordTypePacketAns        = 0xC0,  // Received in the Answer Section of a DNS Response
-       kDNSRecordTypePacketAnsUnique  = 0xE0,  // Received in the Answer Section of a DNS Response with kDNSClass_UniqueRRSet set
-
-       kDNSRecordTypePacketAnsMask    = 0x40,  // True for PacketAns       and PacketAnsUnique
-       kDNSRecordTypePacketUniqueMask = 0x20   // True for PacketAddUnique and PacketAnsUnique
-       };
-
-typedef packedstruct { mDNSu16 priority; mDNSu16 weight; mDNSIPPort port; domainname target; } rdataSRV;
-typedef packedstruct { mDNSu16 preference; domainname exchange; } rdataMX;
-
-// StandardAuthRDSize is 264 (256+8), which is large enough to hold a maximum-sized SRV record
-// MaximumRDSize is 8K the absolute maximum we support (at least for now)
-#define StandardAuthRDSize 264
-#define MaximumRDSize 8192
-
-// InlineCacheRDSize is 64
-// Records received from the network with rdata this size or less have their rdata stored right in the CacheRecord object
-// Records received from the network with rdata larger than this have additional storage allocated for the rdata
-// A quick unscientific sample from a busy network at Apple with lots of machines revealed this:
-// 1461 records in cache
-// 292 were one-byte TXT records
-// 136 were four-byte A records
-// 184 were sixteen-byte AAAA records
-// 780 were various PTR, TXT and SRV records from 12-64 bytes
-// Only 69 records had rdata bigger than 64 bytes
-#define InlineCacheRDSize 64
-
-typedef union
-       {
-       mDNSu8      data[StandardAuthRDSize];
-       mDNSv4Addr  ip;                 // For 'A' record
-       mDNSv6Addr  ipv6;               // For 'AAAA' record
-       domainname  name;               // For PTR and CNAME records
-       UTF8str255  txt;                // For TXT record
-       rdataSRV    srv;                // For SRV record
-       rdataMX     mx;                 // For MX record
-       } RDataBody;
-
-typedef struct
-       {
-       mDNSu16    MaxRDLength; // Amount of storage allocated for rdata (usually sizeof(RDataBody))
-       RDataBody  u;
-       } RData;
-#define sizeofRDataHeader (sizeof(RData) - sizeof(RDataBody))
-
-typedef struct AuthRecord_struct AuthRecord;
-typedef struct CacheRecord_struct CacheRecord;
-typedef struct ResourceRecord_struct ResourceRecord;
-typedef struct DNSQuestion_struct DNSQuestion;
-typedef struct mDNS_struct mDNS;
-typedef struct mDNS_PlatformSupport_struct mDNS_PlatformSupport;
-
-// Note: Within an mDNSRecordCallback mDNS all API calls are legal except mDNS_Init(), mDNS_Close(), mDNS_Execute() 
-typedef void mDNSRecordCallback(mDNS *const m, AuthRecord *const rr, mStatus result);
-
-// Note:
-// Restrictions: An mDNSRecordUpdateCallback may not make any mDNS API calls.
-// The intent of this callback is to allow the client to free memory, if necessary.
-// The internal data structures of the mDNS code may not be in a state where mDNS API calls may be made safely.
-typedef void mDNSRecordUpdateCallback(mDNS *const m, AuthRecord *const rr, RData *OldRData);
-
-struct ResourceRecord_struct
-       {
-       mDNSu8          RecordType;                     // See enum above
-       mDNSInterfaceID InterfaceID;            // Set if this RR is specific to one interface
-                                                                               // For records received off the wire, InterfaceID is *always* set to the receiving interface
-                                                                               // For our authoritative records, InterfaceID is usually zero, except for those few records
-                                                                               // that are interface-specific (e.g. address records, especially linklocal addresses)
-       domainname      name;                           
-       mDNSu16         rrtype;
-       mDNSu16         rrclass;
-       mDNSu32         rroriginalttl;          // In seconds
-       mDNSu16         rdlength;                       // Size of the raw rdata, in bytes
-       mDNSu16         rdestimate;                     // Upper bound on size of rdata after name compression
-       mDNSu32         namehash;                       // Name-based (i.e. case insensitive) hash of name
-       mDNSu32         rdatahash;                      // 32-bit hash of the raw rdata
-       mDNSu32         rdnamehash;                     // Set if this rdata contains a domain name (e.g. PTR, SRV, CNAME etc.)
-       RData           *rdata;                         // Pointer to storage for this rdata
-       };
-
-struct AuthRecord_struct
-       {
-       // For examples of how to set up this structure for use in mDNS_Register(),
-       // see mDNS_AdvertiseInterface() or mDNS_RegisterService().
-       // Basically, resrec and persistent metadata need to be set up before calling mDNS_Register().
-       // mDNS_SetupResourceRecord() is avaliable as a helper routine to set up most fields to sensible default values for you
-
-       AuthRecord     *next;                           // Next in list; first element of structure for efficiency reasons
-       ResourceRecord  resrec;
-
-       // Persistent metadata for Authoritative Records
-       AuthRecord     *Additional1;            // Recommended additional record to include in response
-       AuthRecord     *Additional2;            // Another additional
-       AuthRecord     *DependentOn;            // This record depends on another for its uniqueness checking
-       AuthRecord     *RRSet;                          // This unique record is part of an RRSet
-       mDNSRecordCallback *RecordCallback;     // Callback function to call for state changes
-       void           *RecordContext;          // Context parameter for the callback function
-       mDNSu8          HostTarget;                     // Set if the target of this record (PTR, CNAME, SRV, etc.) is our host name
-
-       // Transient state for Authoritative Records
-       mDNSu8          Acknowledged;           // Set if we've given the success callback to the client
-       mDNSu8          ProbeCount;                     // Number of probes remaining before this record is valid (kDNSRecordTypeUnique)
-       mDNSu8          AnnounceCount;          // Number of announcements remaining (kDNSRecordTypeShared)
-       mDNSu8          IncludeInProbe;         // Set if this RR is being put into a probe right now
-       mDNSInterfaceID ImmedAnswer;            // Someone on this interface issued a query we need to answer (all-ones for all interfaces)
-       mDNSInterfaceID ImmedAdditional;        // Hint that we might want to also send this record, just to be helpful
-       mDNSInterfaceID SendRNow;                       // The interface this query is being sent on right now
-       mDNSv4Addr      v4Requester;            // Recent v4 query for this record, or all-ones if more than one recent query
-       mDNSv6Addr      v6Requester;            // Recent v6 query for this record, or all-ones if more than one recent query
-       AuthRecord     *NextResponse;           // Link to the next element in the chain of responses to generate
-       const mDNSu8   *NR_AnswerTo;            // Set if this record was selected by virtue of being a direct answer to a question
-       AuthRecord     *NR_AdditionalTo;        // Set if this record was selected by virtue of being additional to another
-       mDNSs32         ThisAPInterval;         // In platform time units: Current interval for announce/probe
-       mDNSs32         AnnounceUntil;          // In platform time units: Creation time + TTL
-       mDNSs32         LastAPTime;                     // In platform time units: Last time we sent announcement/probe
-       mDNSs32         LastMCTime;                     // Last time we multicast this record (used to guard against packet-storm attacks)
-       mDNSInterfaceID LastMCInterface;        // Interface this record was multicast on at the time LastMCTime was recorded
-       RData          *NewRData;                       // Set if we are updating this record with new rdata
-       mDNSu16         newrdlength;            // ... and the length of the new RData
-       mDNSRecordUpdateCallback *UpdateCallback;
-       mDNSu32         UpdateCredits;          // Token-bucket rate limiting of excessive updates
-       mDNSs32         NextUpdateCredit;       // Time next token is added to bucket
-       mDNSs32         UpdateBlocked;          // Set if update delaying is in effect
-
-       RData           rdatastorage;           // Normally the storage is right here, except for oversized records
-       // rdatastorage MUST be the last thing in the structure -- when using oversized AuthRecords, extra bytes
-       // are appended after the end of the AuthRecord, logically augmenting the size of the rdatastorage
-       // DO NOT ADD ANY MORE FIELDS HERE
-       };
-
-struct CacheRecord_struct
-       {
-       CacheRecord    *next;                           // Next in list; first element of structure for efficiency reasons
-       ResourceRecord  resrec;
-
-       // Transient state for Cache Records
-       CacheRecord    *NextInKAList;           // Link to the next element in the chain of known answers to send
-       mDNSs32         TimeRcvd;                       // In platform time units
-       mDNSs32         NextRequiredQuery;      // In platform time units
-       mDNSs32         LastUsed;                       // In platform time units
-       mDNSu32         UseCount;                       // Number of times this RR has been used to answer a question
-       DNSQuestion    *CRActiveQuestion;       // Points to an active question referencing this answer
-       mDNSu32         UnansweredQueries;      // Number of times we've issued a query for this record without getting an answer
-       mDNSs32         LastUnansweredTime;     // In platform time units; last time we incremented UnansweredQueries
-       mDNSu32         MPUnansweredQ;          // Multi-packet query handling: Number of times we've seen a query for this record
-       mDNSs32         MPLastUnansweredQT;     // Multi-packet query handling: Last time we incremented MPUnansweredQ
-       mDNSu32         MPUnansweredKA;         // Multi-packet query handling: Number of times we've seen this record in a KA list
-       mDNSBool        MPExpectingKA;          // Multi-packet query handling: Set when we increment MPUnansweredQ; allows one KA
-       CacheRecord    *NextInCFList;           // Set if this is in the list of records we just received with the cache flush bit set
-
-       struct { mDNSu16 MaxRDLength; mDNSu8 data[InlineCacheRDSize]; } rdatastorage;   // Storage for small records is right here
-       };
-
-typedef struct
-       {
-       CacheRecord r;
-       mDNSu8 _extradata[MaximumRDSize-InlineCacheRDSize];             // Glue on the necessary number of extra bytes
-       } LargeCacheRecord;
-
-typedef struct NetworkInterfaceInfo_struct NetworkInterfaceInfo;
-
-struct NetworkInterfaceInfo_struct
-       {
-       // Internal state fields. These are used internally by mDNSCore; the client layer needn't be concerned with them.
-       NetworkInterfaceInfo *next;
-
-       mDNSBool        InterfaceActive;        // InterfaceActive is set if interface is sending & receiving packets
-                                                                               // InterfaceActive is clear if interface is here to represent an address with A
-                                                                               // and/or AAAA records, but there is already an earlier representative for this
-                                                                               // physical interface which will be used for the actual sending & receiving
-                                                                               // packets (this status may change as interfaces are added and removed)
-       mDNSBool        IPv4Available;          // If InterfaceActive, set if v4 available on this InterfaceID
-       mDNSBool        IPv6Available;          // If InterfaceActive, set if v6 available on this InterfaceID
-
-       // Standard AuthRecords that every Responder host should have (one per active IP address)
-       AuthRecord RR_A;                                        // 'A' or 'AAAA' (address) record for our ".local" name
-       AuthRecord RR_PTR;                                      // PTR (reverse lookup) record
-       AuthRecord RR_HINFO;
-
-       // Client API fields: The client must set up these fields *before* calling mDNS_RegisterInterface()
-       mDNSInterfaceID InterfaceID;
-       mDNSAddr        ip;
-       mDNSBool        Advertise;                      // Set Advertise to false if you are only searching on this interface
-       mDNSBool        TxAndRx;                        // Set to false if not sending and receiving packets on this interface
-       };
-
-typedef struct ExtraResourceRecord_struct ExtraResourceRecord;
-struct ExtraResourceRecord_struct
-       {
-       ExtraResourceRecord *next;
-       AuthRecord r;
-       // Note: Add any additional fields *before* the AuthRecord in this structure, not at the end.
-       // In some cases clients can allocate larger chunks of memory and set r->rdata->MaxRDLength to indicate
-       // that this extra memory is available, which would result in any fields after the AuthRecord getting smashed
-       };
-
-// Note: Within an mDNSServiceCallback mDNS all API calls are legal except mDNS_Init(), mDNS_Close(), mDNS_Execute() 
-typedef struct ServiceRecordSet_struct ServiceRecordSet;
-typedef void mDNSServiceCallback(mDNS *const m, ServiceRecordSet *const sr, mStatus result);
-struct ServiceRecordSet_struct
-       {
-       // Internal state fields. These are used internally by mDNSCore; the client layer needn't be concerned with them.
-       // No fields need to be set up by the client prior to calling mDNS_RegisterService();
-       // all required data is passed as parameters to that function.
-       mDNSServiceCallback *ServiceCallback;
-       void                *ServiceContext;
-       ExtraResourceRecord *Extras;    // Optional list of extra AuthRecords attached to this service registration
-       mDNSu32              NumSubTypes;
-       AuthRecord          *SubTypes;
-       mDNSBool             Conflict;  // Set if this record set was forcibly deregistered because of a conflict
-       domainname           Host;              // Set if this service record does not use the standard target host name
-       AuthRecord           RR_ADV;    // e.g. _services._dns-sd._udp.local. PTR _printer._tcp.local.
-       AuthRecord           RR_PTR;    // e.g. _printer._tcp.local.        PTR Name._printer._tcp.local.
-       AuthRecord           RR_SRV;    // e.g. Name._printer._tcp.local.   SRV 0 0 port target
-       AuthRecord           RR_TXT;    // e.g. Name._printer._tcp.local.   TXT PrintQueueName
-       // Don't add any fields after AuthRecord RR_TXT.
-       // This is where the implicit extra space goes if we allocate a ServiceRecordSet containing an oversized RR_TXT record
-       };
-
-// ***************************************************************************
-#if 0
-#pragma mark - Question structures
-#endif
-
-// We record the last eight instances of each duplicate query
-// This gives us v4/v6 on each of Ethernet/AirPort and Firewire, and two free slots "for future expansion"
-// If the host has more active interfaces that this it is not fatal -- duplicate question suppression will degrade gracefully.
-// Since we will still remember the last eight, the busiest interfaces will still get the effective duplicate question suppression.
-#define DupSuppressInfoSize 8
-
-typedef struct
-       {
-       mDNSs32               Time;
-       mDNSInterfaceID       InterfaceID;
-       mDNSs32               Type;                             // v4 or v6?
-       } DupSuppressInfo;
-
-// Note: Within an mDNSQuestionCallback mDNS all API calls are legal except mDNS_Init(), mDNS_Close(), mDNS_Execute() 
-typedef void mDNSQuestionCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord);
-struct DNSQuestion_struct
-       {
-       // Internal state fields. These are used internally by mDNSCore; the client layer needn't be concerned with them.
-       DNSQuestion          *next;
-       mDNSu32               qnamehash;
-       mDNSs32               LastQTime;                // Last scheduled transmission of this Q on *all* applicable interfaces
-       mDNSs32               ThisQInterval;    // LastQTime + ThisQInterval is the next scheduled transmission of this Q
-                                                                                       // ThisQInterval > 0 for an active question;
-                                                                                       // ThisQInterval = 0 for a suspended question that's still in the list
-                                                                                       // ThisQInterval = -1 for a cancelled question that's been removed from the list
-       mDNSu32               RecentAnswers;    // Number of answers since the last time we sent this query
-       mDNSu32               CurrentAnswers;   // Number of records currently in the cache that answer this question
-       mDNSu32               LargeAnswers;             // Number of answers with rdata > 1024 bytes
-       mDNSu32               UniqueAnswers;    // Number of answers received with kDNSClass_UniqueRRSet bit set
-       DNSQuestion          *DuplicateOf;
-       DNSQuestion          *NextInDQList;
-       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
-       mDNSs32               LastQTxTime;              // Last time this Q was sent on one (but not necessarily all) interfaces
-
-       // Client API fields: The client must set up these fields *before* calling mDNS_StartQuery()
-       mDNSInterfaceID       InterfaceID;              // Non-zero if you want to issue link-local queries only on a single specific IP interface
-       domainname            qname;
-       mDNSu16               qtype;
-       mDNSu16               qclass;
-       mDNSQuestionCallback *QuestionCallback;
-       void                 *QuestionContext;
-       };
-
-typedef struct
-       {
-       // Client API fields: The client must set up name and InterfaceID *before* calling mDNS_StartResolveService()
-       // When the callback is invoked, ip, port, TXTlen and TXTinfo will have been filled in with the results learned from the network.
-       domainname      name;
-       mDNSInterfaceID InterfaceID;            // ID of the interface the response was received on
-       mDNSAddr        ip;                                     // Remote (destination) IP address where this service can be accessed
-       mDNSIPPort      port;                           // Port where this service can be accessed
-       mDNSu16         TXTlen;
-       mDNSu8          TXTinfo[2048];          // Additional demultiplexing information (e.g. LPR queue name)
-       } ServiceInfo;
-
-// Note: Within an mDNSServiceInfoQueryCallback mDNS all API calls are legal except mDNS_Init(), mDNS_Close(), mDNS_Execute() 
-typedef struct ServiceInfoQuery_struct ServiceInfoQuery;
-typedef void mDNSServiceInfoQueryCallback(mDNS *const m, ServiceInfoQuery *query);
-struct ServiceInfoQuery_struct
-       {
-       // Internal state fields. These are used internally by mDNSCore; the client layer needn't be concerned with them.
-       // No fields need to be set up by the client prior to calling mDNS_StartResolveService();
-       // all required data is passed as parameters to that function.
-       // The ServiceInfoQuery structure memory is working storage for mDNSCore to discover the requested information
-       // and place it in the ServiceInfo structure. After the client has called mDNS_StopResolveService(), it may
-       // dispose of the ServiceInfoQuery structure while retaining the results in the ServiceInfo structure.
-       DNSQuestion                   qSRV;
-       DNSQuestion                   qTXT;
-       DNSQuestion                   qAv4;
-       DNSQuestion                   qAv6;
-       mDNSu8                        GotSRV;
-       mDNSu8                        GotTXT;
-       mDNSu8                        GotADD;
-       mDNSu32                       Answers;
-       ServiceInfo                  *info;
-       mDNSServiceInfoQueryCallback *ServiceInfoQueryCallback;
-       void                         *ServiceInfoQueryContext;
-       };
-
-// ***************************************************************************
-#if 0
-#pragma mark - Main mDNS object, used to hold all the mDNS state
-#endif
-
-typedef void mDNSCallback(mDNS *const m, mStatus result);
-
-#define CACHE_HASH_SLOTS 499
-
-enum
-       {
-       mDNS_KnownBug_PhantomInterfaces = 1
-       };
-
-struct mDNS_struct
-       {
-       // Internal state fields. These hold the main internal state of mDNSCore;
-       // the client layer needn't be concerned with them.
-       // No fields need to be set up by the client prior to calling mDNS_Init();
-       // all required data is passed as parameters to that function.
-
-       mDNS_PlatformSupport *p;                        // Pointer to platform-specific data of indeterminite size
-       mDNSu32  KnownBugs;
-       mDNSBool AdvertiseLocalAddresses;
-       mStatus mDNSPlatformStatus;
-       mDNSCallback *MainCallback;
-       void         *MainContext;
-
-       // For debugging: To catch and report locking failures
-       mDNSu32 mDNS_busy;                                      // Incremented between mDNS_Lock/mDNS_Unlock section
-       mDNSu32 mDNS_reentrancy;                        // Incremented when calling a client callback
-       mDNSu8  mDNS_shutdown;                          // Set when we're shutting down, allows us to skip some unnecessary steps
-       mDNSu8  lock_rrcache;                           // For debugging: Set at times when these lists may not be modified
-       mDNSu8  lock_Questions;
-       mDNSu8  lock_Records;
-       char MsgBuffer[80];                                     // Temp storage used while building error log messages
-
-       // Task Scheduling variables
-       mDNSs32  timenow;                                       // The time that this particular activation of the mDNS code started
-       mDNSs32  timenow_last;                          // The time the last time we ran
-       mDNSs32  timenow_adjust;                        // Correction applied if we ever discover time went backwards
-       mDNSs32  NextScheduledEvent;            // Derived from values below
-       mDNSs32  SuppressSending;                       // Don't send *any* packets during this time
-       mDNSs32  NextCacheCheck;                        // Next time to refresh cache record before it expires
-       mDNSs32  NextScheduledQuery;            // Next time to send query in its exponential backoff sequence
-       mDNSs32  NextScheduledProbe;            // Next time to probe for new authoritative record
-       mDNSs32  NextScheduledResponse;         // Next time to send authoritative record(s) in responses
-       mDNSs32  ExpectUnicastResponse;         // Set when we send a query with the kDNSQClass_UnicastResponse bit set
-       mDNSs32  RandomQueryDelay;                      // For de-synchronization of query packets on the wire
-       mDNSBool SendDeregistrations;           // Set if we need to send deregistrations (immediately)
-       mDNSBool SendImmediateAnswers;          // Set if we need to send answers (immediately -- or as soon as SuppressSending clears)
-       mDNSBool SleepState;                            // Set if we're sleeping (send no more packets)
-
-       // These fields only required for mDNS Searcher...
-       DNSQuestion *Questions;                         // List of all registered questions, active and inactive
-       DNSQuestion *NewQuestions;                      // Fresh questions not yet answered from cache
-       DNSQuestion *CurrentQuestion;           // Next question about to be examined in AnswerLocalQuestions()
-       DNSQuestion *LocalOnlyQuestions;        // Questions with InterfaceID set to ~0 ("local only")
-       DNSQuestion *NewLocalOnlyQuestions;     // Fresh local-only questions not yet answered
-       mDNSu32 rrcache_size;                           // Total number of available cache entries
-       mDNSu32 rrcache_totalused;                      // Number of cache entries currently occupied
-       mDNSu32 rrcache_active;                         // Number of cache entries currently occupied by records that answer active questions
-       mDNSu32 rrcache_report;
-       CacheRecord *rrcache_free;
-       CacheRecord *rrcache_hash[CACHE_HASH_SLOTS];
-       CacheRecord **rrcache_tail[CACHE_HASH_SLOTS];
-       mDNSu32 rrcache_used[CACHE_HASH_SLOTS];
-
-       // Fields below only required for mDNS Responder...
-       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  hostname;                           // Host Name, e.g. "Foo.local."
-       UTF8str255 HIHardware;
-       UTF8str255 HISoftware;
-       AuthRecord *ResourceRecords;
-       AuthRecord *DuplicateRecords;           // Records currently 'on hold' because they are duplicates of existing records
-       AuthRecord *LocalOnlyRecords;           // Local records registered with InterfaceID set to ~0 ("local only")
-       AuthRecord *NewLocalOnlyRecords;        // Fresh local-only records not yet delivered to local-only questions
-       mDNSBool    DiscardLocalOnlyRecords;// Set when we have "remove" events we need to deliver to local-only questions
-       AuthRecord *CurrentRecord;                      // Next AuthRecord about to be examined
-       NetworkInterfaceInfo *HostInterfaces;
-       mDNSs32 ProbeFailTime;
-       mDNSs32 NumFailedProbes;
-       mDNSs32 SuppressProbes;
-       };
-
-// ***************************************************************************
-#if 0
-#pragma mark - Useful Static Constants
-#endif
-
-extern const mDNSIPPort      zeroIPPort;
-extern const mDNSv4Addr      zeroIPAddr;
-extern const mDNSv6Addr      zerov6Addr;
-extern const mDNSv4Addr      onesIPv4Addr;
-extern const mDNSv6Addr      onesIPv6Addr;
-extern const mDNSInterfaceID mDNSInterface_Any;
-
-extern const mDNSIPPort      UnicastDNSPort;
-extern const mDNSIPPort      MulticastDNSPort;
-extern const mDNSv4Addr      AllDNSAdminGroup;
-extern const mDNSv4Addr      AllDNSLinkGroup;
-extern const mDNSv6Addr      AllDNSLinkGroupv6;
-extern const mDNSAddr        AllDNSLinkGroup_v4;
-extern const mDNSAddr        AllDNSLinkGroup_v6;
-
-// ***************************************************************************
-#if 0
-#pragma mark - Main Client Functions
-#endif
-
-// Every client should call mDNS_Init, passing in storage for the mDNS object, mDNS_PlatformSupport object, and rrcache.
-// The rrcachesize parameter is the size of (i.e. number of entries in) the rrcache array passed in.
-// Most clients use mDNS_Init_AdvertiseLocalAddresses. This causes mDNSCore to automatically
-// create the correct address records for all the hosts interfaces. If you plan to advertise
-// services being offered by the local machine, this is almost always what you want.
-// There are two cases where you might use mDNS_Init_DontAdvertiseLocalAddresses:
-// 1. A client-only device, that browses for services but doesn't advertise any of its own.
-// 2. A proxy-registration service, that advertises services being offered by other machines, and takes
-//    the appropriate steps to manually create the correct address records for those other machines.
-// In principle, a proxy-like registration service could manually create address records for its own machine too,
-// but this would be pointless extra effort when using mDNS_Init_AdvertiseLocalAddresses does that for you.
-//
-// When mDNS has finished setting up the client's callback is called
-// A client can also spin and poll the mDNSPlatformStatus field to see when it changes from mStatus_Waiting to mStatus_NoError
-//
-// Call mDNS_Close to tidy up before exiting
-//
-// Call mDNS_Register with a completed AuthRecord object to register a resource record
-// If the resource record type is kDNSRecordTypeUnique (or kDNSknownunique) then if a conflicting resource record is discovered,
-// the resource record's mDNSRecordCallback will be called with error code mStatus_NameConflict. The callback should deregister
-// the record, and may then try registering the record again after picking a new name (e.g. by automatically appending a number).
-//
-// Call mDNS_StartQuery to initiate a query. mDNS will proceed to issue Multicast DNS query packets, and any time a response
-// is received containing a record which matches the question, the DNSQuestion's mDNSAnswerCallback function will be called
-// Call mDNS_StopQuery when no more answers are required
-//
-// Care should be taken on multi-threaded or interrupt-driven environments.
-// The main mDNS routines call mDNSPlatformLock() on entry and mDNSPlatformUnlock() on exit;
-// each platform layer needs to implement these appropriately for its respective platform.
-// For example, if the support code on a particular platform implements timer callbacks at interrupt time, then
-// mDNSPlatformLock/Unlock need to disable interrupts or do similar concurrency control to ensure that the mDNS
-// code is not entered by an interrupt-time timer callback while in the middle of processing a client call.
-
-extern mStatus mDNS_Init      (mDNS *const m, mDNS_PlatformSupport *const p,
-                                                               CacheRecord *rrcachestorage, mDNSu32 rrcachesize,
-                                                               mDNSBool AdvertiseLocalAddresses,
-                                                               mDNSCallback *Callback, void *Context);
-// See notes above on use of NoCache/ZeroCacheSize
-#define mDNS_Init_NoCache                     mDNSNULL
-#define mDNS_Init_ZeroCacheSize               0
-// See notes above on use of Advertise/DontAdvertiseLocalAddresses
-#define mDNS_Init_AdvertiseLocalAddresses     mDNStrue
-#define mDNS_Init_DontAdvertiseLocalAddresses mDNSfalse
-#define mDNS_Init_NoInitCallback              mDNSNULL
-#define mDNS_Init_NoInitCallbackContext       mDNSNULL
-
-extern void    mDNS_GrowCache (mDNS *const m, CacheRecord *storage, mDNSu32 numrecords);
-extern void    mDNS_Close     (mDNS *const m);
-extern mDNSs32 mDNS_Execute   (mDNS *const m);
-
-extern mStatus mDNS_Register  (mDNS *const m, AuthRecord *const rr);
-extern mStatus mDNS_Update    (mDNS *const m, AuthRecord *const rr, mDNSu32 newttl,
-                                                               const mDNSu16 newrdlength, 
-                                                               RData *const newrdata, mDNSRecordUpdateCallback *Callback);
-extern mStatus mDNS_Deregister(mDNS *const m, AuthRecord *const rr);
-
-extern mStatus mDNS_StartQuery(mDNS *const m, DNSQuestion *const question);
-extern mStatus mDNS_StopQuery (mDNS *const m, DNSQuestion *const question);
-extern mStatus mDNS_Reconfirm (mDNS *const m, CacheRecord *const cacherr);
-extern mStatus mDNS_ReconfirmByValue(mDNS *const m, ResourceRecord *const rr);
-
-// ***************************************************************************
-#if 0
-#pragma mark - Platform support functions that are accessible to the client layer too
-#endif
-
-extern mDNSs32  mDNSPlatformOneSecond;
-extern mDNSs32  mDNSPlatformTimeNow(void);
-
-// ***************************************************************************
-#if 0
-#pragma mark - General utility and helper functions
-#endif
-
-// mDNS_RegisterService is a single call to register the set of resource records associated with a given named service.
-//
-// mDNS_StartResolveService is single call which is equivalent to multiple calls to mDNS_StartQuery,
-// to find the IP address, port number, and demultiplexing information for a given named service.
-// As with mDNS_StartQuery, it executes asynchronously, and calls the ServiceInfoQueryCallback when the answer is
-// found. After the service is resolved, the client should call mDNS_StopResolveService to complete the transaction.
-// The client can also call mDNS_StopResolveService at any time to abort the transaction.
-//
-// mDNS_GetBrowseDomains is a special case of the mDNS_StartQuery call, where the resulting answers
-// are a list of PTR records indicating (in the rdata) domains that are recommended for browsing.
-// After getting the list of domains to browse, call mDNS_StopQuery to end the search.
-// mDNS_GetDefaultBrowseDomain returns the name of the domain that should be highlighted by default.
-//
-// mDNS_GetRegistrationDomains and mDNS_GetDefaultRegistrationDomain are the equivalent calls to get the list
-// of one or more domains that should be offered to the user as choices for where they may register their service,
-// and the default domain in which to register in the case where the user has made no selection.
-
-extern void    mDNS_SetupResourceRecord(AuthRecord *rr, RData *RDataStorage, mDNSInterfaceID InterfaceID,
-               mDNSu16 rrtype, mDNSu32 ttl, mDNSu8 RecordType, mDNSRecordCallback Callback, void *Context);
-
-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, const mDNSu8 txtinfo[], mDNSu16 txtlen,
-               AuthRecord *SubTypes, mDNSu32 NumSubTypes,
-               const mDNSInterfaceID InterfaceID, mDNSServiceCallback Callback, void *Context);
-extern mStatus mDNS_AddRecordToService(mDNS *const m, ServiceRecordSet *sr, ExtraResourceRecord *extra, RData *rdata, mDNSu32 ttl);
-extern mStatus mDNS_RemoveRecordFromService(mDNS *const m, ServiceRecordSet *sr, ExtraResourceRecord *extra);
-extern mStatus mDNS_RenameAndReregisterService(mDNS *const m, ServiceRecordSet *const sr, const domainlabel *newname);
-extern mStatus mDNS_DeregisterService(mDNS *const m, ServiceRecordSet *sr);
-
-extern mStatus mDNS_RegisterNoSuchService(mDNS *const m, AuthRecord *const rr,
-               const domainlabel *const name, const domainname *const type, const domainname *const domain,
-               const domainname *const host,
-               const mDNSInterfaceID InterfaceID, mDNSRecordCallback Callback, void *Context);
-#define        mDNS_DeregisterNoSuchService mDNS_Deregister
-
-extern mStatus mDNS_StartBrowse(mDNS *const m, DNSQuestion *const question,
-               const domainname *const srv, const domainname *const domain,
-               const mDNSInterfaceID InterfaceID, mDNSQuestionCallback *Callback, void *Context);
-#define        mDNS_StopBrowse mDNS_StopQuery
-
-extern mStatus mDNS_StartResolveService(mDNS *const m, ServiceInfoQuery *query, ServiceInfo *info, mDNSServiceInfoQueryCallback *Callback, void *Context);
-extern void    mDNS_StopResolveService (mDNS *const m, ServiceInfoQuery *query);
-
-typedef enum
-       {
-       mDNS_DomainTypeBrowse              = 0,
-       mDNS_DomainTypeBrowseDefault       = 1,
-       mDNS_DomainTypeRegistration        = 2,
-       mDNS_DomainTypeRegistrationDefault = 3
-       } mDNS_DomainType;
-
-extern mStatus mDNS_GetDomains(mDNS *const m, DNSQuestion *const question, mDNS_DomainType DomainType, const mDNSInterfaceID InterfaceID, mDNSQuestionCallback *Callback, void *Context);
-// In the Panther mDNSResponder we don't do unicast queries yet, so there's no point trying to do domain enumeration
-// mDNS_GetDomains() and mDNS_StopGetDomains() are set to be no-ops so that clients don't try to do browse/register operations that will fail
-//#define        mDNS_StopGetDomains mDNS_StopQuery
-#define        mDNS_StopGetDomains(m,q) ((void)(m),(void)(q))
-extern mStatus mDNS_AdvertiseDomains(mDNS *const m, AuthRecord *rr, mDNS_DomainType DomainType, const mDNSInterfaceID InterfaceID, char *domname);
-#define        mDNS_StopAdvertiseDomains mDNS_Deregister
-
-// ***************************************************************************
-#if 0
-#pragma mark - DNS name utility functions
-#endif
-
-// In order to expose the full capabilities of the DNS protocol (which allows any arbitrary eight-bit values
-// in domain name labels, including unlikely characters like ascii nulls and even dots) all the mDNS APIs
-// work with DNS's native length-prefixed strings. For convenience in C, the following utility functions
-// are provided for converting between C's null-terminated strings and DNS's length-prefixed strings.
-
-// Assignment
-// A simple C structure assignment of a domainname can cause a protection fault by accessing unmapped memory,
-// because that object is defined to be 256 bytes long, but not all domainname objects are truly the full size.
-// This macro uses mDNSPlatformMemCopy() to make sure it only touches the actual bytes that are valid.
-#define AssignDomainName(DST, SRC) mDNSPlatformMemCopy((SRC).c, (DST).c, DomainNameLength(&(SRC)))
-
-// Comparison functions
-extern mDNSBool SameDomainLabel(const mDNSu8 *a, const mDNSu8 *b);
-extern mDNSBool SameDomainName(const domainname *const d1, const domainname *const d2);
-
-// Get total length of domain name, in native DNS format, including terminal root label
-//   (e.g. length of "com." is 5 (length byte, three data bytes, final zero)
-extern mDNSu16  DomainNameLength(const domainname *const name);
-
-// Append functions to append one or more labels to an existing native format domain name:
-//   AppendLiteralLabelString adds a single label from a literal C string, with no escape character interpretation.
-//   AppendDNSNameString      adds zero or more labels from a C string using conventional DNS dots-and-escaping interpretation
-//   AppendDomainLabel        adds a single label from a native format domainlabel
-//   AppendDomainName         adds zero or more labels from a native format domainname
-extern mDNSu8  *AppendLiteralLabelString(domainname *const name, const char *cstr);
-extern mDNSu8  *AppendDNSNameString     (domainname *const name, const char *cstr);
-extern mDNSu8  *AppendDomainLabel       (domainname *const name, const domainlabel *const label);
-extern mDNSu8  *AppendDomainName        (domainname *const name, const domainname *const append);
-
-// Convert from null-terminated string to native DNS format:
-//   The DomainLabel form makes a single label from a literal C string, with no escape character interpretation.
-//   The DomainName form makes native format domain name from a C string using conventional DNS interpretation:
-//     dots separate labels, and within each label, '\.' represents a literal dot, '\\' represents a literal
-//     backslash and backslash with three decimal digits (e.g. \000) represents an arbitrary byte value.
-extern mDNSBool MakeDomainLabelFromLiteralString(domainlabel *const label, const char *cstr);
-extern mDNSu8  *MakeDomainNameFromDNSNameString (domainname  *const name,  const char *cstr);
-
-// Convert native format domainlabel or domainname back to C string format
-// IMPORTANT:
-// When using ConvertDomainLabelToCString, the target buffer must be MAX_ESCAPED_DOMAIN_LABEL (254) bytes long
-// to guarantee there will be no buffer overrun. It is only safe to use a buffer shorter than this in rare cases
-// where the label is known to be constrained somehow (for example, if the label is known to be either "_tcp" or "_udp").
-// Similarly, when using ConvertDomainNameToCString, the target buffer must be MAX_ESCAPED_DOMAIN_NAME (1005) bytes long.
-// See definitions of MAX_ESCAPED_DOMAIN_LABEL and MAX_ESCAPED_DOMAIN_NAME for more detailed explanation.
-extern char    *ConvertDomainLabelToCString_withescape(const domainlabel *const name, char *cstr, char esc);
-#define         ConvertDomainLabelToCString_unescaped(D,C) ConvertDomainLabelToCString_withescape((D), (C), 0)
-#define         ConvertDomainLabelToCString(D,C)           ConvertDomainLabelToCString_withescape((D), (C), '\\')
-extern char    *ConvertDomainNameToCString_withescape(const domainname *const name, char *cstr, char esc);
-#define         ConvertDomainNameToCString_unescaped(D,C) ConvertDomainNameToCString_withescape((D), (C), 0)
-#define         ConvertDomainNameToCString(D,C)           ConvertDomainNameToCString_withescape((D), (C), '\\')
-
-extern void     ConvertUTF8PstringToRFC1034HostLabel(const mDNSu8 UTF8Name[], domainlabel *const hostlabel);
-
-extern mDNSu8  *ConstructServiceName(domainname *const fqdn, const domainlabel *name, const domainname *type, const domainname *const domain);
-extern mDNSBool DeconstructServiceName(const domainname *const fqdn, domainlabel *const name, domainname *const type, domainname *const domain);
-
-// Note: Some old functions have been replaced by more sensibly-named versions.
-// You can uncomment the hash-defines below if you don't want to have to change your source code right away.
-// When updating your code, note that (unlike the old versions) *all* the new routines take the target object
-// as their first parameter.
-//#define ConvertCStringToDomainName(SRC,DST)  MakeDomainNameFromDNSNameString((DST),(SRC))
-//#define ConvertCStringToDomainLabel(SRC,DST) MakeDomainLabelFromLiteralString((DST),(SRC))
-//#define AppendStringLabelToName(DST,SRC)     AppendLiteralLabelString((DST),(SRC))
-//#define AppendStringNameToName(DST,SRC)      AppendDNSNameString((DST),(SRC))
-//#define AppendDomainLabelToName(DST,SRC)     AppendDomainLabel((DST),(SRC))
-//#define AppendDomainNameToName(DST,SRC)      AppendDomainName((DST),(SRC))
-
-// ***************************************************************************
-#if 0
-#pragma mark - Other utility functions
-#endif
-
-extern mDNSu32 mDNS_vsnprintf(char *sbuffer, mDNSu32 buflen, const char *fmt, va_list arg);
-extern mDNSu32 mDNS_snprintf(char *sbuffer, mDNSu32 buflen, const char *fmt, ...) IS_A_PRINTF_STYLE_FUNCTION(3,4);
-extern char *DNSTypeName(mDNSu16 rrtype);
-extern char *GetRRDisplayString_rdb(mDNS *const m, const ResourceRecord *rr, RDataBody *rd);
-#define GetRRDisplayString(m, rr) GetRRDisplayString_rdb((m), &(rr)->resrec, &(rr)->resrec.rdata->u)
-extern mDNSBool mDNSSameAddress(const mDNSAddr *ip1, const mDNSAddr *ip2);
-extern void IncrementLabelSuffix(domainlabel *name, mDNSBool RichText);
-
-// ***************************************************************************
-#if 0
-#pragma mark - PlatformSupport interface
-#endif
-
-// This section defines the interface to the Platform Support layer.
-// Normal client code should not use any of types defined here, or directly call any of the functions defined here.
-// The definitions are placed here because sometimes clients do use these calls indirectly, via other supported client operations.
-// For example, AssignDomainName is a macro defined using mDNSPlatformMemCopy()
-
-typedef packedstruct
-       {
-       mDNSOpaque16 id;
-       mDNSOpaque16 flags;
-       mDNSu16 numQuestions;
-       mDNSu16 numAnswers;
-       mDNSu16 numAuthorities;
-       mDNSu16 numAdditionals;
-       } DNSMessageHeader;
-
-// We can send and receive packets up to 9000 bytes (Ethernet Jumbo Frame size, if that ever becomes widely used)
-// However, in the normal case we try to limit packets to 1500 bytes so that we don't get IP fragmentation on standard Ethernet
-// 40 (IPv6 header) + 8 (UDP header) + 12 (DNS message header) + 1440 (DNS message body) = 1500 total
-#define AbsoluteMaxDNSMessageData 8940
-#define NormalMaxDNSMessageData 1440
-typedef packedstruct
-       {
-       DNSMessageHeader h;                                             // Note: Size 12 bytes
-       mDNSu8 data[AbsoluteMaxDNSMessageData]; // 40 (IPv6) + 8 (UDP) + 12 (DNS header) + 8940 (data) = 9000
-       } DNSMessage;
-
-// Every platform support module must provide the following functions.
-// mDNSPlatformInit() typically opens a communication endpoint, and starts listening for mDNS packets.
-// When Setup is complete, the platform support layer calls mDNSCoreInitComplete().
-// mDNSPlatformSendUDP() sends one UDP packet
-// When a packet is received, the PlatformSupport code calls mDNSCoreReceive()
-// mDNSPlatformClose() tidies up on exit
-// Note: mDNSPlatformMemAllocate/mDNSPlatformMemFree are only required for handling oversized resource records.
-// If your target platform has a well-defined specialized application, and you know that all the records it uses
-// are InlineCacheRDSize or less, then you can just make a simple mDNSPlatformMemAllocate() stub that always returns
-// NULL. InlineCacheRDSize is a compile-time constant, which is set by default to 64. If you need to handle records
-// a little larger than this and you don't want to have to implement run-time allocation and freeing, then you
-// can raise the value of this constant to a suitable value (at the expense of increased memory usage).
-extern mStatus  mDNSPlatformInit        (mDNS *const m);
-extern void     mDNSPlatformClose       (mDNS *const m);
-extern mStatus  mDNSPlatformSendUDP(const mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end,
-       mDNSInterfaceID InterfaceID, mDNSIPPort srcport, const mDNSAddr *dst, mDNSIPPort dstport);
-
-extern void     mDNSPlatformLock        (const mDNS *const m);
-extern void     mDNSPlatformUnlock      (const mDNS *const m);
-
-extern void     mDNSPlatformStrCopy     (const void *src,       void *dst);
-extern mDNSu32  mDNSPlatformStrLen      (const void *src);
-extern void     mDNSPlatformMemCopy     (const void *src,       void *dst, mDNSu32 len);
-extern mDNSBool mDNSPlatformMemSame     (const void *src, const void *dst, mDNSu32 len);
-extern void     mDNSPlatformMemZero     (                       void *dst, mDNSu32 len);
-extern void *   mDNSPlatformMemAllocate (mDNSu32 len);
-extern void     mDNSPlatformMemFree     (void *mem);
-extern mStatus  mDNSPlatformTimeInit    (mDNSs32 *timenow);
-
-// The core mDNS code provides these functions, for the platform support code to call at appropriate times
-//
-// mDNS_GenerateFQDN() is called once on startup (typically from mDNSPlatformInit())
-// and then again on each subsequent change of the dot-local host name.
-//
-// mDNS_RegisterInterface() is used by the platform support layer to inform mDNSCore of what
-// physical and/or logical interfaces are available for sending and receiving packets.
-// Typically it is called on startup for each available interface, but register/deregister may be
-// called again later, on multiple occasions, to inform the core of interface configuration changes.
-// If set->Advertise is set non-zero, then mDNS_RegisterInterface() also registers the standard
-// resource records that should be associated with every publicised IP address/interface:
-// -- Name-to-address records (A/AAAA)
-// -- Address-to-name records (PTR)
-// -- Host information (HINFO)
-//
-// mDNSCoreInitComplete() is called when the platform support layer is finished.
-// Typically this is at the end of mDNSPlatformInit(), but may be later
-// (on platforms like OT that allow asynchronous initialization of the networking stack).
-//
-// mDNSCoreReceive() is called when a UDP packet is received
-//
-// mDNSCoreMachineSleep() is called when the machine sleeps or wakes
-// (This refers to heavyweight laptop-style sleep/wake that disables network access,
-// not lightweight second-by-second CPU power management modes.)
-
-extern void     mDNS_GenerateFQDN(mDNS *const m);
-extern mStatus  mDNS_RegisterInterface  (mDNS *const m, NetworkInterfaceInfo *set);
-extern void     mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *set);
-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 *const dstaddr, const mDNSIPPort dstport, const mDNSInterfaceID InterfaceID, mDNSu8 ttl);
-extern void     mDNSCoreMachineSleep(mDNS *const m, mDNSBool wake);
-
-// ***************************************************************************
-#if 0
-#pragma mark - Compile-Time assertion checks
-#endif
-
-// Some C compiler cleverness. We can make the compiler check certain things for
-// us, and report compile-time errors if anything is wrong. The usual way to do
-// this would be to use a run-time "if" statement, but then you don't find out
-// what's wrong until you run the software. This way, if the assertion condition
-// is false, the array size is negative, and the complier complains immediately.
-
-struct mDNS_CompileTimeAssertionChecks
-       {
-       // Check that the compiler generated our on-the-wire packet format structure definitions
-       // properly packed, without adding padding bytes to align fields on 32-bit or 64-bit boundaries.
-       char assert0[(sizeof(rdataSRV)         == 262                          ) ? 1 : -1];
-       char assert1[(sizeof(DNSMessageHeader) ==  12                          ) ? 1 : -1];
-       char assert2[(sizeof(DNSMessage)       ==  12+AbsoluteMaxDNSMessageData) ? 1 : -1];
-       char assert3[(sizeof(mDNSs8)           ==   1                          ) ? 1 : -1];
-       char assert4[(sizeof(mDNSu8)           ==   1                          ) ? 1 : -1];
-       char assert5[(sizeof(mDNSs16)          ==   2                          ) ? 1 : -1];
-       char assert6[(sizeof(mDNSu16)          ==   2                          ) ? 1 : -1];
-       char assert7[(sizeof(mDNSs32)          ==   4                          ) ? 1 : -1];
-       char assert8[(sizeof(mDNSu32)          ==   4                          ) ? 1 : -1];
-       char assert9[(sizeof(mDNSOpaque16)     ==   2                          ) ? 1 : -1];
-       char assertA[(sizeof(mDNSOpaque32)     ==   4                          ) ? 1 : -1];
-       char assertB[(sizeof(mDNSOpaque128)    ==  16                          ) ? 1 : -1];
-       };
-
-// ***************************************************************************
-
-#ifdef __cplusplus
-       }
-#endif
-
-#endif
diff --git a/mDNSCore/mDNSPlatformFunctions.h b/mDNSCore/mDNSPlatformFunctions.h
deleted file mode 100755 (executable)
index 8f07d59..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- * 
- * @APPLE_LICENSE_HEADER_END@
-
-    Change History (most recent first):
-
-$Log: mDNSPlatformFunctions.h,v $
-Revision 1.22.2.1  2003/12/05 00:03:34  cheshire
-<rdar://problem/3487869> Use buffer size MAX_ESCAPED_DOMAIN_NAME instead of 256
-
-Revision 1.22  2003/08/18 22:53:37  cheshire
-<rdar://problem/3382647> mDNSResponder divide by zero in mDNSPlatformTimeNow()
-
-Revision 1.21  2003/08/15 20:16:57  cheshire
-Update comment for <rdar://problem/3366590> mDNSResponder takes too much RPRVT
-
-Revision 1.20  2003/08/12 19:56:24  cheshire
-Update to APSL 2.0
-
-Revision 1.19  2003/08/05 22:20:15  cheshire
-<rdar://problem/3330324> Need to check IP TTL on responses
-
-Revision 1.18  2003/07/22 23:57:20  cheshire
-Move platform-layer function prototypes from mDNSClientAPI.h to mDNSPlatformFunctions.h where they belong
-
-Revision 1.17  2003/07/19 03:15:15  cheshire
-Add generic MemAllocate/MemFree prototypes to mDNSPlatformFunctions.h,
-and add the obvious trivial implementations to each platform support layer
-
-Revision 1.16  2003/07/02 21:19:46  cheshire
-<rdar://problem/3313413> Update copyright notices, etc., in source code comments
-
-Revision 1.15  2003/05/23 22:39:45  cheshire
-<rdar://problem/3268151> Need to adjust maximum packet size for IPv6
-
-Revision 1.14  2003/04/28 21:54:57  cheshire
-Fix compiler warning
-
-Revision 1.13  2003/03/15 04:40:36  cheshire
-Change type called "mDNSOpaqueID" to the more descriptive name "mDNSInterfaceID"
-
-Revision 1.12  2003/02/21 01:54:08  cheshire
-Bug #: 3099194 mDNSResponder needs performance improvements
-Switched to using new "mDNS_Execute" model (see "Implementer Notes.txt")
-
-Revision 1.11  2002/12/23 22:13:29  jgraessl
-
-Reviewed by: Stuart Cheshire
-Initial IPv6 support for mDNSResponder.
-
-Revision 1.10  2002/09/21 20:44:49  zarzycki
-Added APSL info
-
-Revision 1.9  2002/09/19 04:20:43  cheshire
-Remove high-ascii characters that confuse some systems
-
-Revision 1.8  2002/09/16 23:12:14  cheshire
-Minor code tidying
-
-Revision 1.7  2002/09/16 18:41:42  cheshire
-Merge in license terms from Quinn's copy, in preparation for Darwin release
-
-*/
-
-// Note: All moved to mDNSClientAPI.h
diff --git a/mDNSCore/uDNS.c b/mDNSCore/uDNS.c
new file mode 100755 (executable)
index 0000000..90fd363
--- /dev/null
@@ -0,0 +1,3001 @@
+/*
+ * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+
+$Log: uDNS.c,v $
+Revision 1.54  2004/06/22 02:10:53  ksekar
+<rdar://problem/3705433>: Lighthouse failure causes packet flood to DNS
+
+Revision 1.53  2004/06/17 20:49:09  ksekar
+<rdar://problem/3690436>: Tiger8A148: repeated crash of mDNSResponder while location cycling
+
+Revision 1.52  2004/06/17 01:13:11  ksekar
+<rdar://problem/3696616>: polling interval too short
+
+Revision 1.51  2004/06/10 04:36:44  cheshire
+Fix compiler warning
+
+Revision 1.50  2004/06/10 00:55:13  ksekar
+<rdar://problem/3686213>: crash on network reconnect
+
+Revision 1.49  2004/06/10 00:10:50  ksekar
+<rdar://problem/3686174>: Infinite Loop in uDNS_Execute()
+
+Revision 1.48  2004/06/09 20:03:37  ksekar
+<rdar://problem/3686163>: Incorrect copying of resource record in deregistration
+
+Revision 1.47  2004/06/09 03:48:28  ksekar
+<rdar://problem/3685226>: nameserver address fails with prod. Lighthouse server
+
+Revision 1.46  2004/06/09 01:44:30  ksekar
+<rdar://problem/3681378> reworked Cache Record copy code
+
+Revision 1.45  2004/06/08 18:54:47  ksekar
+<rdar://problem/3681378>: mDNSResponder leaks after exploring in Printer Setup Utility
+
+Revision 1.44  2004/06/05 00:33:51  cheshire
+<rdar://problem/3681029>: Check for incorrect time comparisons
+
+Revision 1.43  2004/06/05 00:14:44  cheshire
+Fix signed/unsigned and other compiler warnings
+
+Revision 1.42  2004/06/04 22:36:16  ksekar
+Properly set u->nextevent in uDNS_Execute
+
+Revision 1.41  2004/06/04 08:58:29  ksekar
+<rdar://problem/3668624>: Keychain integration for secure dynamic update
+
+Revision 1.40  2004/06/03 03:09:58  ksekar
+<rdar://problem/3668626>: Garbage Collection for Dynamic Updates
+
+Revision 1.39  2004/06/01 23:46:50  ksekar
+<rdar://problem/3675149>: DynDNS: dynamically look up LLQ/Update ports
+
+Revision 1.38  2004/05/31 22:19:44  ksekar
+<rdar://problem/3258021>: Feature: DNS server->client notification on
+record changes (#7805) - revert to polling mode on setup errors
+
+Revision 1.37  2004/05/28 23:42:37  ksekar
+<rdar://problem/3258021>: Feature: DNS server->client notification on record changes (#7805)
+
+Revision 1.36  2004/05/18 23:51:25  cheshire
+Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
+
+Revision 1.35  2004/05/07 23:01:04  ksekar
+Cleaned up list traversal in deriveGoodbyes - removed unnecessary
+conditional assignment.
+
+Revision 1.34  2004/05/05 18:26:12  ksekar
+Periodically re-transmit questions if the send() fails.  Include
+internal questions in retransmission.
+
+Revision 1.33  2004/05/05 17:40:06  ksekar
+Removed prerequisite from deregistration update - it does not work for
+shared records, and is unnecessary until we have more sophisticated
+name conflict management.
+
+Revision 1.32  2004/05/05 17:32:18  ksekar
+Prevent registration of loopback interface caused by removal of
+Multicast flag in interface structure.
+
+Revision 1.31  2004/05/05 17:05:02  ksekar
+Use LargeCacheRecord structs when pulling records off packets
+
+Revision 1.30  2004/04/16 21:33:27  ksekar
+Fixed bug in processing GetZoneData responses that do not use BIND formatting.
+
+Revision 1.29  2004/04/15 20:03:13  ksekar
+Clarified log message when pulling bad resource records off packet.
+
+Revision 1.28  2004/04/15 00:51:28  bradley
+Minor tweaks for Windows and C++ builds. Added casts for signed/unsigned integers and 64-bit pointers.
+Prefix some functions with mDNS to avoid conflicts. Disable benign warnings on Microsoft compilers.
+
+Revision 1.27  2004/04/14 23:09:28  ksekar
+Support for TSIG signed dynamic updates.
+
+Revision 1.26  2004/04/14 19:36:05  ksekar
+Fixed memory corruption error in deriveGoodbyes.
+
+Revision 1.25  2004/04/14 04:07:11  ksekar
+Fixed crash in IsActiveUnicastQuery().  Removed redundant checks in routine.
+
+Revision 1.24  2004/04/08 09:41:40  bradley
+Added const to AuthRecord in deadvertiseIfCallback to match callback typedef.
+
+Revision 1.23  2004/03/24 00:29:45  ksekar
+Make it safe to call StopQuery in a unicast question callback
+
+Revision 1.22  2004/03/19 10:11:09  bradley
+Added AuthRecord * cast from umalloc for C++ builds.
+
+Revision 1.21  2004/03/15 02:03:45  bradley
+Added const to params where needed to match prototypes. Changed SetNewRData calls to use 0 instead
+of -1 for unused size to fix warning. Disable assignment within conditional warnings with Visual C++.
+
+Revision 1.20  2004/03/13 02:07:26  ksekar
+<rdar://problem/3192546>: DynDNS: Dynamic update of service records
+
+Revision 1.19  2004/03/13 01:57:33  ksekar
+<rdar://problem/3192546>: DynDNS: Dynamic update of service records
+
+Revision 1.18  2004/02/21 08:34:15  bradley
+Added casts from void * to specific type for C++ builds. Changed void * l-value cast
+r-value cast to fix problems with VC++ builds. Removed empty switch to fix VC++ error.
+
+Revision 1.17  2004/02/21 02:06:24  cheshire
+Can't use anonymous unions -- they're non-standard and don't work on all compilers
+
+Revision 1.16  2004/02/12 01:51:45  cheshire
+Don't try to send uDNS queries unless we have at least one uDNS server available
+
+Revision 1.15  2004/02/10 03:02:46  cheshire
+Fix compiler warning
+
+Revision 1.14  2004/02/06 23:04:19  ksekar
+Basic Dynamic Update support via mDNS_Register (dissabled via
+UNICAST_REGISTRATION #define)
+
+Revision 1.13  2004/02/03 22:15:01  ksekar
+Fixed nameToAddr error check: don't abort state machine on nxdomain error.
+
+Revision 1.12  2004/02/03 19:47:36  ksekar
+Added an asyncronous state machine mechanism to uDNS.c, including
+calls to find the parent zone for a domain name.  Changes include code
+in repository previously dissabled via "#if 0 //incomplete".  Codepath
+is currently unused, and will be called to create update records, etc.
+
+Revision 1.11  2004/01/30 02:12:30  ksekar
+Changed uDNS_ReceiveMsg() to correctly return void.
+
+Revision 1.10  2004/01/29 02:59:17  ksekar
+Unicast DNS: Changed from a resource record oriented question/response
+matching to packet based matching.  New callback architecture allows
+collections of records in a response to be processed differently
+depending on the nature of the request, and allows the same structure
+to be used for internal and client-driven queries with different processing needs.
+
+Revision 1.9  2004/01/28 20:20:45  ksekar
+Unified ActiveQueries and ActiveInternalQueries lists, using a flag to
+demux them.  Check-in includes work-in-progress code, #ifdef'd out.
+
+Revision 1.8  2004/01/28 02:30:07  ksekar
+Added default Search Domains to unicast browsing, controlled via
+Networking sharing prefs pane.  Stopped sending unicast messages on
+every interface.  Fixed unicast resolving via mach-port API.
+
+Revision 1.7  2004/01/27 20:15:22  cheshire
+<rdar://problem/3541288>: Time to prune obsolete code for listening on port 53
+
+Revision 1.6  2004/01/24 23:47:17  cheshire
+Use mDNSOpaque16fromIntVal() instead of shifting and masking
+
+Revision 1.5  2004/01/24 04:59:15  cheshire
+Fixes so that Posix/Linux, OS9, Windows, and VxWorks targets build again
+
+Revision 1.4  2004/01/24 04:19:26  cheshire
+Restore overwritten checkin 1.2
+
+Revision 1.3  2004/01/23 23:23:15  ksekar
+Added TCP support for truncated unicast messages.
+
+Revision 1.2  2004/01/22 03:48:41  cheshire
+Make sure uDNS client doesn't accidentally use query ID zero
+
+Revision 1.1  2003/12/13 03:05:27  ksekar
+<rdar://problem/3192548>: DynDNS: Unicast query of service records
+
+ */
+
+#include "uDNS.h"
+
+#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
+       // of parentheses, this signals to the compiler that you really intended an assignment and no warning is necessary.
+       // The Microsoft compiler doesn't understand this convention, so in the absense of any other way to signal
+       // to the compiler that the assignment is intentional, we have to just turn this warning off completely.
+       #pragma warning(disable:4706)
+#endif
+
+#ifndef NULL
+#define NULL mDNSNULL
+#endif // NULL
+
+
+#define ustrcpy(d,s)       mDNSPlatformStrCopy(s,d)       // use strcpy(2) param ordering
+#define ustrlen(s)         mDNSPlatformStrLen(s)
+#define umalloc(x)         mDNSPlatformMemAllocate(x)       // short hands for common routines
+#define ufree(x)           mDNSPlatformMemFree(x)
+#define ubzero(x,y)        mDNSPlatformMemZero(x,y)
+#define umemcpy(x, y, l)   mDNSPlatformMemCopy(y, x, l)  // uses memcpy(2) arg ordering
+
+
+// Asyncronous operation types
+
+typedef enum
+       {
+       zoneDataResult
+       // other async. operation names go here
+       } AsyncOpResultType;
+
+typedef struct
+       {
+    domainname zoneName; 
+    mDNSAddr primaryAddr;
+    mDNSu16 zoneClass;
+    mDNSIPPort llqPort;
+    mDNSIPPort updatePort;
+       } zoneData_t;
+
+// other async. result struct defs go here
+
+typedef struct
+       {
+    AsyncOpResultType type;
+    zoneData_t zoneData;
+    // other async result structs go here
+       } AsyncOpResult;
+
+typedef void AsyncOpCallback(mStatus err, mDNS *const m, void *info, const AsyncOpResult *result); 
+
+
+// Private Function Prototypes
+// Note:  In general, functions are ordered such that they do not require forward declarations.
+// However, prototypes are used where cyclic call graphs exist (e.g. foo calls bar, and bar calls
+// foo), or when they aid in the grouping or readability of code (e.g. state machine code that is easier
+// read top-to-bottom.)
+
+mDNSlocal void hndlTruncatedAnswer(DNSQuestion *question,  const mDNSAddr *src, mDNS *m);
+mDNSlocal mStatus startGetZoneData(domainname *name, mDNS *m, mDNSBool findUpdatePort, mDNSBool findLLQPort,
+                                                                  AsyncOpCallback callback, void *callbackInfo);
+mDNSlocal mDNSBool recvLLQResponse(mDNS *m, DNSMessage *msg, const mDNSu8 *end, const mDNSAddr *srcaddr, mDNSIPPort srcport, const mDNSInterfaceID InterfaceID);
+mDNSlocal void sendRecordRegistration(mDNS *const m, AuthRecord *rr);
+mDNSlocal void SendServiceRegistration(mDNS *m, ServiceRecordSet *srs);
+
+// ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark - General Utility Functions
+#endif
+
+mDNSlocal mDNSOpaque16 newMessageID(uDNS_GlobalInfo *u)
+       {
+       // if NextMessageID is 0 (ininitialized) or 0xffff (reserved for TCP packets) reset to 1
+       if (!u->NextMessageID || u->NextMessageID == (mDNSu16)~0) u->NextMessageID = 1;
+       return mDNSOpaque16fromIntVal(u->NextMessageID++);
+       }
+
+// unlink an AuthRecord from a linked list
+mDNSlocal mStatus unlinkAR(AuthRecord **list, AuthRecord *const rr)
+       {
+       AuthRecord *rptr, *prev = NULL;
+       
+       for (rptr = *list; rptr; rptr = rptr->next)
+               {
+               if (rptr == rr)
+                       {
+                       if (prev) prev->next = rptr->next;
+                       else *list  = rptr->next;
+                       rptr->next = NULL;
+                       return mStatus_NoError;
+                       }
+               prev = rptr;
+               }
+       LogMsg("ERROR: unlinkAR - no such active record");
+       return mStatus_UnknownErr;
+       }
+
+mDNSlocal void LinkActiveQuestion(uDNS_GlobalInfo *u, DNSQuestion *q)
+       {
+       if (IsActiveUnicastQuery(q, u))
+               { LogMsg("LinkActiveQuestion - %s (%d) already in list!", q->qname.c, q->qtype); return; }
+       
+       q->next = u->ActiveQueries;
+       u->ActiveQueries = q;
+       }
+
+
+// ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark - Name Server List Management
+#endif
+
+mDNSexport void mDNS_RegisterDNS(mDNS *const m, mDNSv4Addr *const dnsAddr)
+    {
+    //!!!KRS do this dynamically!
+    uDNS_GlobalInfo *u = &m->uDNS_info;
+    int i;
+
+       if (!dnsAddr->NotAnInteger)
+        {
+        LogMsg("ERROR: attempt to register DNS with IP address 0");
+        return;
+        }
+
+    for (i = 0; i < 32; i++)
+        {
+        if (!u->Servers[i].ip.v4.NotAnInteger)
+            {
+            u->Servers[i].ip.v4.NotAnInteger = dnsAddr->NotAnInteger;
+                       u->Servers[i].type = mDNSAddrType_IPv4;
+            return;
+            }
+        if (u->Servers[i].ip.v4.NotAnInteger == dnsAddr->NotAnInteger)
+            {
+            LogMsg("ERROR: mDNS_RegisterDNS - DNS already registered");
+            return;
+            }
+        }
+    if (i == 32) {  LogMsg("ERROR: mDNS_RegisterDNS - too many registered servers");  }
+
+    }
+
+mDNSexport void mDNS_DeregisterDNS(mDNS *const m, mDNSv4Addr *const dnsAddr)
+    {
+    uDNS_GlobalInfo *u = &m->uDNS_info;
+    int i;
+
+    if (!dnsAddr->NotAnInteger)
+        {
+        LogMsg("ERROR: attempt to deregister DNS with IP address 0");
+        return;
+        }
+
+    for (i = 0; i < 32; i++)
+        {
+
+        if (u->Servers[i].ip.v4.NotAnInteger == dnsAddr->NotAnInteger)
+            {
+            u->Servers[i].ip.v4.NotAnInteger = 0;
+            return;
+            }
+        }
+    if (i == 32) {  LogMsg("ERROR: mDNS_DeregisterDNS - no such DNS registered");  }
+    }
+
+mDNSexport void mDNS_DeregisterDNSList(mDNS *const m)
+    {
+    ubzero(m->uDNS_info.Servers, 32 * sizeof(mDNSAddr));
+    }
+
+mDNSexport mDNSBool mDNS_DNSRegistered(mDNS *const m)
+       {
+       int i;
+
+       for (i = 0; i < 32; i++) if (m->uDNS_info.Servers[i].ip.v4.NotAnInteger) return mDNStrue;
+       return mDNSfalse;
+       }
+          
+
+ // ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark - authorization management
+#endif
+
+
+mDNSexport mStatus mDNS_UpdateDomainRequiresAuthentication(mDNS *m, domainname *zone, domainname *key,
+    mDNSu8 *sharedSecret, mDNSu32 ssLen, mDNSBool base64)
+       {
+       uDNS_AuthInfo *info;
+       mDNSu8 keybuf[1024];
+       mDNSs32 keylen;
+       
+       info = (uDNS_AuthInfo*)umalloc(sizeof(uDNS_AuthInfo) + ssLen);
+       if (!info) { LogMsg("ERROR: umalloc"); return mStatus_NoMemoryErr; }
+       ubzero(info, sizeof(uDNS_AuthInfo));
+       ustrcpy(info->zone.c, zone->c);
+       ustrcpy(info->keyname.c, key->c);
+
+       if (base64)
+               {
+               keylen = DNSDigest_Base64ToBin((const char*)sharedSecret, keybuf, 1024);
+               if (keylen < 0)
+                       {
+                       LogMsg("ERROR: mDNS_UpdateDomainRequiresAuthentication - could not convert shared secret from base64");
+                       ufree(info);
+                       return mStatus_UnknownErr;
+                       }               
+               DNSDigest_ConstructHMACKey(info, keybuf, (mDNSu32)keylen);              
+               }
+       else DNSDigest_ConstructHMACKey(info, sharedSecret, ssLen);
+
+    // link into list
+       // !!!KRS this should be a hashtable since we must check if updates are required on each registration
+       info->next = m->uDNS_info.AuthInfoList;
+       m->uDNS_info.AuthInfoList = info;
+       return mStatus_NoError;
+       }
+
+mDNSexport void mDNS_ClearAuthenticationList(mDNS *m)
+       {
+       uDNS_AuthInfo *fptr, *ptr = m->uDNS_info.AuthInfoList;
+       
+       while (ptr)
+               {
+               fptr = ptr;
+               ptr = ptr->next;
+               ufree(fptr);
+               }
+       m->uDNS_info.AuthInfoList = NULL;
+       }
+
+mDNSlocal uDNS_AuthInfo *GetAuthInfoForZone(const uDNS_GlobalInfo *u, const domainname *zone)
+       {
+       uDNS_AuthInfo *ptr;
+       domainname *z;
+       mDNSu32 zoneLen, ptrZoneLen;
+
+       zoneLen = ustrlen(zone->c);
+       for (ptr = u->AuthInfoList; ptr; ptr = ptr->next)
+               {
+               z = &ptr->zone;
+               ptrZoneLen = ustrlen(z->c);
+               if (zoneLen < ptrZoneLen) continue;
+               // return info if zone ends in info->zone
+               if (mDNSPlatformMemSame(z->c, zone->c + (zoneLen - ptrZoneLen), ptrZoneLen)) return ptr;
+               }                 
+       return NULL;
+       }       
+       
+
+
+
+ // ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark - host name and interface management
+#endif
+
+
+mDNSlocal void hostnameCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
+       {
+       // note that the rr is already unlinked if result is non-zero
+
+       if (result == mStatus_MemFree) return;
+       if (result == mStatus_NameConflict && rr->resrec.RecordType == kDNSRecordTypeUnique)
+               {
+               // if we get a name conflict, make sure our name/addr isn't already registered by re-registering
+               rr->resrec.RecordType = kDNSRecordTypeKnownUnique;
+               uDNS_RegisterRecord(m, rr);
+               return;
+               }
+
+       if (rr->resrec.RecordType == kDNSRecordTypeKnownUnique)
+               // we've already tried to re-register.  reset RecordType before returning RR to client
+               {
+               if (result == mStatus_NoSuchRecord)  // name is advertised for some other address
+                       result = mStatus_NameConflict;
+               rr->resrec.RecordType = kDNSRecordTypeUnique;
+               }
+               
+       if (!result) rr->resrec.RecordType = kDNSRecordTypeVerified;
+       if (result)
+               ((NetworkInterfaceInfo *)(rr->RecordContext))->uDNS_info.registered = mDNSfalse;
+       mDNS_HostNameCallback(m, rr, result);   
+       }
+
+
+mDNSlocal void deadvertiseIfCallback(mDNS *const m, AuthRecord *const rr, mStatus err)
+       {
+       (void)m; // unused
+       
+       if (err == mStatus_MemFree) ufree(rr);
+       else LogMsg("deadvertiseIfCallback - error %s for record %s", err, rr->resrec.name.c);
+       }
+ mDNSexport void uDNS_DeadvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set)
+       {
+       AuthRecord *copy;
+       AuthRecord *rr = &set->uDNS_info.RR_A;
+       
+       // NOTE: for compatibility w/ mDNS architecture, we make a copy of the address record before sending a
+       // goodbye, since mDNS does not send goodbyes for address records and expects the memory to be immediately
+       // freed
+       
+       if (set->uDNS_info.registered)
+               {
+               // copy resource record
+               copy = (AuthRecord*)umalloc(sizeof(AuthRecord));  // allocate storage
+               if (!copy) { LogMsg("ERROR: Malloc"); return; }        
+               umemcpy(copy, rr, sizeof(AuthRecord));            // copy all fields
+        copy->resrec.rdata = &copy->rdatastorage;         // set rdata pointer         
+        if (rr->resrec.rdata != &rr->rdatastorage) 
+            { LogMsg("ERROR: uDNS_DeadvertiseInterface - expected local rdata storage.  Aborting deregistration"); return; }
+        
+               // link copy into list
+               copy->next = m->uDNS_info.RecordRegistrations;
+               m->uDNS_info.RecordRegistrations = copy;
+               copy->RecordCallback = deadvertiseIfCallback;
+               
+               // unlink the original
+               unlinkAR(&m->uDNS_info.RecordRegistrations, rr);
+               rr->uDNS_info.state = regState_Unregistered;
+               set->uDNS_info.registered = mDNSfalse;
+               uDNS_DeregisterRecord(m, copy);
+               }
+       else debugf("uDNS_DeadvertiseInterface - interface not registered");
+       return; 
+       }
+
+mDNSexport void uDNS_AdvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set) 
+       {
+       mDNSu8 *ip = set->ip.ip.v4.b;   
+       AuthRecord *a   = &set->uDNS_info.RR_A;
+       a->RecordContext = set;
+       if (set->ip.type != mDNSAddrType_IPv4                                 // non-v4
+               || (ip[0] == 169 && ip[1] == 254)                             // link-local
+               || (ip[0] == 127 && ip[1] == 0 && ip[2] == 0 && ip[3] == 1))  // loopback
+               return;         
+       
+       if (set->uDNS_info.registered && SameDomainName(&m->uDNS_info.hostname, &set->uDNS_info.regname))               
+         return; // already registered
+
+       if (!m->uDNS_info.hostname.c[0])
+               {
+               // no hostname available
+               set->uDNS_info.registered = mDNSfalse;
+               return;
+               }
+               
+       set->uDNS_info.registered = mDNStrue;
+       ustrcpy(set->uDNS_info.regname.c, m->uDNS_info.hostname.c);
+        //!!!KRS temp ttl 1
+       mDNS_SetupResourceRecord(a, mDNSNULL, 0, kDNSType_A,  1, kDNSRecordTypeShared /*Unique*/, hostnameCallback, set); //!!!KRS
+
+       ustrcpy(a->resrec.name.c, m->uDNS_info.hostname.c);
+       a->resrec.rdata->u.ip = set->ip.ip.v4;
+       LogMsg("uDNS_AdvertiseInterface: advertising %s", m->uDNS_info.hostname.c);
+               
+       uDNS_RegisterRecord(m, a); 
+       }
+
+
+// ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark - Incoming Message Processing
+#endif
+
+mDNSlocal mDNSBool sameResourceRecord(ResourceRecord *r1, ResourceRecord *r2)
+       {
+       return (r1->namehash == r2->namehash &&
+                       r1->rrtype == r2->rrtype && 
+                       SameDomainName(&r1->name, &r2->name) &&
+                       SameRData(r1, r2));
+       }
+
+mDNSlocal mDNSBool kaListContainsAnswer(DNSQuestion *question, CacheRecord *rr)
+       {
+       CacheRecord *ptr;
+
+       for (ptr = question->uDNS_info.knownAnswers; ptr; ptr = ptr->next)
+               if (sameResourceRecord(&ptr->resrec, &rr->resrec)) return mDNStrue;
+
+       return mDNSfalse;
+       }
+
+
+mDNSlocal void removeKnownAnswer(DNSQuestion *question, CacheRecord *rr)
+       {
+       CacheRecord *ptr, *prev = NULL;
+
+       for (ptr = question->uDNS_info.knownAnswers; ptr; ptr = ptr->next)
+               {
+               if (sameResourceRecord(&ptr->resrec, &rr->resrec))
+                       {
+                       if (prev) prev->next = ptr->next;
+                       else question->uDNS_info.knownAnswers = ptr->next;
+                       ufree(ptr);
+                       return;
+                       }
+               prev = ptr;
+               }
+       LogMsg("removeKnownAnswer() called for record not in KA list");
+       }
+
+
+mDNSlocal void addKnownAnswer(DNSQuestion *question, const CacheRecord *rr)
+       {
+       CacheRecord *newCR = NULL;
+       mDNSu32 size;   
+
+       size = sizeof(CacheRecord) + rr->resrec.rdlength - InlineCacheRDSize;
+       newCR = (CacheRecord *)umalloc(size);
+       if (!newCR) { LogMsg("ERROR: addKnownAnswer - malloc"); return; }
+       umemcpy(newCR, rr, size);
+       newCR->resrec.rdata = (RData*)&newCR->rdatastorage;
+       newCR->resrec.rdata->MaxRDLength = rr->resrec.rdlength;
+       newCR->next = question->uDNS_info.knownAnswers;
+       question->uDNS_info.knownAnswers = newCR;
+       }
+
+mDNSlocal void deriveGoodbyes(mDNS * const m, DNSMessage *msg, const  mDNSu8 *end, DNSQuestion *question)
+       {
+       const mDNSu8 *ptr;
+       int i;
+       CacheRecord *fptr, *ka, *cr, *answers = NULL, *prev = NULL;
+       LargeCacheRecord *lcr;
+       
+       if (question != m->uDNS_info.CurrentQuery) { LogMsg("ERROR: deriveGoodbyes called without CurrentQuery set!"); return; }
+
+       ptr = LocateAnswers(msg, end);
+       if (!ptr) goto pkt_error;
+
+       if (!msg->h.numAnswers)
+               {
+               // delete the whole KA list
+               ka = question->uDNS_info.knownAnswers;
+               while (ka)
+                       {
+                       debugf("deriving goodbye for %s", ka->resrec.name.c);
+                       question->QuestionCallback(m, question, &ka->resrec, mDNSfalse);
+                       if (question != m->uDNS_info.CurrentQuery)
+                               {
+                               debugf("deriveGoodbyes - question removed via callback.  returning.");
+                               return;
+                               }
+                       fptr = ka;
+                       ka = ka->next;
+                       ufree(fptr);
+                       }
+               question->uDNS_info.knownAnswers = NULL;
+               return;
+               }
+       
+       // make a list of all the new answers
+       for (i = 0; i < msg->h.numAnswers; i++)
+               {
+               lcr = (LargeCacheRecord *)umalloc(sizeof(LargeCacheRecord));
+               if (!lcr) goto malloc_error;
+               ubzero(lcr, sizeof(LargeCacheRecord));
+               ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAns, lcr);
+               if (!ptr) goto pkt_error;
+               cr = &lcr->r;
+               if (ResourceRecordAnswersQuestion(&cr->resrec, question)) 
+                       {
+                       cr->next = answers;
+                       answers = cr;
+                       }
+               else ufree(cr);
+               }
+       
+       // make sure every known answer is in the answer list
+       ka = question->uDNS_info.knownAnswers;
+       while (ka)
+               {
+               for (cr = answers; cr; cr = cr->next)
+                       { if (sameResourceRecord(&ka->resrec, &cr->resrec)) break; }
+               if (!cr)
+                       {
+                       // record is in KA list but not answer list - remove from KA list
+                       if (prev) prev->next = ka->next;
+                       else question->uDNS_info.knownAnswers = ka->next;
+                       debugf("deriving goodbye for %s", ka->resrec.name.c);
+                       question->QuestionCallback(m, question, &ka->resrec, mDNSfalse);
+                       if (question != m->uDNS_info.CurrentQuery)
+                               {
+                               debugf("deriveGoodbyes - question removed via callback.  returning.");
+                               return;
+                               }
+                       fptr = ka;
+                       ka = ka->next;
+                       ufree(fptr);
+                       }
+               else
+                       {
+                       prev = ka;
+                       ka = ka->next;
+                       }
+               }
+
+       // free temp answers list
+       cr = answers;
+       while (cr) { fptr = cr; cr = cr->next; ufree(fptr); }
+
+       return;
+       
+       pkt_error:
+       LogMsg("ERROR: deriveGoodbyes - received malformed response to query for %s (%d)",
+                  question->qname.c, question->qtype);
+       return;
+
+       malloc_error:
+       LogMsg("ERROR: Malloc");        
+       }
+
+mDNSlocal void pktResponseHndlr(mDNS * const m, DNSMessage *msg, const  mDNSu8 *end, DNSQuestion *question, mDNSBool llq)
+       {
+       const mDNSu8 *ptr;
+       int i;
+       LargeCacheRecord lcr;
+       CacheRecord *cr = &lcr.r;
+       mDNSBool goodbye, inKAList;
+       LLQ_Info *llqInfo = question->uDNS_info.llq;
+       
+       if (question != m->uDNS_info.CurrentQuery)
+               { LogMsg("ERROR: pktResponseHdnlr called without CurrentQuery ptr set!");  return; }
+               
+       ptr = LocateAnswers(msg, end);
+       if (!ptr) goto pkt_error;
+
+       for (i = 0; i < msg->h.numAnswers; i++)
+               {
+               ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr);
+               if (!ptr) goto pkt_error;
+               if (ResourceRecordAnswersQuestion(&cr->resrec, question))
+                       {
+                       goodbye = llq ? ((mDNSs32)cr->resrec.rroriginalttl == -1) : mDNSfalse;
+                       inKAList = kaListContainsAnswer(question, cr);
+
+                       if ((goodbye && !inKAList) || (!goodbye && inKAList)) continue;  // list up to date
+                       if (!inKAList) addKnownAnswer(question, cr);
+                       if (goodbye) removeKnownAnswer(question, cr);
+                       question->QuestionCallback(m, question, &cr->resrec, !goodbye);
+                       if (question != m->uDNS_info.CurrentQuery)
+                               {
+                               debugf("pktResponseHndlr - CurrentQuery changed by QuestionCallback - returning");
+                               return;
+                               }
+                       }                       
+               else
+                       {
+                       LogMsg("unexpected answer: %s", cr->resrec.name.c);
+                       }
+               }
+       if (llq && (llqInfo->state == LLQ_Poll || llqInfo->deriveRemovesOnResume))      
+               { deriveGoodbyes(m, msg, end,question);  llqInfo->deriveRemovesOnResume = mDNSfalse; }
+       //!!!KRS should we derive goodbyes for non-LLQs?
+
+       return;
+
+       pkt_error:
+       LogMsg("ERROR: pktResponseHndlr - received malformed response to query for %s (%d)",
+                  question->qname.c, question->qtype);
+       return;
+       }
+
+mDNSlocal void simpleResponseHndlr(mDNS * const m, DNSMessage *msg, const  mDNSu8 *end, DNSQuestion *question, void *context)
+       {
+       (void)context; // unused
+       pktResponseHndlr(m, msg, end, question, mDNSfalse);
+       }
+
+mDNSlocal void llqResponseHndlr(mDNS * const m, DNSMessage *msg, const  mDNSu8 *end, DNSQuestion *question, void *context)
+       {
+       (void)context; // unused
+       pktResponseHndlr(m, msg, end, question, mDNStrue);
+       }
+
+
+
+mDNSlocal void unlinkSRS(uDNS_GlobalInfo *u, ServiceRecordSet *srs)
+       {
+       ServiceRecordSet *ptr, *prev = NULL;
+       
+       for (ptr = u->ServiceRegistrations; ptr; ptr = ptr->next)
+               {
+               if (ptr == srs)
+                       {
+                       if (prev) prev->next = ptr->next;
+                       else u->ServiceRegistrations = ptr->next;
+                       ptr->next = NULL;
+                       return;
+                       }
+               prev = ptr;
+               }
+       LogMsg("ERROR: unlinkSRS - SRS not found in ServiceRegistrations list");
+       }
+
+
+mDNSlocal mStatus checkUpdateResult(domainname *name, mDNSu8 rcode, const DNSMessage *msg)
+       {
+       (void)msg;  // currently unused, needed for TSIG errors
+       if (!rcode) return mStatus_NoError;
+       else if (rcode == kDNSFlag1_RC_YXDomain)
+               {
+               LogMsg("Name in use: %s", name->c);
+               return mStatus_NameConflict;
+               }
+       else if (rcode == kDNSFlag1_RC_Refused)
+               {
+               LogMsg("Update %s refused", name->c);
+               return mStatus_Refused;
+               }
+       else if (rcode == kDNSFlag1_RC_NXRRSet)
+               {
+               LogMsg("Reregister refusted (NXRRSET): %s", name->c);
+               return mStatus_NoSuchRecord;
+               }
+       else if (rcode == kDNSFlag1_RC_NotAuth)
+               {
+               LogMsg("Permission denied (NOAUTH): %s", name->c);
+               return mStatus_NoAuth;
+               }
+       else if (rcode == kDNSFlag1_RC_FmtErr)
+               {
+               LogMsg("Format Error: %s", name->c);
+               return mStatus_UnknownErr;
+               //!!!KRS need to parse message for TSIG errors
+               }
+       else
+               {
+               LogMsg("Update %s failed with rcode %d", name->c, rcode);
+               return mStatus_UnknownErr;
+               }
+       }
+
+mDNSlocal void hndlServiceUpdateReply(mDNS * const m, ServiceRecordSet *srs,  mStatus err)
+       {       
+    //!!!KRS make sure we're doing the right thing w/ MemFree
+       
+       switch (srs->uDNS_info.state)
+               {
+               case regState_Pending:
+               case regState_Refresh:
+                       if (err)
+                               {
+                               if (srs->uDNS_info.lease && err == mStatus_UnknownErr)
+                                       {
+                                       LogMsg("Re-trying update of service %s without lease option", srs->RR_SRV.resrec.name.c);
+                                       srs->uDNS_info.lease = mDNSfalse;
+                                       srs->uDNS_info.expire = -1;
+                                       SendServiceRegistration(m, srs);
+                                       return;
+                                       }
+                               else
+                                       {
+                                       LogMsg("hndlServiceUpdateReply: Error %d returned for registration of %s",
+                                                  err, srs->RR_SRV.resrec.name.c);
+                                       srs->uDNS_info.state = regState_Unregistered;
+                                       break;
+                                       }
+                               }
+                       else
+                               {
+                               if (srs->uDNS_info.state == regState_Refresh)
+                                       {
+                                       srs->uDNS_info.state = regState_Registered;                             
+                                       return;
+                                       }
+                               srs->uDNS_info.state = regState_Registered;
+                               break;
+                               }                               
+               case regState_DeregPending:
+                       if (err) LogMsg("hndlServiceUpdateReply: Error %d returned for dereg of %s",
+                                                       err, srs->RR_SRV.resrec.name.c);
+                       else err = mStatus_MemFree;
+                       break;
+               case regState_DeregDeferred:
+                       if (err) LogMsg("hndlServiceUpdateReply: Error %d received prior to deferred derigstration of %s",
+                                                       err, srs->RR_SRV.resrec.name.c);
+                       LogMsg("Performing deferred deregistration of %s", srs->RR_SRV.resrec.name.c);
+                       uDNS_DeregisterService(m, srs);
+                       return;                 
+               case regState_TargetChange:
+                       if (err)
+                               {
+                               LogMsg("hdnlServiceUpdateReply: Error %d returned for host target update of %s",
+                                          err, srs->RR_SRV.resrec.name.c);
+                               srs->uDNS_info.state = regState_Unregistered;
+                               // !!!KRS we are leaving the ptr/txt records registered
+                               }
+                       else srs->uDNS_info.state = regState_Registered;
+                       break;                  
+               default:
+                       LogMsg("hndlServiceUpdateReply called for service %s in unexpected state %d with error %d.  Unlinking.",
+                                  srs->RR_SRV.resrec.name.c, srs->uDNS_info.state, err);
+                       err = mStatus_UnknownErr;
+               }
+
+       if (err)
+               {
+               unlinkSRS(&m->uDNS_info, srs);          // name conflicts, force dereg, and errors
+               srs->uDNS_info.state = regState_Unregistered;
+               }
+       
+       srs->ServiceCallback(m, srs, err);
+       // NOTE: do not touch structures after calling ServiceCallback
+       }
+
+mDNSlocal void hndlRecordUpdateReply(mDNS *m, AuthRecord *rr, mStatus err)
+       {
+       uDNS_GlobalInfo *u = &m->uDNS_info;
+       
+       if (rr->uDNS_info.state == regState_DeregPending)
+               {                                       
+               debugf("Received reply for deregister record %s type %d", rr->resrec.name.c, rr->resrec.rrtype);
+               if (err) LogMsg("ERROR: Deregistration of record %s type %s failed with error %d",
+                                               rr->resrec.name.c, rr->resrec.rrtype, err);
+               else err = mStatus_MemFree;
+               if (unlinkAR(&m->uDNS_info.RecordRegistrations, rr))
+                       LogMsg("ERROR: Could not unlink resource record following deregistration");
+               rr->uDNS_info.state = regState_Unregistered;
+               rr->RecordCallback(m, rr, err);
+               return;
+               }
+
+       if (rr->uDNS_info.state == regState_DeregDeferred)
+               {
+               if (err)
+                       {
+                       LogMsg("Cancelling deferred deregistration record %s type %d due to registration error %d",
+                                  rr->resrec.name.c, rr->resrec.rrtype, err);
+                       unlinkAR(&m->uDNS_info.RecordRegistrations, rr);
+                       rr->uDNS_info.state = regState_Unregistered;
+                       return;
+                       }
+               LogMsg("Calling deferred deregistration of record %s type %d",
+                          rr->resrec.name.c, rr->resrec.rrtype);
+               rr->uDNS_info.state = regState_Registered;
+               uDNS_DeregisterRecord(m, rr);                                   
+               return;
+               }
+
+       if (rr->uDNS_info.state == regState_Pending || rr->uDNS_info.state == regState_Refresh)
+               {
+               if (err)
+                       {
+                       if (rr->uDNS_info.lease && err == mStatus_UnknownErr)
+                               {
+                               LogMsg("Re-trying update of record %s without lease option", rr->resrec.name.c);
+                               rr->uDNS_info.lease = mDNSfalse;
+                               rr->uDNS_info.expire = -1;
+                               sendRecordRegistration(m, rr);
+                               return;
+                               }
+                       
+                       LogMsg("Registration of record %s type %d failed with error %d",
+                                  rr->resrec.name.c, rr->resrec.rrtype, err);
+                       unlinkAR(&u->RecordRegistrations, rr); 
+                       rr->uDNS_info.state = regState_Unregistered;
+                       }
+               else
+                       {
+                       if (rr->uDNS_info.state == regState_Refresh)
+                               rr->uDNS_info.state = regState_Registered;                      
+                       else
+                               {
+                               rr->uDNS_info.state = regState_Registered;
+                               rr->RecordCallback(m, rr, err);
+                               }
+                       return;
+                       }
+               }
+       
+       LogMsg("Received unexpected response for record %s type %d, in state %d, with response error %d",
+                  rr->resrec.name.c, rr->resrec.rrtype, rr->uDNS_info.state, err);
+       }
+
+
+mDNSlocal void SetUpdateExpiration(mDNS *m, DNSMessage *msg, const mDNSu8 *end, uDNS_RegInfo *info)
+       {
+       LargeCacheRecord lcr;
+       const mDNSu8 *ptr;
+       int i;
+       mDNSu32 lease = 0;
+
+       ptr = LocateAdditionals(msg, end);
+
+       if (info->lease && (ptr = LocateAdditionals(msg, end)))
+               {
+               for (i = 0; i < msg->h.numAdditionals; i++)
+                       {
+                       ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &lcr);
+                       if (!ptr) break;
+                       if (lcr.r.resrec.rrtype == kDNSType_OPT)
+                               {
+                               if (lcr.r.resrec.rdlength < LEASE_OPT_SIZE) continue;
+                               if (lcr.r.resrec.rdata->u.opt.opt != kDNSOpt_Lease) continue;
+                               lease = lcr.r.resrec.rdata->u.opt.OptData.lease;
+                               break;
+                               }
+                       }
+               }
+       
+       if (lease > 0)
+               info->expire = (mDNSPlatformTimeNow() + (((mDNSs32)lease * mDNSPlatformOneSecond)) * 3/4);
+       else info->expire = -1;
+       }
+
+mDNSexport void uDNS_ReceiveMsg(mDNS *const m, DNSMessage *const msg, const mDNSu8 *const end,
+       const mDNSAddr *const srcaddr, const mDNSIPPort srcport, const mDNSAddr *const dstaddr,
+       const mDNSIPPort dstport, const mDNSInterfaceID InterfaceID, mDNSu8 ttl)
+       {
+       DNSQuestion *qptr;
+       AuthRecord *rptr;
+       ServiceRecordSet *sptr;
+       mStatus err = mStatus_NoError;
+       uDNS_GlobalInfo *u = &m->uDNS_info;
+       
+       mDNSu8 StdR    = kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery;
+       mDNSu8 UpdateR = kDNSFlag0_OP_Update   | kDNSFlag0_QR_Response;
+       mDNSu8 QR_OP   = (mDNSu8)(msg->h.flags.b[0] & kDNSFlag0_QROP_Mask);
+       mDNSu8 rcode   = (mDNSu8)(msg->h.flags.b[1] & kDNSFlag1_RC);
+       
+    // unused
+       (void)srcaddr;
+       (void)srcport;
+       (void)dstaddr;
+       (void)dstport;
+       (void)ttl;
+       (void)InterfaceID;
+       
+       if (QR_OP == StdR)
+               {               
+               // !!!KRS we should to a table lookup here to see if it answers an LLQ or a 1-shot
+               if (recvLLQResponse(m, msg, end, srcaddr, srcport, InterfaceID)) return;
+       
+               for (qptr = u->ActiveQueries; qptr; qptr = qptr->next)
+                       {
+                       //!!!KRS we should have a hashtable, hashed on message id
+                       if (qptr->uDNS_info.id.NotAnInteger == msg->h.id.NotAnInteger)
+                               {
+                               if (msg->h.flags.b[0] & kDNSFlag0_TC)
+                                       { hndlTruncatedAnswer(qptr, srcaddr, m); return; }
+                               else
+                                       {
+                                       u->CurrentQuery = qptr;
+                                       qptr->uDNS_info.responseCallback(m, msg, end, qptr, qptr->uDNS_info.context);
+                                       u->CurrentQuery = NULL;
+                                       // Note: responseCallback can invalidate qptr
+                                       return;
+                                       }
+                               }
+                       }
+               }
+       if (QR_OP == UpdateR)
+               {
+               for (sptr = u->ServiceRegistrations; sptr; sptr = sptr->next)
+                       {
+                       if (sptr->uDNS_info.id.NotAnInteger == msg->h.id.NotAnInteger)
+                               {
+                               err = checkUpdateResult(&sptr->RR_SRV.resrec.name, rcode, msg);
+                               if (!err) SetUpdateExpiration(m, msg, end, &sptr->uDNS_info);
+                               hndlServiceUpdateReply(m, sptr, err);
+                               return;
+                               }
+                       }
+               for (rptr = u->RecordRegistrations; rptr; rptr = rptr->next)
+                       {
+                       if (rptr->uDNS_info.id.NotAnInteger == msg->h.id.NotAnInteger)
+                               {
+                               err = checkUpdateResult(&rptr->resrec.name, rcode, msg);
+                               if (!err) SetUpdateExpiration(m, msg, end, &rptr->uDNS_info);                           
+                               hndlRecordUpdateReply(m, rptr, err);
+                               return;
+                               }
+                       }
+               }
+       debugf("Received unexpected response: ID %d matches no active records", mDNSVal16(msg->h.id));
+       }
+
+               
+mDNSlocal void receiveMsg(mDNS *const m, DNSMessage *const msg, const mDNSu8 *const end,
+       const mDNSInterfaceID InterfaceID)
+       {
+       mDNSAddr *sa = NULL, *da = NULL;
+       mDNSIPPort sp, dp;
+       mDNSu8 ttl = 0;
+
+       sp.NotAnInteger = 0;
+       dp.NotAnInteger = 0;
+       uDNS_ReceiveMsg(m, msg, end, sa, sp, da, dp, InterfaceID, ttl);
+       }
+
+//!!!KRS this should go away (don't just pick one randomly!)
+mDNSlocal const mDNSAddr *getInitializedDNS(uDNS_GlobalInfo *u)
+    {
+    int i;
+    for (i = 0; i < 32; i++)
+               if (u->Servers[i].ip.v4.NotAnInteger) return &u->Servers[i];
+
+       return NULL;
+    }
+
+// ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark - Query Routines
+#endif
+
+#define sameID(x,y) mDNSPlatformMemSame(x,y,8)
+
+mDNSlocal void initializeQuery(DNSMessage *msg, DNSQuestion *question)
+       {
+       mDNSOpaque16 flags = QueryFlags;
+       
+       ubzero(msg, sizeof(msg));
+       flags.b[0] |= kDNSFlag0_RD;  // recursion desired
+    InitializeDNSMessage(&msg->h, question->uDNS_info.id, flags);
+       }
+
+mDNSlocal mStatus constructQueryMsg(DNSMessage *msg, mDNSu8 **endPtr, DNSQuestion *const question)
+       {
+       initializeQuery(msg, question);
+
+       *endPtr = putQuestion(msg, msg->data, msg->data + AbsoluteMaxDNSMessageData, &question->qname, question->qtype, question->qclass);
+    if (!*endPtr)
+        {
+        LogMsg("ERROR: Unicast query out of space in packet");
+        return mStatus_UnknownErr;
+        }
+       return mStatus_NoError;
+       }
+
+mDNSlocal mDNSu8 *putLLQ(DNSMessage *const msg, mDNSu8 *ptr, DNSQuestion *question, LLQOptData *data, mDNSBool includeQuestion)
+       {
+       AuthRecord rr;
+       ResourceRecord *opt = &rr.resrec; 
+       rdataOpt *optRD;
+       
+       //!!!KRS when we implement multiple llqs per message, we'll need to memmove anything past the question section
+       if (includeQuestion)
+               {
+               ptr = putQuestion(msg, ptr, msg->data + AbsoluteMaxDNSMessageData, &question->qname, question->qtype, question->qclass);
+               if (!ptr) { LogMsg("ERROR: putLLQ - putQuestion"); return NULL; }
+               }
+       // locate OptRR if it exists, set pointer to end 
+       // !!!KRS implement me
+
+       
+       // format opt rr (fields not specified are zero-valued)
+       ubzero(&rr, sizeof(AuthRecord));
+       opt->rdata = &rr.rdatastorage;
+       
+       opt->RecordType = kDNSRecordTypeKnownUnique;  // to avoid warnings in other layers
+       opt->rrtype = kDNSType_OPT;
+       opt->rdlength = LLQ_OPT_SIZE;
+       opt->rdestimate = LLQ_OPT_SIZE;
+
+       optRD = &rr.resrec.rdata->u.opt;
+       optRD->opt = kDNSOpt_LLQ;
+       optRD->optlen = sizeof(LLQOptData);
+       umemcpy(&optRD->OptData.llq, data, sizeof(LLQOptData));
+       ptr = PutResourceRecordTTL(msg, ptr, &msg->h.numAdditionals, opt, 0);
+       if (!ptr) { LogMsg("ERROR: putLLQ - PutResourceRecordTTL"); return NULL; }
+
+       return ptr;
+       }
+
+                         
+mDNSlocal mDNSBool getLLQAtIndex(mDNS *m, DNSMessage *msg, const mDNSu8 *end, LLQOptData *llq, int index)
+       {
+       LargeCacheRecord lcr;
+       int i;
+       const mDNSu8 *ptr;
+       
+       ptr = LocateAdditionals(msg, end);
+       if (!ptr) return mDNSfalse;
+
+       // find the last additional
+       for (i = 0; i < msg->h.numAdditionals; i++)
+//             { ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &lcr); if (!ptr) return mDNSfalse; }
+//!!!KRS workaround for LH server bug, which puts OPT as first additional
+               { ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &lcr); if (!ptr) return mDNSfalse; if (lcr.r.resrec.rrtype == kDNSType_OPT) break; }               
+       if (lcr.r.resrec.rrtype != kDNSType_OPT) return mDNSfalse;
+       if (lcr.r.resrec.rdlength < (index + 1) * LLQ_OPT_SIZE) return mDNSfalse;  // rdata too small 
+       umemcpy(llq, (mDNSu8 *)&lcr.r.resrec.rdata->u.opt.OptData.llq + (index * sizeof(LLQOptData)), sizeof(LLQOptData));
+       return mDNStrue;
+       }
+
+mDNSlocal void recvRefreshReply(mDNS *m, DNSMessage *msg, const mDNSu8 *end, DNSQuestion *q)
+       {
+       LLQ_Info *qInfo;
+       LLQOptData pktData;
+
+       qInfo = q->uDNS_info.llq;
+       if (!getLLQAtIndex(m, msg, end, &pktData, 0)) { LogMsg("ERROR recvRefreshReply - getLLQAtIndex"); return; }
+       if (pktData.llqOp != kLLQ_Refresh) return;
+       if (!sameID(pktData.id, qInfo->id)) { LogMsg("recvRefreshReply - ID mismatch.  Discarding");  return; }
+       if (pktData.err != LLQErr_NoError) { LogMsg("recvRefreshReply: received error %d from server", pktData.err); return; }
+
+       qInfo->expire = mDNSPlatformTimeNow() + ((mDNSs32)pktData.lease * mDNSPlatformOneSecond);
+       qInfo->retry = qInfo->expire + ((mDNSs32)pktData.lease * mDNSPlatformOneSecond * 3/4);
+       qInfo->origLease = pktData.lease;
+       qInfo->state = LLQ_Established; 
+       }
+
+mDNSlocal void sendLLQRefresh(mDNS *m, DNSQuestion *q, mDNSu32 lease)
+       {
+       DNSMessage msg;
+       mDNSu8 *end;
+       LLQOptData llq;
+       LLQ_Info *info = q->uDNS_info.llq;
+       mStatus err;
+
+       if (info->state == kLLQ_Refresh && info->ntries >= kLLQ_MAX_TRIES)
+               {
+               LogMsg("sendLLQRefresh - %d failed attempts for llq %s", info->ntries, q->qname.c);
+               info->state = LLQ_Retry;
+               info->retry = mDNSPlatformTimeNow() + kLLQ_DEF_RETRY * mDNSPlatformOneSecond;
+               info->deriveRemovesOnResume = mDNStrue;
+               return;
+               //!!!KRS handle this - periodically try to re-establish
+               }
+               
+       llq.vers = kLLQ_Vers;
+       llq.llqOp = kLLQ_Refresh;
+       llq.err = LLQErr_NoError;
+       umemcpy(llq.id, info->id, 8);
+       llq.lease = lease;
+
+       initializeQuery(&msg, q);
+       end = putLLQ(&msg, msg.data, q, &llq, mDNStrue);
+       if (!end) { LogMsg("ERROR: sendLLQRefresh - putLLQ"); return; }
+       
+       err = mDNSSendDNSMessage(m, &msg, end, q->InterfaceID, &info->servAddr, info->servPort);
+       if (err) LogMsg("ERROR: sendLLQRefresh - mDNSSendDNSMessage returned %d", err);
+
+       if (info->state == LLQ_Established) info->ntries = 1;
+       else info->ntries++;
+       info->state = LLQ_Refresh;
+       q->LastQTime = mDNSPlatformTimeNow();
+       info->retry = (info->expire - q->LastQTime) / 2;        
+       }
+
+mDNSlocal void recvLLQEvent(mDNS *m, DNSQuestion *q, DNSMessage *msg, const mDNSu8 *end, const mDNSAddr *srcaddr, mDNSIPPort srcport, mDNSInterfaceID InterfaceID)
+       {
+       DNSMessage ack;
+       mDNSu8 *ackEnd = ack.data;
+       mStatus err;
+
+    // invoke response handler
+       m->uDNS_info.CurrentQuery = q;
+       q->uDNS_info.responseCallback(m, msg, end, q, q->uDNS_info.context);
+       if (m->uDNS_info.CurrentQuery != q) return;
+       
+    //  format and send ack
+       InitializeDNSMessage(&ack.h, msg->h.id, ResponseFlags);
+       ackEnd = putQuestion(&ack, ack.data, ack.data + AbsoluteMaxDNSMessageData, &q->qname, q->qtype, q->qclass);
+       if (!ackEnd) { LogMsg("ERROR: recvLLQEvent - putQuestion");  return; }
+       err = mDNSSendDNSMessage(m, &ack, ackEnd, InterfaceID, srcaddr, srcport); 
+       if (err) LogMsg("ERROR: recvLLQEvent - mDNSSendDNSMessage returned %d", err);
+    }
+
+
+
+mDNSlocal void hndlChallengeResponseAck(mDNS *m, DNSMessage *pktMsg, const mDNSu8 *end, LLQOptData *llq, DNSQuestion *q)
+       {
+       LLQ_Info *info = q->uDNS_info.llq;
+       
+       if (llq->err) { LogMsg("hndlChallengeResponseAck - received error %d from server", llq->err); goto error; }
+       if (!sameID(info->id, llq->id)) { LogMsg("hndlChallengeResponseAck - ID changed.  discarding"); return; } // this can happen rarely (on packet loss + reordering)
+       info->expire = mDNSPlatformTimeNow() + ((mDNSs32)llq->lease * mDNSPlatformOneSecond);
+       info->retry = info->expire + ((mDNSs32)llq->lease * mDNSPlatformOneSecond * 3/4);
+       info->origLease = llq->lease;
+       info->state = LLQ_Established;  
+       q->uDNS_info.responseCallback = llqResponseHndlr;
+       llqResponseHndlr(m, pktMsg, end, q, NULL);
+       return;
+
+       error:
+       info->state = LLQ_Error;
+       }
+
+mDNSlocal void sendChallengeResponse(mDNS *m, DNSQuestion *q, LLQOptData *llq)
+       {
+       LLQ_Info *info = q->uDNS_info.llq;
+       DNSMessage response;
+       mDNSu8 *responsePtr = response.data;
+       mStatus err;
+       LLQOptData llqBuf;
+       mDNSs32 timenow = mDNSPlatformTimeNow();
+       
+       if (info->ntries++ == kLLQ_MAX_TRIES)
+               {
+               LogMsg("sendChallengeResponse: %d failed attempts for LLQ %s. Will re-try in %d minutes",
+                          kLLQ_MAX_TRIES, q->qname.c, kLLQ_DEF_RETRY / 60);
+               info->state = LLQ_Retry;
+               info->retry = timenow + (kLLQ_DEF_RETRY * mDNSPlatformOneSecond);
+               // !!!KRS give a callback error in these cases?
+               return;
+               }
+               
+
+       if (!llq)
+               {
+               llq = &llqBuf;
+               llq->vers    = kLLQ_Vers;
+               llq->llqOp   = kLLQ_Setup;
+               llq->err     = LLQErr_NoError;
+               umemcpy(llq->id, info->id, 8);
+               llq->lease    = info->origLease;
+               }
+
+       q->LastQTime = timenow;
+       info->retry = timenow  + (kLLQ_INIT_RESEND * info->ntries * mDNSPlatformOneSecond);
+       
+       if (constructQueryMsg(&response, &responsePtr, q)) goto error;
+       responsePtr = putLLQ(&response, responsePtr, q, llq, mDNSfalse);
+       if (!responsePtr) { LogMsg("ERROR: sendChallengeResponse - putLLQ"); goto error; }
+       
+       err = mDNSSendDNSMessage(m, &response, responsePtr, q->InterfaceID, &info->servAddr, info->servPort);
+       if (err) LogMsg("ERROR: sendChallengeResponse - mDNSSendDNSMessage returned %d", err);
+       // on error, we procede as normal and retry after the appropriate interval
+
+       return;
+
+       error:
+       info->state = LLQ_Error;
+       }
+
+
+
+mDNSlocal void hndlRequestChallenge(mDNS *m, DNSMessage *pktMsg, const mDNSu8 *end, LLQOptData *llq, DNSQuestion *q)
+       {
+       LLQ_Info *info = q->uDNS_info.llq;
+       mDNSs32 timenow = mDNSPlatformTimeNow();
+       switch(llq->err)
+               {
+               case LLQErr_NoError: break;
+               case LLQErr_ServFull:
+                       LogMsg("hndlRequestChallenge - received ServFull from server for LLQ %s.  Retry in %d sec", q->qname.c, llq->lease);
+                       info->retry = timenow + ((mDNSs32)llq->lease * mDNSPlatformOneSecond);
+                       info->state = LLQ_Retry;
+                       simpleResponseHndlr(m, pktMsg, end, q, NULL);  // get available answers
+                       info->deriveRemovesOnResume = mDNStrue;
+               case LLQErr_Static:
+                       info->state = LLQ_Static;
+                       LogMsg("LLQ %s: static", q->qname.c);
+                       simpleResponseHndlr(m, pktMsg, end, q, NULL);
+                       return;
+               case LLQErr_FormErr:
+                       LogMsg("ERROR: hndlRequestChallenge - received FormErr from server for LLQ %s", q->qname.c);
+                       goto error;
+               case LLQErr_BadVers:
+                       LogMsg("ERROR: hndlRequestChallenge - received BadVers from server");
+                       goto error;
+               case LLQErr_UnknownErr:
+                       LogMsg("ERROR: hndlRequestChallenge - received UnknownErr from server for LLQ %s", q->qname.c);
+                       goto error;
+               default:
+                       LogMsg("ERROR: hndlRequestChallenge - received invalid error %d for LLQ %s", llq->err, q->qname.c);
+                       goto error;
+               }
+
+       if (info->origLease != llq->lease)
+               LogMsg("hndlRequestChallenge: requested lease %d, granted lease %d", info->origLease, llq->lease);
+
+       // cache expiration in case we go to sleep before finishing setup
+       info->origLease = llq->lease;
+       info->expire = timenow + ((mDNSs32)llq->lease * mDNSPlatformOneSecond);
+
+       // update state and timestamp
+       info->state = LLQ_SecondaryRequest;
+       umemcpy(info->id, llq->id, 8);
+       info->ntries = 0; // first attempt to send response
+
+       sendChallengeResponse(m, q, llq);
+       return;
+
+
+       error:
+       info->state = LLQ_Error;        
+       }
+
+
+// response handler for initial and secondary setup responses
+mDNSlocal void recvSetupResponse(mDNS *m, DNSMessage *pktMsg, const mDNSu8 *end, DNSQuestion *q, void *clientContext)
+       {
+       DNSQuestion pktQuestion;
+       LLQOptData llq;
+       const mDNSu8 *ptr = pktMsg->data;
+       LLQ_Info *info = q->uDNS_info.llq;
+       mDNSu8 rcode = (mDNSu8)(pktMsg->h.flags.b[1] & kDNSFlag1_RC);
+
+       (void)clientContext;  // unused
+       
+       if (rcode && rcode != kDNSFlag1_RC_NXDomain)
+               {
+               LogMsg("LLQ Setup for %s failed with rcode %d.  Reverting to polling mode", q->qname.c, rcode);
+               info->state = LLQ_Poll;
+               q->uDNS_info.responseCallback = simpleResponseHndlr;
+               q->LastQTime = mDNSPlatformTimeNow();
+               q->ThisQInterval = 1;
+               return;
+               }
+       
+       ptr = getQuestion(pktMsg, ptr, end, 0, &pktQuestion);
+       if (!ptr) { LogMsg("ERROR: recvSetupResponse - getQuestion"); goto error; }
+       if (!SameDomainName(&q->qname, &pktQuestion.qname))
+               { LogMsg("ERROR: recvSetupResponse - mismatched question in response for llq setup %s", q->qname.c);   goto error; }
+
+       if (!getLLQAtIndex(m, pktMsg, end, &llq, 0)) { LogMsg("ERROR: recvSetupResponse - GetLLQAtIndex"); goto error; }
+       if (llq.llqOp != kLLQ_Setup) { LogMsg("ERROR: recvSetupResponse - bad op %d", llq.llqOp); goto error; } 
+       if (llq.vers != kLLQ_Vers) { LogMsg("ERROR: recvSetupResponse - bad vers %d", llq.vers);  goto error; } 
+
+       if (info->state == LLQ_InitialRequest) { hndlRequestChallenge(m, pktMsg, end, &llq, q); return; }
+       if (info->state == LLQ_SecondaryRequest) { hndlChallengeResponseAck(m, pktMsg, end, &llq, q); return; }
+       LogMsg("recvSetupResponse - bad state %d", info->state);
+
+
+       error:
+       info->state = LLQ_Error;
+       }
+
+
+
+mDNSlocal void startLLQHandshake(mDNS *m, LLQ_Info *info)
+       {
+       DNSMessage msg;
+       mDNSu8 *end;
+       LLQOptData llqData;
+       DNSQuestion *q = info->question; 
+       mStatus err;
+       mDNSs32 timenow = mDNSPlatformTimeNow();
+       
+       if (info->ntries++ == kLLQ_MAX_TRIES)
+               {
+               LogMsg("startLLQHandshake: %d failed attempts for LLQ %s. Will re-try in %d minutes",
+                          kLLQ_MAX_TRIES, q->qname.c, kLLQ_DEF_RETRY / 60);
+               info->state = LLQ_Retry;
+               info->retry = timenow + (kLLQ_DEF_RETRY * mDNSPlatformOneSecond);
+               // !!!KRS give a callback error in these cases?
+               return;
+               }       
+       
+    // set llq rdata
+       llqData.vers    = kLLQ_Vers;
+       llqData.llqOp   = kLLQ_Setup;
+       llqData.err     = LLQErr_NoError;
+       ubzero(llqData.id, 8);
+       llqData.lease    = kLLQ_DefLease;
+
+       initializeQuery(&msg, q);
+       end = putLLQ(&msg, msg.data, q, &llqData, mDNStrue);
+       if (!end)
+               {
+               LogMsg("ERROR: startLLQHandshake - putLLQ");
+               info->state = LLQ_Error;                
+               return;
+               }
+
+       err = mDNSSendDNSMessage(m, &msg, end, q->InterfaceID, &info->servAddr, info->servPort);
+       if (err) LogMsg("ERROR: startLLQHandshake - mDNSSendDNSMessage returned %d", err);
+       // on error, we procede as normal and retry after the appropriate interval
+
+       // update question/info state
+       info->state = LLQ_InitialRequest;
+       info->origLease = kLLQ_DefLease;
+    info->retry = timenow + (kLLQ_INIT_RESEND * mDNSPlatformOneSecond);
+       q->LastQTime = timenow;
+       q->uDNS_info.responseCallback = recvSetupResponse;
+       q->uDNS_info.internal = mDNStrue;
+       }
+
+// wrapper for startLLQHandshake, invoked by async op callback
+mDNSlocal void startLLQHandshakeCallback(mStatus err, mDNS *const m, void *llqInfo, const AsyncOpResult *result)
+       {
+       LLQ_Info *info = (LLQ_Info *)llqInfo;
+       const zoneData_t *zoneInfo = &result->zoneData;
+
+       if (err)
+               {
+               LogMsg("ERROR: startLLQHandshakeCallback invoked with error code %d", err);
+               info->state = LLQ_Poll;
+               info->question->LastQTime = 0;  // trigger immediate poll
+               info->question->ThisQInterval = INIT_UCAST_POLL_INTERVAL;
+               return;
+               }
+
+       if (info->state == LLQ_Cancelled)
+               {
+               // StopQuery was called while we were getting the zone info
+               LogMsg("startLLQHandshake - LLQ Cancelled.");
+               info->question = NULL;  // question may be deallocated
+               ufree(info);
+               return;
+               }
+
+       if (info->state != LLQ_GetZoneInfo)
+               {
+               LogMsg("ERROR: startLLQHandshake - bad state %d", info->state);
+               return;
+               }
+       
+    // cache necessary zone data
+       info->servAddr.type = zoneInfo->primaryAddr.type;
+       info->servAddr.ip.v4.NotAnInteger = zoneInfo->primaryAddr.ip.v4.NotAnInteger;
+       info->servPort.NotAnInteger = zoneInfo->llqPort.NotAnInteger;
+    info->ntries = 0;
+       startLLQHandshake(m, info);
+       }
+
+mDNSlocal mStatus startLLQ(mDNS *m, DNSQuestion *question)
+    {
+       LLQ_Info *info;
+       mStatus err = mStatus_NoError;
+       
+       // allocate / init info struct
+    info = umalloc(sizeof(LLQ_Info));
+    if (!info) { LogMsg("ERROR: startLLQ - malloc"); return mStatus_NoMemoryErr; }
+       ubzero(info, sizeof(LLQ_Info));
+    info->state = LLQ_GetZoneInfo;
+       
+       // link info/question
+       info->question = question;
+       question->uDNS_info.llq = info;
+
+       question->uDNS_info.responseCallback = llqResponseHndlr;
+       
+       err = startGetZoneData(&question->qname, m, mDNSfalse, mDNStrue, startLLQHandshakeCallback, info);
+    if (err)
+               {
+               LogMsg("ERROR: startLLQ - startGetZoneData returned %d", err);
+               info->question = NULL;
+               ufree(info);
+               question->uDNS_info.llq = NULL;
+               return err;
+               }
+
+       LinkActiveQuestion(&m->uDNS_info, question);
+       return err;
+       }
+
+mDNSlocal mDNSBool recvLLQResponse(mDNS *m, DNSMessage *msg, const mDNSu8 *end, const mDNSAddr *srcaddr, mDNSIPPort srcport, const mDNSInterfaceID InterfaceID)
+       {
+       DNSQuestion pktQ, *q;
+       uDNS_GlobalInfo *u = &m->uDNS_info;
+       const mDNSu8 *ptr = msg->data;
+       LLQ_Info *llqInfo;
+       
+       if (!msg->h.numQuestions) return mDNSfalse;
+
+       ptr = getQuestion(msg, ptr, end, 0, &pktQ);
+       if (!ptr) return mDNSfalse;
+       pktQ.uDNS_info.id = msg->h.id;
+       
+       // !!!KRS we should do a table lookup to quickly determine if this packet is for an LLQ
+   
+       q = u->ActiveQueries;
+       while (q)
+               {
+               llqInfo = q->uDNS_info.llq;
+               if (q->LongLived &&                          
+                       llqInfo &&
+                       q->qnamehash == pktQ.qnamehash &&        
+                       q->qtype == pktQ.qtype &&
+                       SameDomainName(&q->qname, &pktQ.qname))
+                       {
+                       u->CurrentQuery = q;
+                       if (llqInfo->state == LLQ_Established || (llqInfo->state == LLQ_Refresh && msg->h.numAnswers))                  
+                               { recvLLQEvent(m, q, msg, end, srcaddr, srcport, InterfaceID); return mDNStrue; }
+                       else if (msg->h.id.NotAnInteger != q->uDNS_info.id.NotAnInteger)
+                               { q = q->next; continue; }
+                       else if (llqInfo->state == LLQ_Refresh && msg->h.numAdditionals && !msg->h.numAnswers)
+                               { recvRefreshReply(m, msg, end, q); return mDNStrue; }
+                       else if (llqInfo->state < LLQ_Static)
+                               { q->uDNS_info.responseCallback(m, msg, end, q, q->uDNS_info.context); return mDNStrue; }                       
+                       }
+               q = q->next;
+               }
+       return mDNSfalse;
+       }
+
+mDNSexport mDNSBool IsActiveUnicastQuery(DNSQuestion *const question, uDNS_GlobalInfo *u)
+    {
+       DNSQuestion *q;
+
+       for (q = u->ActiveQueries; q; q = q->next)
+               {
+               if (q == question)
+                       {
+                       if (!question->uDNS_info.id.NotAnInteger || question->InterfaceID || IsLocalDomain(&question->qname))
+                               LogMsg("Warning: Question %s in Active Unicast Query list with id %d, interfaceID %x",
+                                          question->qname.c, question->uDNS_info.id.NotAnInteger, question->InterfaceID);
+                       return mDNStrue;
+                       }
+               }
+       return mDNSfalse;
+       }
+
+// stopLLQ happens IN ADDITION to stopQuery
+mDNSlocal void stopLLQ(mDNS *m, DNSQuestion *question)
+       {       
+       LLQ_Info *info = question->uDNS_info.llq;
+       (void)m;  // unused
+
+       if (!question->LongLived) { LogMsg("ERROR: stopLLQ - LongLived flag not set"); return; }
+       if (!info)                { LogMsg("ERROR: stopLLQ - llq info is NULL");       return; }
+
+       switch (info->state)
+               {
+               case LLQ_UnInit:
+                       LogMsg("ERROR: stopLLQ - state LLQ_UnInit");
+                       //!!!KRS should we unlink info<->question here?
+                       return;
+               case LLQ_GetZoneInfo:
+                       info->question = NULL; // remove ref to question, as it may be freed when we get called back from async op
+                       info->state = LLQ_Cancelled;
+                       return;                 
+               case LLQ_Established:
+               case LLQ_Refresh:
+                       // refresh w/ lease 0
+                       sendLLQRefresh(m, question, 0);
+                       goto free_info; 
+               default:                        
+                       debugf("stopLLQ - silently discarding LLQ in state %d", info->state);                           
+                       goto free_info;
+               }
+       
+       free_info:
+       info->question = NULL;
+       ufree(info);
+       question->uDNS_info.llq = NULL;
+       
+       }
+
+mDNSexport mStatus uDNS_StopQuery(mDNS *const m, DNSQuestion *const question)
+       {
+       uDNS_GlobalInfo *u = &m->uDNS_info;
+       DNSQuestion *qptr, *prev = NULL;
+       CacheRecord *ka;
+       
+       qptr = u->ActiveQueries;
+       while (qptr)
+        {
+        if (qptr == question)
+            {
+                       if (question->LongLived && question->uDNS_info.llq)
+                               stopLLQ(m, question);
+                       if (m->uDNS_info.CurrentQuery == question)
+                               m->uDNS_info.CurrentQuery = m->uDNS_info.CurrentQuery->next;
+                       while (question->uDNS_info.knownAnswers)
+                               {
+                               ka = question->uDNS_info.knownAnswers;
+                               question->uDNS_info.knownAnswers = question->uDNS_info.knownAnswers->next;
+                               ufree(ka);
+                               }
+                       if (prev) prev->next = question->next;
+            else u->ActiveQueries = question->next;
+                       return mStatus_NoError;
+            }
+        prev = qptr;
+               qptr = qptr->next;
+        }
+    LogMsg("uDNS_StopQuery: no such active query (%s)", question->qname.c);
+    return mStatus_UnknownErr;
+    }
+
+mDNSexport void uDNS_SuspendLLQs(mDNS *m)
+       {
+       DNSQuestion *q;
+       LLQ_Info *llq;
+       for (q = m->uDNS_info.ActiveQueries; q; q = q->next)
+               {
+               llq = q->uDNS_info.llq;
+               if (q->LongLived && llq && llq->state < LLQ_Suspended)
+                       {
+                       if (llq->state == LLQ_Established || llq->state == LLQ_Refresh)
+                               sendLLQRefresh(m, q, 0);
+                       // note that we suspend LLQs in setup states too                        
+                       if (llq->state != LLQ_Retry) llq->state = LLQ_Suspended;
+                       }
+               }
+       }
+
+extern void uDNS_RestartLLQs(mDNS *m)
+       {
+       uDNS_GlobalInfo *u = &m->uDNS_info;
+       DNSQuestion *q;
+       LLQ_Info *llqInfo;
+       
+       u->CurrentQuery = u->ActiveQueries;
+       while (u->CurrentQuery)
+               {
+               q = u->CurrentQuery;
+               u->CurrentQuery = u->CurrentQuery->next;
+               llqInfo = q->uDNS_info.llq;
+               if (q->LongLived && llqInfo && llqInfo->state == LLQ_Suspended)         
+                       { llqInfo->ntries = 0; llqInfo->deriveRemovesOnResume = mDNStrue; startLLQHandshake(m, llqInfo); }
+               }
+       }
+
+
+mDNSlocal mStatus startQuery(mDNS *const m, DNSQuestion *const question, mDNSBool internal)
+    {
+    uDNS_GlobalInfo *u = &m->uDNS_info;
+    DNSMessage msg;
+    mDNSu8 *endPtr;
+    mStatus err = mStatus_NoError;
+       const mDNSAddr *server;
+       
+    //!!!KRS we should check if the question is already in our acivequestion list
+       if (!ValidateDomainName(&question->qname))
+               {
+               LogMsg("Attempt to start query with invalid qname %##s %s", question->qname.c, DNSTypeName(question->qtype));
+               return mStatus_Invalid;
+               }
+               
+       question->next = NULL;
+       question->qnamehash = DomainNameHashValue(&question->qname);    // to do quick domain name comparisons
+    question->uDNS_info.id = newMessageID(u);
+       
+       // break here if its and LLQ
+       if (question->LongLived) return startLLQ(m, question);
+
+       err = constructQueryMsg(&msg, &endPtr, question);
+       if (err) return err;
+
+       // else send the query to our server
+
+       question->LastQTime = mDNSPlatformTimeNow();
+       question->ThisQInterval = INIT_UCAST_POLL_INTERVAL;
+    // store the question/id in active question list
+    question->uDNS_info.timestamp = question->LastQTime;
+       question->uDNS_info.internal = internal;
+       LinkActiveQuestion(u, question);
+       question->uDNS_info.knownAnswers = NULL;
+
+       server = getInitializedDNS(u);
+       if (!server) { LogMsg("startQuery - no initialized DNS"); err =  mStatus_NotInitializedErr; }
+       else err = mDNSSendDNSMessage(m, &msg, endPtr, question->InterfaceID, server, UnicastDNSPort);  
+       if (err) { LogMsg("ERROR: startQuery - %d (keeping question in list for retransmission", err); }
+
+       return err;
+       }
+       
+mDNSexport mStatus uDNS_StartQuery(mDNS *const m, DNSQuestion *const question)
+    {
+       ubzero(&question->uDNS_info, sizeof(uDNS_QuestionInfo));
+       question->uDNS_info.responseCallback = simpleResponseHndlr;
+       question->uDNS_info.context = NULL;
+       return startQuery(m, question, 0);
+    }
+
+// explicitly set response handler
+mDNSlocal mStatus startInternalQuery(DNSQuestion *q, mDNS *m, InternalResponseHndlr callback, void *hndlrContext)
+    {
+       ubzero(&q->uDNS_info, sizeof(uDNS_QuestionInfo));
+    q->QuestionContext = hndlrContext; 
+    q->uDNS_info.responseCallback = callback;
+       q->uDNS_info.context = hndlrContext;
+    return startQuery(m, q, 1);
+    }
+
+
+
+// ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark - Domain -> Name Server Conversion
+#endif
+
+
+/* startGetZoneData
+ *
+ * asyncronously find the address of the nameserver for the enclosing zone for a given domain name,
+ * i.e. the server to which update and LLQ requests will be sent for a given name.  Once the address is
+ * derived, it will be passed to the callback, along with a context pointer.  If the zone cannot
+ * be determined or if an error occurs, an all-zeros address will be passed and a message will be
+ * written to the syslog.
+ *
+ * If the FindUpdatePort arg is set, the port on which the server accepts dynamic updates is determined
+ * by querying for the _update._dns-sd._udp.<zone>. SRV record.  Likewise, if the FindLLQPort arg is set,
+ * the port on which the server accepts long lived queries is determined by querying for _llq._dns-sd.
+ * _udp.<zone>. record.  If either of these queries fail, or flags are not specified, the llqPort and
+ * updatePort fields in the result structure are set to zero.
+ *
+ *  Steps for deriving the zone name are as follows:
+ *
+ * Query for an SOA record for the required domain.  If we don't get an answer (or an SOA in the Authority
+ * section), we strip the leading label from the name and repeat, until we get an answer.
+ *
+ * The name of the SOA record is our enclosing zone.  The mname field in the SOA rdata is the domain
+ * name of the primary NS.
+ *
+ * We verify that there is an NS record with this zone for a name and the mname for its rdata.
+ * (!!!KRS this seems redundant, but BIND does this, and it should normally be zero-overhead since
+ * the NS query will get us address records in the additionals section, which we'd otherwise have to
+ * explicitly query for.)
+ *
+ * We then query for the address record for this nameserver (if it is not in the addionals section of
+ * the NS record response.)
+ */
+
+// state machine types and structs
+//
+
+// state machine states
+typedef enum
+    {
+    init,
+    lookupSOA,
+       foundZone,
+       lookupNS,
+       foundNS,
+       lookupA,
+       foundA,
+       lookupPort,
+       foundPort,
+       complete
+    } ntaState;
+
+// state machine actions
+typedef enum
+    {
+    smContinue,  // continue immediately to next state 
+    smBreak,     // break until next packet/timeout 
+       smError      // terminal error - cleanup and abort
+    } smAction;
+typedef struct
+    {
+    domainname         origName;            // name we originally try to convert
+    domainname         *curSOA;             // name we have an outstanding SOA query for
+    ntaState   state;               // determines what we do upon receiving a packet
+    mDNS           *m;
+    domainname  zone;                // left-hand-side of SOA record
+    mDNSu16     zoneClass; 
+    domainname  ns;                  // mname in SOA rdata, verified in confirmNS state
+    mDNSv4Addr  addr;                // address of nameserver
+    DNSQuestion question;            // storage for any active question
+    DNSQuestion extraQuestion;       // additional storage
+    mDNSBool    questionActive;      // if true, StopQuery() can be called on the question field
+    mDNSBool    findUpdatePort;      
+    mDNSBool    findLLQPort;
+    mDNSIPPort  updatePort;
+    mDNSIPPort  llqPort;
+    AsyncOpCallback *callback;       // caller specified function to be called upon completion
+    void        *callbackInfo;
+    } ntaContext;
+
+
+// function prototypes (for routines that must be used as fn pointers prior to their definitions,
+// and allows states to be read top-to-bottom in logical order)
+mDNSlocal void getZoneData(mDNS *const m, DNSMessage *msg, const mDNSu8 *end, DNSQuestion *question, void *contextPtr);
+mDNSlocal smAction hndlLookupSOA(DNSMessage *msg, const mDNSu8 *end, ntaContext *context);
+mDNSlocal void processSOA(ntaContext *context, ResourceRecord *rr);
+mDNSlocal smAction confirmNS(DNSMessage *msg, const mDNSu8 *end, ntaContext *context);
+mDNSlocal smAction lookupNSAddr(DNSMessage *msg, const mDNSu8 *end, ntaContext *context);
+mDNSlocal smAction hndlLookupPorts(DNSMessage *msg, const mDNSu8 *end, ntaContext *context);
+
+// initialization
+mDNSlocal mStatus startGetZoneData(domainname *name, mDNS *m, mDNSBool findUpdatePort, mDNSBool findLLQPort,
+                                                                  AsyncOpCallback callback, void *callbackInfo)
+    {
+    ntaContext *context = (ntaContext*)umalloc(sizeof(ntaContext));
+    if (!context) { LogMsg("ERROR: startGetZoneData - umalloc failed");  return mStatus_NoMemoryErr; }
+       ubzero(context, sizeof(ntaContext));
+    ustrcpy(context->origName.c, name->c);
+    context->state = init;
+    context->m = m;
+       context->callback = callback;
+       context->callbackInfo = callbackInfo;
+       context->findUpdatePort = findUpdatePort;
+       context->findLLQPort = findLLQPort;
+    getZoneData(m, NULL, NULL, NULL, context);
+    return mStatus_NoError;
+    }
+
+// state machine entry routine
+mDNSlocal void getZoneData(mDNS *const m, DNSMessage *msg, const mDNSu8 *end, DNSQuestion *question, void *contextPtr)
+    {
+       AsyncOpResult result;
+       ntaContext *context = (ntaContext*)contextPtr;
+       smAction action;
+
+    // unused
+       (void)m;
+       (void)question;
+       
+       // stop any active question
+       if (context->questionActive)
+               {
+               uDNS_StopQuery(context->m, &context->question);
+               context->questionActive = mDNSfalse;
+               }
+
+       if (msg && msg->h.flags.b[2] >> 4 && msg->h.flags.b[2] >> 4 != kDNSFlag1_RC_NXDomain)
+               {
+               // rcode non-zero, non-nxdomain
+               LogMsg("ERROR: getZoneData - received response w/ rcode %d", msg->h.flags.b[2] >> 4);
+               goto error;
+               }
+       
+       switch (context->state)
+        {
+        case init:
+        case lookupSOA:
+            action = hndlLookupSOA(msg, end, context);
+                       if (action == smError) goto error;
+                       if (action == smBreak) return;
+               case foundZone:
+               case lookupNS:
+                       action = confirmNS(msg, end, context);
+                       if (action == smError) goto error;
+                       if (action == smBreak) return;
+               case foundNS:
+               case lookupA:
+                       action = lookupNSAddr(msg, end, context);
+                       if (action == smError) goto error;
+                       if (action == smBreak) return;
+               case foundA:
+                       if (!context->findUpdatePort && !context->findLLQPort)
+                               {
+                               context->state = complete;
+                               break;
+                               }
+               case lookupPort:
+                       action = hndlLookupPorts(msg, end, context);
+                       if (action == smError) goto error;
+                       if (action == smBreak) return;
+                       if (action == smContinue) context->state = complete;
+               case foundPort:
+               case complete: break;                   
+               }
+                                         
+       if (context->state != complete)
+               {
+               LogMsg("ERROR: getZoneData - exited state machine with state %d", context->state);
+               goto error;
+               }
+       
+       result.type = zoneDataResult;
+       result.zoneData.primaryAddr.ip.v4.NotAnInteger = context->addr.NotAnInteger;
+       result.zoneData.primaryAddr.type = mDNSAddrType_IPv4;
+       ustrcpy(result.zoneData.zoneName.c, context->zone.c);
+       result.zoneData.zoneClass = context->zoneClass;
+       result.zoneData.llqPort    = context->findLLQPort    ? context->llqPort    : zeroIPPort;
+       result.zoneData.updatePort = context->findUpdatePort ? context->updatePort : zeroIPPort;
+       context->callback(mStatus_NoError, context->m, context->callbackInfo, &result);
+       goto cleanup;   
+                       
+error:
+       if (context && context->callback)
+               context->callback(mStatus_UnknownErr, context->m, context->callbackInfo, NULL); 
+cleanup:
+       if (context && context->questionActive)
+               {
+               uDNS_StopQuery(context->m, &context->question);
+               context->questionActive = mDNSfalse;
+               }               
+    if (context) ufree(context);
+       }
+
+mDNSlocal smAction hndlLookupSOA(DNSMessage *msg, const mDNSu8 *end, ntaContext *context)
+    {
+    mStatus err;
+    LargeCacheRecord lcr;
+       ResourceRecord *rr = &lcr.r.resrec;
+       DNSQuestion *query = &context->question;
+       const mDNSu8 *ptr;
+       
+    if (msg)
+        {
+        // if msg contains SOA record in answer or authority sections, update context/state and return                 
+               int i;
+               ptr = LocateAnswers(msg, end);
+               for (i = 0; i < msg->h.numAnswers; i++)
+                       {
+                       ptr = GetLargeResourceRecord(context->m, msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr);
+                       if (!ptr) { LogMsg("ERROR: hndlLookupSOA, Answers - GetLargeResourceRecord returned NULL");  return smError; }
+                       if (rr->rrtype == kDNSType_SOA && SameDomainName(context->curSOA, &rr->name))
+                               {
+                               processSOA(context, rr);
+                               return smContinue;
+                               }
+                       }               
+               ptr = LocateAuthorities(msg, end);
+               // SOA not in answers, check in authority
+               for (i = 0; i < msg->h.numAuthorities; i++)
+                       {
+                       ptr = GetLargeResourceRecord(context->m, msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr); ///!!!KRS using type PacketAns for auth
+                       if (!ptr) { LogMsg("ERROR: hndlLookupSOA, Authority - GetLargeResourceRecord returned NULL");  return smError; }                                
+                       if (rr->rrtype == kDNSType_SOA)
+                               {
+                               processSOA(context, rr);
+                               return smContinue;
+                               }
+                       }
+               }    
+
+    if (context->state != init && !context->curSOA->c[0])
+        {
+        // we've gone down to the root and have not found an SOA  
+        LogMsg("ERROR: hndlLookupSOA - recursed to root label of %s without finding SOA", 
+                context->origName.c);
+               return smError;
+        }
+
+    ubzero(query, sizeof(DNSQuestion));
+    // chop off leading label unless this is our first try
+    if (context->state == init)  context->curSOA = &context->origName;
+    else                         context->curSOA = (domainname *)(context->curSOA->c + context->curSOA->c[0]+1);
+    
+    context->state = lookupSOA;
+    ustrcpy(query->qname.c, context->curSOA->c);
+    query->qtype = kDNSType_SOA;
+    query->qclass = kDNSClass_IN;
+    err = startInternalQuery(query, context->m, getZoneData, context);
+       context->questionActive = mDNStrue;
+       if (err) LogMsg("hndlLookupSOA: startInternalQuery returned error %d (breaking until next periodic retransmission)", err);
+
+    return smBreak;     // break from state machine until we receive another packet    
+    }
+
+mDNSlocal void processSOA(ntaContext *context, ResourceRecord *rr)
+       {
+       ustrcpy(context->zone.c, rr->name.c);
+       context->zoneClass = rr->rrclass;
+       ustrcpy(context->ns.c, rr->rdata->u.soa.mname.c);
+       context->state = foundZone;
+       }
+
+
+mDNSlocal smAction confirmNS(DNSMessage *msg, const mDNSu8 *end, ntaContext *context)
+       {
+       DNSQuestion *query = &context->question;
+       mStatus err;
+       LargeCacheRecord lcr;
+       ResourceRecord *rr = &lcr.r.resrec;
+       const mDNSu8 *ptr;
+       int i;
+               
+       if (context->state == foundZone)
+               {
+               // we've just learned the zone.  confirm that an NS record exists
+               ustrcpy(query->qname.c, context->zone.c);
+               query->qtype = kDNSType_NS;
+               query->qclass = kDNSClass_IN;
+               err = startInternalQuery(query, context->m, getZoneData, context);
+               context->questionActive = mDNStrue;        
+               if (err) LogMsg("confirmNS: startInternalQuery returned error %d (breaking until next periodic retransmission", err);
+               context->state = lookupNS;
+               return smBreak;  // break from SM until we receive another packet
+               }
+       else if (context->state == lookupNS)
+               {
+               ptr = LocateAnswers(msg, end);
+               for (i = 0; i < msg->h.numAnswers; i++)
+                       {
+                       ptr = GetLargeResourceRecord(context->m, msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr);
+                       if (!ptr) { LogMsg("ERROR: confirmNS, Answers - GetLargeResourceRecord returned NULL");  return smError; }
+                       if (rr->rrtype == kDNSType_NS &&
+                               SameDomainName(&context->zone, &rr->name) && SameDomainName(&context->ns, &rr->rdata->u.name))
+                               {
+                               context->state = foundNS;
+                               return smContinue;  // next routine will examine additionals section of A record                                
+                               }                               
+                       }
+               LogMsg("ERROR: could not confirm existance of NS record %s", context->zone.c);
+               return smError;
+               }
+       else { LogMsg("ERROR: confirmNS - bad state %d", context->state); return smError; }
+       }
+
+mDNSlocal smAction queryNSAddr(ntaContext *context)
+       {
+       mStatus err;
+       DNSQuestion *query = &context->question;
+       
+       ustrcpy(query->qname.c, context->ns.c);
+       query->qtype = kDNSType_A;
+       query->qclass = kDNSClass_IN;
+       err = startInternalQuery(query, context->m, getZoneData, context);
+       context->questionActive = mDNStrue;     
+       if (err) LogMsg("confirmNS: startInternalQuery returned error %d (breaking until next periodic retransmission)", err);
+       context->state = lookupA;
+       return smBreak;
+       }
+
+mDNSlocal smAction lookupNSAddr(DNSMessage *msg, const mDNSu8 *end, ntaContext *context)
+       {
+       const mDNSu8 *ptr;
+       int i;
+       LargeCacheRecord lcr;
+       ResourceRecord *rr = &lcr.r.resrec;
+       
+       if (context->state == foundNS)
+               {
+               // we just found the NS record - look for the corresponding A record in the Additionals section
+               if (!msg->h.numAdditionals) return queryNSAddr(context);
+               ptr = LocateAdditionals(msg, end);
+               if (!ptr)
+                       {
+                       LogMsg("ERROR: lookupNSAddr - LocateAdditionals returned NULL, expected %d additionals", msg->h.numAdditionals);
+                       return queryNSAddr(context);
+                       }
+               else
+                       {
+                       for (i = 0; i < msg->h.numAdditionals; i++)
+                               {
+                               ptr = GetLargeResourceRecord(context->m, msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr);
+                               if (!ptr)
+                                       {
+                                       LogMsg("ERROR: lookupNSAddr, Additionals - GetLargeResourceRecord returned NULL");
+                                       return queryNSAddr(context);
+                                       }
+                               if (rr->rrtype == kDNSType_A && SameDomainName(&context->ns, &rr->name))
+                                       {
+                                       context->addr.NotAnInteger = rr->rdata->u.ip.NotAnInteger;
+                                       context->state = foundA;
+                                       return smContinue;
+                                       }
+                               }
+                       }
+               // no A record in Additionals - query the server
+               return queryNSAddr(context);
+               }
+       else if (context->state == lookupA)
+               {
+               ptr = LocateAnswers(msg, end);
+               if (!ptr) { LogMsg("ERROR: lookupNSAddr: LocateAnswers returned NULL");  return smError; }
+               for (i = 0; i < msg->h.numAnswers; i++)
+                       {
+                       ptr = GetLargeResourceRecord(context->m, msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr);
+                       if (!ptr) { LogMsg("ERROR: lookupNSAddr, Answers - GetLargeResourceRecord returned NULL"); break; }                     
+                       if (rr->rrtype == kDNSType_A && SameDomainName(&context->ns, &rr->name))
+                               {
+                               context->addr.NotAnInteger = rr->rdata->u.ip.NotAnInteger;
+                               context->state = foundA;
+                               return smContinue;
+                               }
+                       }               
+               LogMsg("ERROR: lookupNSAddr: Address record not found in answer section");
+               return smError;
+               }
+       else { LogMsg("ERROR: lookupNSAddr - bad state %d", context->state); return smError; }
+       }
+       
+mDNSlocal smAction lookupDNSPort(DNSMessage *msg, const mDNSu8 *end, ntaContext *context, char *portName, mDNSIPPort *port)
+       {
+       int i;
+       LargeCacheRecord lcr;
+       const mDNSu8 *ptr;
+       DNSQuestion *q;
+       mStatus err;
+       
+       if (context->state == lookupPort)  // we've already issued the query
+               {
+               if (!msg) { LogMsg("ERROR: hndlLookupUpdatePort - NULL message"); return smError; }
+               ptr = LocateAnswers(msg, end);
+               for (i = 0; i < msg->h.numAnswers; i++)
+                       {
+                       ptr = GetLargeResourceRecord(context->m, msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr);
+                       if (!ptr) { LogMsg("ERROR: hndlLookupUpdatePort - GetLargeResourceRecord returned NULL");  return smError; }
+                       if (ResourceRecordAnswersQuestion(&lcr.r.resrec, &context->question))
+                               {
+                               port->NotAnInteger = lcr.r.resrec.rdata->u.srv.port.NotAnInteger;
+                               context->state = foundPort;
+                               return smContinue;
+                               }
+                       }
+               LogMsg("hndlLookupUpdatePort %s - answer not contained in reply.  Guessing port %d", portName, UnicastDNSPort);
+               *port = UnicastDNSPort;
+               context->state = foundPort;
+               return smContinue;
+               }
+
+       // query the server for the update port for the zone
+       context->state = lookupPort;
+       q = &context->question;
+       MakeDomainNameFromDNSNameString(&q->qname, portName);
+       ustrcpy((q->qname.c + ustrlen(q->qname.c)), context->zone.c);
+    q->qtype = kDNSType_SRV;
+    q->qclass = kDNSClass_IN;
+    err = startInternalQuery(q, context->m, getZoneData, context);
+       context->questionActive = mDNStrue;
+    if (err) LogMsg("hndlLookupSOA: startInternalQuery returned error %d (breaking until next periodic retransmission)", err);
+    return smBreak;     // break from state machine until we receive another packet    
+       }
+
+mDNSlocal smAction hndlLookupPorts(DNSMessage *msg, const mDNSu8 *end, ntaContext *context)
+       {
+       smAction action;
+       
+       if (context->findUpdatePort && !context->updatePort.NotAnInteger)
+               {
+               action = lookupDNSPort(msg, end, context, UPDATE_PORT_NAME, &context->updatePort);
+               if (action != smContinue) return action;
+               }
+       if (context->findLLQPort && !context->llqPort.NotAnInteger)
+               return lookupDNSPort(msg, end, context, LLQ_PORT_NAME, &context->llqPort);
+
+       return smContinue;
+       }
+
+
+// ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark - Truncation Handling
+#endif
+
+typedef struct
+       {
+    DNSQuestion  *question;
+    DNSMessage reply;
+    mDNSu16  replylen;
+    int nread;
+    mDNS *m;
+       } tcpInfo_t;
+
+// issue queries over a conected socket
+mDNSlocal void conQueryCallback(int sd, void *context, mDNSBool ConnectionEstablished)
+       {
+       mStatus err = 0;
+       char msgbuf[356];  // 96 (hdr) + 256 (domain) + 4 (class/type)
+       DNSMessage *msg;
+       mDNSu8 *end;
+       tcpInfo_t *info = (tcpInfo_t *)context;
+       DNSQuestion *question = info->question;
+       int n;
+
+       question->uDNS_info.id.NotAnInteger = (mDNSu16)~0;
+
+       if (ConnectionEstablished)
+               {
+               // connection is established - send the message
+               msg = (DNSMessage *)&msgbuf;
+               err = constructQueryMsg(msg, &end, question);
+               if (err) { LogMsg("ERROR: conQueryCallback: constructQueryMsg - %d", err);  goto error; }
+               err = mDNSSendDNSMessage_tcp(info->m, msg, end, sd);
+               if (err) { LogMsg("ERROR: conQueryCallback: mDNSSendDNSMessage_tcp - %d", err);  goto error; }
+               return;
+               }
+       else
+               {
+               if (!info->nread)
+                       {
+                       // read msg len
+                       n = mDNSPlatformReadTCP(sd, &info->replylen, 2);
+                       if (n != 2)
+                               {
+                               LogMsg("ERROR:conQueryCallback - attempt to read message length failed (read returned %d)", n);
+                               goto error;
+                               }
+                       }
+               n = mDNSPlatformReadTCP(sd, ((char *)&info->reply) + info->nread, info->replylen - info->nread);
+               if (n < 0) { LogMsg("ERROR: conQueryCallback - read returned %d", n); goto error; }
+               info->nread += n;
+               if (info->nread == info->replylen)
+                       {
+                       // finished reading message
+                       receiveMsg(info->m, &info->reply, ((mDNSu8 *)&info->reply) + info->replylen, question->InterfaceID);
+                       mDNSPlatformTCPCloseConnection(sd);
+                       ufree(info);
+                       return;
+                       }
+               else return;
+               }
+       return;
+
+       error:
+       mDNSPlatformTCPCloseConnection(sd);
+       ufree(info);
+       }
+
+mDNSlocal void hndlTruncatedAnswer(DNSQuestion *question, const  mDNSAddr *src, mDNS *m)
+       {
+       mStatus connectionStatus;
+       uDNS_QuestionInfo *info = &question->uDNS_info;
+       int sd;
+       tcpInfo_t *context;
+
+       context = (tcpInfo_t *)umalloc(sizeof(tcpInfo_t));
+       if (!context) { LogMsg("ERROR: hndlTruncatedAnswer - memallocate failed"); return; }
+       ubzero(context, sizeof(tcpInfo_t));
+       context->question = question;
+       context->m = m;
+
+       info->id.NotAnInteger = (mDNSu16)~0;             // all 1's indicates TCP queries
+       info->timestamp = mDNSPlatformTimeNow();         // reset timestamp
+
+       connectionStatus = mDNSPlatformTCPConnect(src, UnicastDNSPort, question->InterfaceID, conQueryCallback, context, &sd);
+       if (connectionStatus == mStatus_ConnectionEstablished)  // manually invoke callback if connection completes
+               {
+               conQueryCallback(sd, context, mDNStrue);
+               return;
+               }
+       if (connectionStatus == mStatus_ConnectionPending) return; // callback will be automatically invoked when connection completes
+       LogMsg("hndlTruncatedAnswer: connection failed");
+       uDNS_StopQuery(m, question);  //!!!KRS can we really call this here?
+       }
+
+
+// ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark - Dynamic Updates
+#endif
+
+
+mDNSlocal mDNSu8 *putZone(DNSMessage *const msg, mDNSu8 *ptr, mDNSu8 *limit, const domainname *zone, mDNSOpaque16 zoneClass)
+       {
+       ptr = putDomainNameAsLabels(msg, ptr, limit, zone);
+       if (!ptr || ptr + 4 > limit) return NULL;               // If we're out-of-space, return NULL
+       ((mDNSOpaque16 *)ptr)->NotAnInteger = kDNSType_SOA;
+       ptr += 2;
+       ((mDNSOpaque16 *)ptr)->NotAnInteger = zoneClass.NotAnInteger;
+       ptr += 2;
+       msg->h.mDNS_numZones++;
+       return ptr;
+       }
+
+
+
+mDNSlocal mDNSu8 *putPrereqNameNotInUse(domainname *name, DNSMessage *msg, mDNSu8 *ptr, mDNSu8 *end)
+       {
+       AuthRecord prereq;
+
+       ubzero(&prereq, sizeof(AuthRecord));
+       ustrcpy(prereq.resrec.name.c, name->c);
+       prereq.resrec.rrtype = kDNSQType_ANY;
+       prereq.resrec.rrclass = kDNSClass_NONE;
+       ptr = putEmptyResourceRecord(msg, ptr, end, &msg->h.mDNS_numPrereqs, &prereq);
+       return ptr;
+       }
+
+mDNSlocal mDNSu8 *putDeletionRecord(DNSMessage *msg, mDNSu8 *ptr, ResourceRecord *rr)
+       {
+       mDNSu16 origclass;
+       // deletion: specify record w/ TTL 0, class NONE
+
+       origclass = rr->rrclass;
+       rr->rrclass = kDNSClass_NONE;
+       ptr = PutResourceRecordTTL(msg, ptr, &msg->h.mDNS_numUpdates, rr, 0);
+       rr->rrclass = origclass;
+       return ptr;
+       }
+
+mDNSlocal mDNSu8 *putUpdateLease(DNSMessage *msg, mDNSu8 *end)
+       {
+       AuthRecord rr;
+       ResourceRecord *opt = &rr.resrec; 
+       rdataOpt *optRD;
+
+       ubzero(&rr, sizeof(AuthRecord));
+       opt->rdata = &rr.rdatastorage;
+       
+       opt->RecordType = kDNSRecordTypeKnownUnique;  // to avoid warnings in other layers
+       opt->rrtype = kDNSType_OPT;
+       opt->rdlength = LEASE_OPT_SIZE;
+       opt->rdestimate = LEASE_OPT_SIZE;
+
+       optRD = &rr.resrec.rdata->u.opt;
+       optRD->opt = kDNSOpt_Lease;
+       optRD->optlen = sizeof(mDNSs32);
+       optRD->OptData.lease = kUpdate_DefLease;
+       end = PutResourceRecordTTL(msg, end, &msg->h.numAdditionals, opt, 0);
+       if (!end) { LogMsg("ERROR: putUpdateLease - PutResourceRecordTTL"); return NULL; }
+
+       return end;
+
+       }
+
+mDNSlocal void sendRecordRegistration(mDNS *const m, AuthRecord *rr)
+       {
+       DNSMessage msg;
+       mDNSu8 *ptr = msg.data;
+       mDNSu8 *end = (mDNSu8 *)&msg + sizeof(DNSMessage);
+       uDNS_GlobalInfo *u = &m->uDNS_info;
+       mDNSOpaque16 id;
+       uDNS_AuthInfo *authInfo;
+       uDNS_RegInfo *regInfo = &rr->uDNS_info;
+       mStatus err = mStatus_UnknownErr;
+
+       id = newMessageID(u);
+       InitializeDNSMessage(&msg.h, id, UpdateReqFlags);
+       rr->uDNS_info.id.NotAnInteger = id.NotAnInteger;
+       
+    // set zone
+       ptr = putZone(&msg, ptr, end, &regInfo->zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass));
+       if (!ptr) goto error;
+       
+       if (rr->resrec.RecordType == kDNSRecordTypeKnownUnique || rr->uDNS_info.state == regState_Refresh)
+               {
+               // KnownUnique means the record must ALREADY exist, as does refresh
+               // prereq: record must exist (put record in prereq section w/ TTL 0)
+               ptr = PutResourceRecordTTL(&msg, ptr, &msg.h.mDNS_numPrereqs, &rr->resrec, 0);
+               if (!ptr) goto error;
+               }
+       else if (rr->resrec.RecordType != kDNSRecordTypeShared)
+               {
+               ptr = putPrereqNameNotInUse(&rr->resrec.name, &msg, ptr, end);
+               if (!ptr) goto error;
+               }
+
+       ptr = PutResourceRecord(&msg, ptr, &msg.h.mDNS_numUpdates, &rr->resrec);
+       if (!ptr) goto error;
+
+       if (rr->uDNS_info.lease)
+               ptr = putUpdateLease(&msg, ptr);
+          
+       rr->uDNS_info.expire = -1;
+       
+       authInfo = GetAuthInfoForZone(u, &regInfo->zone);
+       if (authInfo)
+               {
+               err = mDNSSendSignedDNSMessage(m, &msg, ptr, 0, &regInfo->ns, regInfo->port, authInfo);
+               if (err) { LogMsg("ERROR: sendRecordRegistration - mDNSSendSignedDNSMessage - %d", err); goto error; }
+               }
+       else
+               {
+               err = mDNSSendDNSMessage(m, &msg, ptr, 0, &regInfo->ns, regInfo->port);
+               if (err) { LogMsg("ERROR: sendRecordRegistration - mDNSSendDNSMessage - %d", err); goto error; }
+               }
+
+       if (regInfo->state != regState_Refresh) regInfo->state = regState_Pending;
+       return;
+
+error:
+       if (rr->uDNS_info.state != regState_Unregistered)
+               {
+               unlinkAR(&u->RecordRegistrations, rr);
+               rr->uDNS_info.state = regState_Unregistered;
+               }
+       rr->RecordCallback(m, rr, err);
+       // NOTE: not safe to touch any client structures here   
+       }
+
+mDNSlocal void RecordRegistrationCallback(mStatus err, mDNS *const m, void *authPtr, const AsyncOpResult *result)      
+       {
+       AuthRecord *newRR = (AuthRecord*)authPtr;
+       const zoneData_t *zoneData = &result->zoneData;
+       uDNS_GlobalInfo *u = &m->uDNS_info;
+       AuthRecord *ptr;
+
+       for (ptr = u->RecordRegistrations; ptr; ptr = ptr->next)
+               if (ptr == newRR) break;
+       if (!ptr) { LogMsg("RecordRegistrationCallback - RR no longer in list.  Discarding."); return; }                
+       
+       if (err) { LogMsg("RecordRegistrationCallback: error %d", err); goto error; }
+       if (newRR->uDNS_info.state == regState_Cancelled)
+               {
+               //!!!KRS we should send a memfree callback here!
+               LogMsg("Registration of %s type %d cancelled prior to update",
+                          newRR->resrec.name.c, newRR->resrec.rrtype);
+               newRR->uDNS_info.state = regState_Unregistered;
+               unlinkAR(&u->RecordRegistrations, newRR);
+               return;
+               }
+       
+       if (result->type != zoneDataResult)
+               {
+               LogMsg("ERROR: buildUpdatePacket passed incorrect result type %d", result->type);
+               goto error;
+               }
+
+       if (newRR->resrec.rrclass != zoneData->zoneClass)
+               {
+               LogMsg("ERROR: New resource record's class (%d) does not match zone class (%d)",
+                          newRR->resrec.rrclass, zoneData->zoneClass);
+               goto error;
+               }       
+       
+       // cache zone data
+       ustrcpy(newRR->uDNS_info.zone.c, zoneData->zoneName.c);
+    newRR->uDNS_info.ns.type = mDNSAddrType_IPv4;
+       newRR->uDNS_info.ns.ip.v4.NotAnInteger = zoneData->primaryAddr.ip.v4.NotAnInteger;
+       newRR->uDNS_info.port.NotAnInteger = zoneData->updatePort.NotAnInteger;
+
+       sendRecordRegistration(m, newRR);
+       return;
+               
+error:
+       if (newRR->uDNS_info.state != regState_Unregistered)
+               {
+               unlinkAR(&u->RecordRegistrations, newRR);
+               newRR->uDNS_info.state = regState_Unregistered;
+               }
+       newRR->RecordCallback(m, newRR, err);
+       // NOTE: not safe to touch any client structures here
+       }
+
+
+mDNSlocal mDNSBool setHostTarget(AuthRecord *rr, mDNS *m)
+       {
+       domainname *target;
+
+       if (!rr->HostTarget)
+       {
+       debugf("Service %s - not updating host target", rr->resrec.name.c);
+       return mDNSfalse;
+       }
+
+    // set SRV target
+       target = GetRRDomainNameTarget(&rr->resrec);
+       if (!target)
+               {
+               LogMsg("ERROR: setHostTarget: Can't set target of rrtype %d", rr->resrec.rrtype);
+               return mDNSfalse;
+               }
+
+       if (SameDomainName(target, &m->uDNS_info.hostname))
+               {
+               debugf("Host target for %s unchanged", rr->resrec.name.c);
+               return mDNSfalse;
+               }
+       AssignDomainName(*target, m->uDNS_info.hostname);
+       SetNewRData(&rr->resrec, NULL, 0);
+       return mDNStrue;
+       }
+
+mDNSlocal void SendServiceRegistration(mDNS *m, ServiceRecordSet *srs)
+       {
+       DNSMessage msg;
+       mDNSu8 *ptr = msg.data;
+       mDNSu8 *end = (mDNSu8 *)&msg + sizeof(DNSMessage);
+       uDNS_GlobalInfo *u = &m->uDNS_info;
+       mDNSOpaque16 id;
+       uDNS_AuthInfo *authInfo;
+       uDNS_RegInfo *rInfo = &srs->uDNS_info;
+       mStatus err = mStatus_UnknownErr;
+       
+       id = newMessageID(u);
+       InitializeDNSMessage(&msg.h, id, UpdateReqFlags);
+       rInfo->id.NotAnInteger = id.NotAnInteger;
+
+       // setup resource records
+       if (setHostTarget(&srs->RR_SRV, m))
+               SetNewRData(&srs->RR_SRV.resrec, NULL, 0);  // set rdlen/estimate/hash
+       
+       //SetNewRData(&srs->RR_ADV.resrec, NULL, 0); //!!!KRS
+       SetNewRData(&srs->RR_PTR.resrec, NULL, 0);      
+       SetNewRData(&srs->RR_TXT.resrec, NULL, 0);
+       
+       // construct update packet
+    // set zone
+       ptr = putZone(&msg, ptr, end, &rInfo->zone, mDNSOpaque16fromIntVal(srs->RR_SRV.resrec.rrclass));
+       if (!ptr) goto error;
+
+       if (srs->uDNS_info.state == regState_Refresh)
+               {
+               // prereq: record must exist (put record in prereq section w/ TTL 0)
+               ptr = PutResourceRecordTTL(&msg, ptr, &msg.h.mDNS_numPrereqs, &srs->RR_SRV.resrec, 0);
+               if (!ptr) goto error;
+               }
+       else
+               {
+               // use SRV for prereq
+               ptr = putPrereqNameNotInUse(&srs->RR_SRV.resrec.name, &msg, ptr, end);
+               if (!ptr) goto error;
+               }
+
+       //!!!KRS  Need to do bounds checking and use TCP if it won't fit!!!
+       //if (!(ptr = PutResourceRecord(&msg, ptr, &msg.h.mDNS_numUpdates, &srs->RR_ADV.resrec))) goto error;
+       if (!(ptr = PutResourceRecord(&msg, ptr, &msg.h.mDNS_numUpdates, &srs->RR_PTR.resrec))) goto error;
+       if (!(ptr = PutResourceRecord(&msg, ptr, &msg.h.mDNS_numUpdates, &srs->RR_SRV.resrec))) goto error;
+       if (!(ptr = PutResourceRecord(&msg, ptr, &msg.h.mDNS_numUpdates, &srs->RR_TXT.resrec))) goto error;
+    // !!!KRS do subtypes/extras etc.
+
+       if (srs->uDNS_info.lease)
+               ptr = putUpdateLease(&msg, ptr);
+          
+       srs->uDNS_info.expire = -1;
+
+       authInfo = GetAuthInfoForZone(u, &rInfo->zone);
+       if (authInfo)
+               {
+               err = mDNSSendSignedDNSMessage(m, &msg, ptr, 0, &rInfo->ns, rInfo->port, authInfo);
+               if (err) { LogMsg("ERROR: SendServiceRegistration - mDNSSendSignedDNSMessage - %d", err); goto error; }
+               }
+       else
+               {
+               err = mDNSSendDNSMessage(m, &msg, ptr, 0, &rInfo->ns, rInfo->port);
+               if (err) { LogMsg("ERROR: SendServiceRegistration - mDNSSendDNSMessage - %d", err); goto error; }
+               }
+       if (rInfo->state != regState_Refresh)
+               rInfo->state = regState_Pending;
+       return;
+
+error:
+       unlinkSRS(u, srs);
+       rInfo->state = regState_Unregistered;
+       srs->ServiceCallback(m, srs, err);
+       //!!!KRS will mem still be free'd on error?
+       // NOTE: not safe to touch any client structures here   
+       }
+
+mDNSlocal void serviceRegistrationCallback(mStatus err, mDNS *const m, void *srsPtr, const AsyncOpResult *result)
+       {
+       ServiceRecordSet *srs = (ServiceRecordSet *)srsPtr;
+       const zoneData_t *zoneData = &result->zoneData;
+       uDNS_GlobalInfo *u = &m->uDNS_info;
+       
+       if (err) goto error;
+       if (result->type != zoneDataResult)
+               {
+               LogMsg("ERROR: buildUpdatePacket passed incorrect result type %d", result->type);
+               goto error;
+               }
+
+       if (srs->uDNS_info.state == regState_Cancelled)
+               {
+               // client cancelled registration while fetching zone data
+               srs->uDNS_info.state = regState_Unregistered;
+               unlinkSRS(u, srs);
+               srs->ServiceCallback(m, srs, mStatus_MemFree);
+               return;
+               }
+
+       if (srs->RR_SRV.resrec.rrclass != zoneData->zoneClass)
+               {
+               LogMsg("Service %s - class does not match zone", srs->RR_SRV.resrec.name.c);
+               goto error;
+               }
+       // cache zone data
+       ustrcpy(srs->uDNS_info.zone.c, zoneData->zoneName.c);
+    srs->uDNS_info.ns.type = mDNSAddrType_IPv4;
+       srs->uDNS_info.ns.ip.v4.NotAnInteger = zoneData->primaryAddr.ip.v4.NotAnInteger;
+       srs->uDNS_info.port.NotAnInteger = zoneData->updatePort.NotAnInteger;
+
+       SendServiceRegistration(m, srs);
+       return;
+               
+error:
+       unlinkSRS(u, srs);
+       srs->uDNS_info.state = regState_Unregistered;
+       srs->ServiceCallback(m, srs, err);
+       //!!!KRS will mem still be free'd on error?
+       // NOTE: not safe to touch any client structures here
+       }
+
+mDNSexport void uDNS_UpdateServiceTargets(mDNS *const m)
+       {
+       DNSMessage msg;
+       mDNSu8 *ptr = msg.data;
+       mDNSu8 *end = (mDNSu8 *)&msg + sizeof(DNSMessage);
+       uDNS_GlobalInfo *u = &m->uDNS_info;
+       ServiceRecordSet *srs;
+       AuthRecord *rr;
+       mStatus err = mStatus_NoError;
+       
+       if (!m->uDNS_info.hostname.c[0])
+               {
+               LogMsg("ERROR: uDNS_UpdateServiceTargets called before registration of hostname");
+               return;
+               //!!!KRS need to handle this case properly!
+               }
+       
+       for (srs = u->ServiceRegistrations; srs; srs = srs->next)
+               {
+               if (err) srs = u->ServiceRegistrations;
+                   // start again from beginning of list, since it may have changed
+                   // (setHostTarget() will skip records already updated)
+               rr = &srs->RR_SRV;
+               if (srs->uDNS_info.state != regState_Registered)
+                       {
+                       LogMsg("ERROR: uDNS_UpdateServiceTargets - service %s not registered", rr->resrec.name.c);
+                       continue;
+                       //!!!KRS need to handle this
+                       }
+               InitializeDNSMessage(&msg.h, srs->uDNS_info.id, UpdateReqFlags);
+               
+               // construct update packet
+               ptr = putZone(&msg, ptr, end, &srs->uDNS_info.zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass));
+               if (ptr) ptr = putDeletionRecord(&msg, ptr, &rr->resrec);  // delete the old target
+               // update the target
+               if (!setHostTarget(rr, m)) continue;
+               if (ptr) ptr = PutResourceRecord(&msg, ptr, &msg.h.mDNS_numUpdates, &rr->resrec);  // put the new target
+               // !!!KRS do subtypes/extras etc.
+               if (!ptr) err = mStatus_UnknownErr;
+               else err = mDNSSendDNSMessage(m, &msg, ptr, 0, &srs->uDNS_info.ns, srs->uDNS_info.port);
+               if (err)                        
+                       {
+                       LogMsg("ERROR: uDNS_UpdateServiceTargets - %s", ptr ? "mDNSSendDNSMessage" : "message formatting error");
+                       unlinkSRS(u, srs);
+                       srs->uDNS_info.state = regState_Unregistered;
+                       srs->ServiceCallback(m, srs, err);
+                       //!!!KRS will mem still be free'd on error?
+                       // NOTE: not safe to touch any client structures here           
+                       }
+               else srs->uDNS_info.state = regState_TargetChange;
+          }
+}                      
+
+
+mDNSexport mStatus uDNS_RegisterRecord(mDNS *const m, AuthRecord *const rr)
+       {
+       domainname *target = GetRRDomainNameTarget(&rr->resrec);
+       
+       if (rr->uDNS_info.state == regState_FetchingZoneData ||
+               rr->uDNS_info.state == regState_Pending ||
+               rr->uDNS_info.state ==  regState_Registered)
+               {
+               LogMsg("Requested double-registration of physical record %s type %s",
+                          rr->resrec.name.c, rr->resrec.rrtype);
+               return mStatus_AlreadyRegistered;
+               }
+       
+       rr->resrec.rdlength   = GetRDLength(&rr->resrec, mDNSfalse);
+       rr->resrec.rdestimate = GetRDLength(&rr->resrec, mDNStrue);
+
+       if (!ValidateDomainName(&rr->resrec.name))
+               {
+               LogMsg("Attempt to register record with invalid name: %s", GetRRDisplayString(m, rr));
+               return mStatus_Invalid;
+               }
+
+       // Don't do this until *after* we've set rr->resrec.rdlength
+       if (!ValidateRData(rr->resrec.rrtype, rr->resrec.rdlength, rr->resrec.rdata))
+               { LogMsg("Attempt to register record with invalid rdata: %s", GetRRDisplayString(m, rr));
+               return mStatus_Invalid;
+               }
+
+       rr->resrec.namehash   = DomainNameHashValue(&rr->resrec.name);
+       rr->resrec.rdatahash  = RDataHashValue(rr->resrec.rdlength, &rr->resrec.rdata->u);
+       rr->resrec.rdnamehash = target ? DomainNameHashValue(target) : 0;
+
+       rr->uDNS_info.state = regState_FetchingZoneData;
+       rr->next = m->uDNS_info.RecordRegistrations;
+       m->uDNS_info.RecordRegistrations = rr;
+
+       rr->uDNS_info.lease = mDNStrue;
+       return startGetZoneData(&rr->resrec.name, m, mDNStrue, mDNSfalse, RecordRegistrationCallback, rr);
+       }
+
+
+
+mDNSexport mStatus uDNS_DeregisterRecord(mDNS *const m, AuthRecord *const rr)
+       {
+       uDNS_GlobalInfo *u = &m->uDNS_info;
+       DNSMessage msg;
+       mDNSu8 *ptr = msg.data;
+       mDNSu8 *end = (mDNSu8 *)&msg + sizeof(DNSMessage);
+       mStatus err;
+       uDNS_AuthInfo *authInfo;
+       switch (rr->uDNS_info.state)
+               {
+               case regState_FetchingZoneData:
+                       rr->uDNS_info.state = regState_Cancelled;
+                       return mStatus_NoError;
+               case regState_Pending:
+                       rr->uDNS_info.state = regState_DeregDeferred;
+                       debugf("Deferring deregistration of record %s until registration completes", rr->resrec.name.c);
+                       return mStatus_NoError;
+               case regState_Registered:                       
+                       break;
+               case regState_DeregPending:
+               case regState_Cancelled:
+                       LogMsg("Double deregistration of record %s type %d",
+                                  rr->resrec.name.c, rr->resrec.rrtype);
+                       return mStatus_UnknownErr;
+               case regState_Unregistered:
+                       LogMsg("Requested deregistration of unregistered record %s type %d",
+                                  rr->resrec.name.c, rr->resrec.rrtype);
+                       return mStatus_UnknownErr;
+               default:
+                       LogMsg("ERROR: uDNS_DeregisterRecord called for record %s type %d with unknown state %d", 
+                                  rr->resrec.name.c, rr->resrec.rrtype, rr->uDNS_info.state);
+                       return mStatus_UnknownErr;
+               }
+               
+       InitializeDNSMessage(&msg.h, rr->uDNS_info.id, UpdateReqFlags);
+
+       // put zone
+       ptr = putZone(&msg, ptr, end, &rr->uDNS_info.zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass));
+       if (!ptr) goto error;
+
+       if (!(ptr = putDeletionRecord(&msg, ptr, &rr->resrec))) goto error;
+
+       authInfo = GetAuthInfoForZone(u, &rr->uDNS_info.zone);
+       if (authInfo)
+               {
+               err = mDNSSendSignedDNSMessage(m, &msg, ptr, 0, &rr->uDNS_info.ns, rr->uDNS_info.port, authInfo);
+               if (err) { LogMsg("ERROR: uDNS_DeregiserRecord - mDNSSendSignedDNSMessage - %d", err); goto error; }
+               }
+       else
+               {
+               err = mDNSSendDNSMessage(m, &msg, ptr, 0, &rr->uDNS_info.ns, rr->uDNS_info.port);
+               if (err) { LogMsg("ERROR: uDNS_DeregisterRecord - mDNSSendDNSMessage - %d", err); goto error; }
+               }
+       
+       return mStatus_NoError;
+
+       error:
+       if (rr->uDNS_info.state != regState_Unregistered)
+               {
+               unlinkAR(&u->RecordRegistrations, rr);
+               rr->uDNS_info.state = regState_Unregistered;
+               }
+       return mStatus_UnknownErr;
+       }
+
+
+mDNSexport mStatus uDNS_RegisterService(mDNS *const m, ServiceRecordSet *srs)
+       {
+       if (!*m->uDNS_info.NameRegDomain)
+               {
+               LogMsg("ERROR: uDNS_RegisterService - cannot register unicast service "
+                          "without setting the NameRegDomain via mDNSResponder.conf");
+               srs->uDNS_info.state = regState_Unregistered;
+               return mStatus_UnknownErr;
+               }
+       
+       srs->RR_SRV.resrec.rroriginalttl = 3;
+       srs->RR_TXT.resrec.rroriginalttl = 3;
+       srs->RR_PTR.resrec.rroriginalttl = 3;
+       
+       // set state and link into list
+       srs->uDNS_info.state = regState_FetchingZoneData;
+       srs->next = m->uDNS_info.ServiceRegistrations;
+       m->uDNS_info.ServiceRegistrations = srs;
+       srs->uDNS_info.lease = mDNStrue;
+       
+       return startGetZoneData(&srs->RR_SRV.resrec.name, m, mDNStrue, mDNSfalse, serviceRegistrationCallback, srs);
+       }
+
+mDNSexport mStatus uDNS_DeregisterService(mDNS *const m, ServiceRecordSet *srs)
+       {
+       uDNS_GlobalInfo *u = &m->uDNS_info;
+       DNSMessage msg;
+       mDNSu8 *ptr = msg.data;
+       mDNSu8 *end = (mDNSu8 *)&msg + sizeof(DNSMessage);
+       mStatus err = mStatus_UnknownErr;
+       uDNS_AuthInfo *authInfo;
+       
+       //!!!KRS make sure we're doing the right thing w/ memfree
+       
+       switch (srs->uDNS_info.state)
+               {
+               case regState_Unregistered:
+                       LogMsg("ERROR: uDNS_DeregisterService - service not registerd");
+                       return mStatus_UnknownErr;
+               case regState_FetchingZoneData:
+               case regState_Pending:
+                       // let the async op complete, then terminate
+                       srs->uDNS_info.state = regState_Cancelled;
+                       return mStatus_NoError;  // deliver memfree upon completion of async op
+               case regState_DeregPending:
+               case regState_DeregDeferred:
+               case regState_Cancelled:
+                       LogMsg("uDNS_DeregisterService - deregistration in process");
+                       return mStatus_UnknownErr;
+               }
+
+       srs->uDNS_info.state = regState_DeregPending;
+       InitializeDNSMessage(&msg.h, srs->uDNS_info.id, UpdateReqFlags);
+
+    // put zone
+       ptr = putZone(&msg, ptr, end, &srs->uDNS_info.zone, mDNSOpaque16fromIntVal(srs->RR_SRV.resrec.rrclass));
+       if (!ptr) { LogMsg("ERROR: uDNS_DeregisterService - putZone"); goto error; }
+       
+    // prereq: record must exist (put record in prereq section w/ TTL 0)
+       ptr = PutResourceRecordTTL(&msg, ptr, &msg.h.mDNS_numPrereqs, &srs->RR_SRV.resrec, 0);
+       if (!ptr) { LogMsg("ERROR: uDNS_DeregisterService - PutResourceRecordTTL"); goto error; }
+
+       if (!(ptr = putDeletionRecord(&msg, ptr, &srs->RR_SRV.resrec))) goto error;
+       if (!(ptr = putDeletionRecord(&msg, ptr, &srs->RR_TXT.resrec))) goto error;
+       if (!(ptr = putDeletionRecord(&msg, ptr, &srs->RR_PTR.resrec))) goto error;
+       //if (!(ptr = putDeletionRecord(&msg, ptr, &srs->RR_ADV.resrec))) goto error;
+       //!!!KRS  need to handle extras/subtypes etc
+
+
+       authInfo = GetAuthInfoForZone(u, &srs->uDNS_info.zone);
+       if (authInfo)
+               {
+               err = mDNSSendSignedDNSMessage(m, &msg, ptr, 0, &srs->uDNS_info.ns, srs->uDNS_info.port, authInfo);
+               if (err) { LogMsg("ERROR: uDNS_DeregiserService - mDNSSendSignedDNSMessage - %d", err); goto error; }
+               }
+       else
+               {
+               err = mDNSSendDNSMessage(m, &msg, ptr, 0, &srs->uDNS_info.ns, srs->uDNS_info.port);
+               if (err) { LogMsg("ERROR: uDNS_DeregisterService - mDNSSendDNSMessage - %d", err); goto error; }
+               }
+       
+       return mStatus_NoError;
+
+       error:
+       unlinkSRS(u, srs);
+       srs->uDNS_info.state = regState_Unregistered;
+       return err;
+       }
+
+mDNSexport void uDNS_Execute(mDNS *const m)
+       {
+       DNSQuestion *q;
+       DNSMessage msg;
+       mStatus err;
+       mDNSu8 *end;
+       mDNSs32 sendtime;
+       LLQ_Info *llq;
+       AuthRecord *rr;
+       ServiceRecordSet *srs;
+       uDNS_RegInfo *rInfo;    
+       uDNS_GlobalInfo *u = &m->uDNS_info;
+       const mDNSAddr *server = getInitializedDNS(&m->uDNS_info);
+       mDNSs32 timenow = mDNSPlatformTimeNow();
+       
+       u->nextevent = timenow + 0x78000000;
+       if (!server) { debugf("uDNS_Execute - no DNS server"); return; }        
+       
+       for (q = u->ActiveQueries; q; q = q->next)
+               {
+               llq = q->uDNS_info.llq;
+               if (q->LongLived && llq->state != LLQ_Poll)
+                       {
+                       if (llq->state >= LLQ_InitialRequest && llq->state <= LLQ_Suspended && llq->retry <= timenow)                           
+                               {
+
+                               // sanity check to avoid packet flood bugs
+                               if (!llq->retry) 
+                                       LogMsg("ERROR: retry timer not set for LLQ %s in state %d", q->qname.c, llq->state);
+                               else if (llq->state == LLQ_Established || llq->state == LLQ_Refresh)
+                                       sendLLQRefresh(m, q, llq->origLease);
+                               else if (llq->state == LLQ_InitialRequest) 
+                                       startLLQHandshake(m, llq);
+                               else if (llq->state == LLQ_SecondaryRequest)
+                                       sendChallengeResponse(m, q, NULL);
+                               else if (llq->state == LLQ_Retry) 
+                                       { llq->ntries = 0; startLLQHandshake(m, llq); }                 
+                               }
+                       }
+               else
+                       {
+                       sendtime = q->LastQTime + q->ThisQInterval;
+                       if (sendtime <= timenow)
+                               {
+                               err = constructQueryMsg(&msg, &end, q);
+                               if (err)
+                                       {
+                                       LogMsg("Error: uDNS_Idle - constructQueryMsg.  Skipping question %s",
+                                                  q->qname.c);
+                                       continue;
+                                       }
+                               err = mDNSSendDNSMessage(m, &msg, end, q->InterfaceID, server, UnicastDNSPort);
+                               if (err) { debugf("ERROR: uDNS_idle - mDNSSendDNSMessage - %d", err); } // surpress syslog messages if we have no network
+                               q->LastQTime = timenow;
+                               if (q->ThisQInterval < MAX_UCAST_POLL_INTERVAL) q->ThisQInterval = q->ThisQInterval * 2;
+                               }
+                       else if (u->nextevent - sendtime > 0) u->nextevent = sendtime;
+                       }
+               }
+
+       //!!!KRS list should be pre-sorted by expiration
+       for (rr = u->RecordRegistrations; rr; rr = rr->next)
+               {
+               rInfo = &rr->uDNS_info;         
+               if (rInfo->lease && rInfo->state == regState_Registered && rInfo->expire > 0)
+                   {               
+                   if (rInfo->expire < timenow)
+                       {
+                       debugf("refreshing record %s", rr->resrec.name.c);
+                       rInfo->state = regState_Refresh;
+                       sendRecordRegistration(m, rr);
+                       }
+                   else if (u->nextevent - rInfo->expire > 0) u->nextevent = rInfo->expire;
+                   }
+               }
+       //!!!KRS list should be pre-sorted by expiration
+       for (srs = u->ServiceRegistrations; srs; srs = srs->next)
+               {
+               rInfo = &srs->uDNS_info;        
+               if (rInfo->lease && rInfo->state == regState_Registered && rInfo->expire > 0)
+                   {               
+                   if (rInfo->expire < timenow)
+                       {       
+                           debugf("refreshing service %s", srs->RR_SRV.resrec.name.c);
+                           rInfo->state = regState_Refresh;
+                           SendServiceRegistration(m, srs);
+                       }
+                   else if (u->nextevent - rInfo->expire > 0) u->nextevent = rInfo->expire;
+                   }   
+               }
+       }
+
+mDNSexport void uDNS_Init(mDNS *const m)
+       {
+       mDNSPlatformMemZero(&m->uDNS_info, sizeof(uDNS_GlobalInfo));
+       m->uDNS_info.nextevent = mDNSPlatformTimeNow() + 0x78000000;
+       }
diff --git a/mDNSCore/uDNS.h b/mDNSCore/uDNS.h
new file mode 100755 (executable)
index 0000000..52fc878
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+
+$Log: uDNS.h,v $
+Revision 1.11  2004/06/17 01:13:11  ksekar
+<rdar://problem/3696616>: polling interval too short
+
+Revision 1.10  2004/06/11 05:45:03  ksekar
+<rdar://problem/3682397>: Change SRV names for LLQ/Update port lookups
+
+Revision 1.9  2004/06/01 23:46:50  ksekar
+<rdar://problem/3675149>: DynDNS: dynamically look up LLQ/Update ports
+
+Revision 1.8  2004/05/28 23:42:37  ksekar
+<rdar://problem/3258021>: Feature: DNS server->client notification on record changes (#7805)
+
+Revision 1.7  2004/05/18 23:51:25  cheshire
+Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
+
+Revision 1.6  2004/03/13 01:57:33  ksekar
+<rdar://problem/3192546>: DynDNS: Dynamic update of service records
+
+Revision 1.5  2004/02/21 08:56:58  bradley
+Wrap prototypes with extern "C" for C++ builds.
+
+Revision 1.4  2004/02/06 23:04:19  ksekar
+Basic Dynamic Update support via mDNS_Register (dissabled via
+UNICAST_REGISTRATION #define)
+
+Revision 1.3  2004/01/24 03:38:27  cheshire
+Fix minor syntactic error: Headers should use "extern" declarations, not "mDNSexport"
+
+Revision 1.2  2004/01/23 23:23:15  ksekar
+Added TCP support for truncated unicast messages.
+
+Revision 1.1  2003/12/13 03:05:27  ksekar
+<rdar://problem/3192548>: DynDNS: Unicast query of service records
+
+ */
+
+#ifndef __UDNS_H_
+#define __UDNS_H_
+
+#include "mDNSClientAPI.h"
+#include "DNSCommon.h"
+
+#ifdef __cplusplus
+       extern "C" {
+#endif
+
+#define INIT_UCAST_POLL_INTERVAL (15 * mDNSPlatformOneSecond)
+#define MAX_UCAST_POLL_INTERVAL (15 * 60 * mDNSPlatformOneSecond)
+#define NO_GOODBYE                       // will we receive goodbye packets from the server?
+#define UPDATE_PORT_NAME "_dns-update._udp."
+#define LLQ_PORT_NAME "_dns-llq._udp"
+       
+// Entry points into unicast-specific routines
+
+extern void uDNS_AdvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set);
+extern void uDNS_DeadvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set);
+
+extern mStatus uDNS_StartQuery(mDNS *const m, DNSQuestion *const question);
+extern mDNSBool IsActiveUnicastQuery(DNSQuestion *const question, uDNS_GlobalInfo *u);  // returns true if OK to call StopQuery
+extern mStatus uDNS_StopQuery(mDNS *const m, DNSQuestion *const question);
+
+// SuspendLLQs stops all LLQs, preserving known answers.  RestartLLQs re-starts these suspended LLQs, generating appropriate add/removes
+// Call SuspendLLQs prior to sleep, and on shutdown.  Call RestartLLQs on wake from sleep.
+extern void uDNS_SuspendLLQs(mDNS *m);
+extern void uDNS_RestartLLQs(mDNS *m);
+       
+extern mStatus uDNS_RegisterRecord(mDNS *const m, AuthRecord *const rr);
+extern mStatus uDNS_DeregisterRecord(mDNS *const m, AuthRecord *const rr);
+
+extern mStatus uDNS_RegisterService(mDNS *const m, ServiceRecordSet *srs);
+extern mStatus uDNS_DeregisterService(mDNS *const m, ServiceRecordSet *srs);
+extern void uDNS_UpdateServiceTargets(mDNS *const m);  // call following namechange
+
+// integer fields of msg header must be in HOST byte order before calling this routine
+extern void uDNS_ReceiveMsg(mDNS *const m, DNSMessage *const msg, const mDNSu8 *const end,
+const mDNSAddr *const srcaddr, const mDNSIPPort srcport, const mDNSAddr *const dstaddr, 
+const mDNSIPPort dstport, const mDNSInterfaceID InterfaceID, mDNSu8 ttl);
+
+// returns time of next scheduled event
+extern void uDNS_Execute(mDNS *const m);
+
+extern void uDNS_Init(mDNS *const m);
+       
+#ifdef __cplusplus
+       }
+#endif
+
+#endif // __UDNS_H_
index 105a3985f47c2c0bad966d472dbb83093816873e..853a4aca834a3a4cf10d7b5ba156c961223c65d1 100644 (file)
@@ -3,6 +3,8 @@
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
index 7c55ca3420ab84a90ba287a810b0144eaa6691eb..9ff78dca98bd0727ebecb49109499cb6d71a6177 100644 (file)
@@ -3,6 +3,8 @@
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
     Change History (most recent first):
 
 $Log: Mac\040OS\040Test\040Responder.c,v $
+Revision 1.21  2004/03/12 21:30:25  cheshire
+Build a System-Context Shared Library from mDNSCore, for the benefit of developers
+like Muse Research who want to be able to use mDNS/DNS-SD from GPL-licensed code.
+
+Revision 1.20  2004/02/09 23:23:32  cheshire
+Advertise "IL 2\4th Floor.apple.com." as another test "browse domain"
+
+Revision 1.19  2004/01/24 23:55:15  cheshire
+Change to use mDNSOpaque16fromIntVal/mDNSVal16 instead of shifting and masking
+
+Revision 1.18  2003/11/14 21:27:08  cheshire
+<rdar://problem/3484766>: Security: Crashing bug in mDNSResponder
+Fix code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1005) instead of 256-byte buffers.
+
 Revision 1.17  2003/08/14 02:19:54  cheshire
 <rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
 
@@ -46,7 +62,7 @@ Update to APSL 2.0
 static mDNS m;
 static mDNS_PlatformSupport p;
 static ServiceRecordSet p1, p2, afp, http, njp;
-static AuthRecord browsedomain;
+static AuthRecord browsedomain1, browsedomain2;
 
 // This sample code just calls mDNS_RenameAndReregisterService to automatically pick a new
 // unique name for the service. For a device such as a printer, this may be appropriate.
@@ -71,14 +87,11 @@ mDNSlocal void RegisterService(mDNS *m, ServiceRecordSet *recordset,
        UInt16 PortAsNumber, const char txtinfo[],
        const domainlabel *const n, const char type[], const char domain[])
        {
-       mDNSIPPort port;
        domainname t;
        domainname d;
-       char buffer[512];
+       char buffer[MAX_ESCAPED_DOMAIN_NAME];
        UInt8 txtbuffer[512];
 
-       port.b[0] = (UInt8)(PortAsNumber >> 8);
-       port.b[1] = (UInt8)(PortAsNumber     );
        MakeDomainNameFromDNSNameString(&t, type);
        MakeDomainNameFromDNSNameString(&d, domain);
        
@@ -92,10 +105,10 @@ mDNSlocal void RegisterService(mDNS *m, ServiceRecordSet *recordset,
 
        mDNS_RegisterService(m, recordset,
                n, &t, &d,                                                                      // Name, type, domain
-               mDNSNULL, port,                                                         // Host and port
+               mDNSNULL, mDNSOpaque16fromIntVal(PortAsNumber),
                txtbuffer, (mDNSu16)(1+txtbuffer[0]),           // TXT data, length
                mDNSNULL, 0,                                                            // Subtypes (none)
-               mDNSInterface_Any,                                                      // Interace ID
+               mDNSInterface_Any,                                                      // Interface ID
                Callback, mDNSNULL);                                            // Callback and context
 
        ConvertDomainNameToCString(&recordset->RR_SRV.resrec.name, buffer);
@@ -120,7 +133,6 @@ mDNSlocal void RegisterFakeServiceForTesting(mDNS *m, ServiceRecordSet *recordse
 mDNSlocal OSStatus CreateProxyRegistrationForRealService(mDNS *m, UInt16 PortAsNumber, const char txtinfo[],
        const char *servicetype, ServiceRecordSet *recordset)
        {
-       mDNSIPPort port;
        InetAddress ia;
        TBind bindReq;
        OSStatus err;
@@ -128,10 +140,8 @@ mDNSlocal OSStatus CreateProxyRegistrationForRealService(mDNS *m, UInt16 PortAsN
        EndpointRef ep = OTOpenEndpoint(OTCreateConfiguration(kTCPName), 0, &endpointinfo, &err);
        if (!ep || err) { printf("OTOpenEndpoint (CreateProxyRegistrationForRealService) failed %d", err); return(err); }
 
-       port.b[0] = (UInt8)(PortAsNumber >> 8);
-       port.b[1] = (UInt8)(PortAsNumber     );
        ia.fAddressType = AF_INET;
-       ia.fPort        = port.NotAnInteger;
+       ia.fPort        = mDNSOpaque16fromIntVal(PortAsNumber).NotAnInteger;
        ia.fHost        = 0;
        bindReq.addr.maxlen = sizeof(ia);
        bindReq.addr.len    = sizeof(ia);
@@ -151,7 +161,7 @@ mDNSlocal OSStatus CreateProxyRegistrationForRealService(mDNS *m, UInt16 PortAsN
 // Done once on startup, and then again every time our address changes
 mDNSlocal OSStatus mDNSResponderTestSetup(mDNS *m)
        {
-       char buffer[256];
+       char buffer[MAX_ESCAPED_DOMAIN_NAME];
        mDNSv4Addr ip = m->HostInterfaces->ip.ip.v4;
        
        ConvertDomainNameToCString(&m->hostname, buffer);
@@ -185,7 +195,8 @@ mDNSlocal OSStatus mDNSResponderTestSetup(mDNS *m)
        //RegisterService(m, &njp, 80, "NJP/", &m->nicelabel, "_njp._tcp.", "local.");
 
        // Advertise that apple.com. is available for browsing
-       mDNS_AdvertiseDomains(m, &browsedomain, mDNS_DomainTypeBrowse, mDNSInterface_Any, "IL 2\\4th Floor.apple.com.");
+       mDNS_AdvertiseDomains(m, &browsedomain1, mDNS_DomainTypeBrowse, mDNSInterface_Any, "apple.com.");
+       mDNS_AdvertiseDomains(m, &browsedomain2, mDNS_DomainTypeBrowse, mDNSInterface_Any, "IL 2\\4th Floor.apple.com.");
 
        return(kOTNoError);
        }
@@ -202,16 +213,13 @@ mDNSlocal Boolean YieldSomeTime(UInt32 milliseconds)
 
 int main()
        {
-       extern void mDNSPlatformIdle(mDNS *const m);    // Only needed for debugging version
        mStatus err;
        Boolean DoneSetup = false;
 
        SIOUXSettings.asktosaveonclose = false;
        SIOUXSettings.userwindowtitle = "\pMulticast DNS Responder";
 
-       printf("Prototype Multicast DNS Responder\n\n");
-       printf("WARNING! This is experimental software.\n\n");
-       printf("Multicast DNS is currently an experimental protocol.\n\n");
+       printf("Multicast DNS Responder\n\n");
        printf("This software reports errors using MacsBug breaks,\n");
        printf("so if you don't have MacsBug installed your Mac may crash.\n\n");
        printf("******************************************************************************\n");
@@ -225,9 +233,12 @@ int main()
 
        while (!YieldSomeTime(35))
                {
-               // For debugging, use "#define __ONLYSYSTEMTASK__ 1" and call mDNSPlatformIdle() periodically.
-               // For shipping code, don't define __ONLYSYSTEMTASK__, and you don't need to call mDNSPlatformIdle()
+#if MDNS_ONLYSYSTEMTASK
+               // For debugging, use "#define MDNS_ONLYSYSTEMTASK 1" and call mDNSPlatformIdle() periodically.
+               // For shipping code, don't define MDNS_ONLYSYSTEMTASK, and you don't need to call mDNSPlatformIdle()
+               extern void mDNSPlatformIdle(mDNS *const m);
                mDNSPlatformIdle(&m);   // Only needed for debugging version
+#endif
                if (m.mDNSPlatformStatus == mStatus_NoError && !DoneSetup)
                        {
                        DoneSetup = true;
index d55dcd5969751ef77d67d7a98447bccad51f7720..6b5d90d16216c16d89679d1b11c4f7b5bd121970 100644 (file)
@@ -3,6 +3,8 @@
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
     Change History (most recent first):
 
 $Log: Mac\040OS\040Test\040Searcher.c,v $
+Revision 1.17  2004/06/10 04:37:27  cheshire
+Add new parameter in mDNS_GetDomains()
+
+Revision 1.16  2004/03/12 21:30:25  cheshire
+Build a System-Context Shared Library from mDNSCore, for the benefit of developers
+like Muse Research who want to be able to use mDNS/DNS-SD from GPL-licensed code.
+
+Revision 1.15  2004/01/24 23:55:15  cheshire
+Change to use mDNSOpaque16fromIntVal/mDNSVal16 instead of shifting and masking
+
+Revision 1.14  2003/11/14 21:27:09  cheshire
+<rdar://problem/3484766>: Security: Crashing bug in mDNSResponder
+Fix code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1005) instead of 256-byte buffers.
+
 Revision 1.13  2003/08/14 02:19:54  cheshire
 <rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
 
@@ -75,7 +91,7 @@ static void PrintServiceInfo(SearcherServices *services)
 
                if (ls->dom)
                        {
-                       char c_dom[256];
+                       char c_dom[MAX_ESCAPED_DOMAIN_NAME];
                        ConvertDomainNameToCString(&s->name, c_dom);
                        if (ls->add) printf("%-55s available for browsing\n", c_dom);
                        else         printf("%-55s no longer available for browsing\n", c_dom);
@@ -84,9 +100,7 @@ static void PrintServiceInfo(SearcherServices *services)
                        {
                        domainlabel name;
                        domainname type, domain;
-                       UInt16 port = (UInt16)((UInt16)s->port.b[0] << 8 | s->port.b[1]);
-                       char c_name[64], c_type[256], c_dom[256], c_ip[20];
-                       
+                       char c_name[MAX_DOMAIN_LABEL+1], c_type[MAX_ESCAPED_DOMAIN_NAME], c_dom[MAX_ESCAPED_DOMAIN_NAME], c_ip[20];
                        DeconstructServiceName(&s->name, &name, &type, &domain);
                        ConvertDomainLabelToCString_unescaped(&name, c_name);
                        ConvertDomainNameToCString(&type, c_type);
@@ -94,7 +108,7 @@ static void PrintServiceInfo(SearcherServices *services)
                        sprintf(c_ip, "%d.%d.%d.%d", s->ip.ip.v4.b[0], s->ip.ip.v4.b[1], s->ip.ip.v4.b[2], s->ip.ip.v4.b[3]);
 
                        printf("%-55s %-16s %-14s ", c_name, c_type, c_dom);
-                       if (ls->add) printf("%-15s %5d %#s\n", c_ip, port, s->TXTinfo);
+                       if (ls->add) printf("%-15s %5d %#s\n", c_ip, mDNSVal16(s->port), s->TXTinfo);
                        else         printf("Removed\n");
                        }
 
@@ -141,7 +155,7 @@ static void FoundInstance(mDNS *const m, DNSQuestion *question, const ResourceRe
        info->i.name          = answer->rdata->u.name;
        info->i.InterfaceID   = answer->InterfaceID;
        info->i.ip.type           = mDNSAddrType_IPv4;
-       info->i.ip.ip.v4  = zeroIPAddr;
+       info->i.ip.ip.v4      = zeroIPAddr;
        info->i.port          = zeroIPPort;
        info->add             = AddRecord;
        info->dom             = mDNSfalse;
@@ -174,7 +188,7 @@ static void FoundDomain(mDNS *const m, DNSQuestion *question, const ResourceReco
        info->i.name          = answer->rdata->u.name;
        info->i.InterfaceID   = answer->InterfaceID;
        info->i.ip.type           = mDNSAddrType_IPv4;
-       info->i.ip.ip.v4  = zeroIPAddr;
+       info->i.ip.ip.v4      = zeroIPAddr;
        info->i.port          = zeroIPPort;
        info->add             = AddRecord;
        info->dom             = mDNStrue;
@@ -194,18 +208,16 @@ static Boolean YieldSomeTime(UInt32 milliseconds)
 
 int main()
        {
-       extern void mDNSPlatformIdle(mDNS *const m);    // Only needed for debugging version
        mStatus err;
        Boolean DoneSetup = false;
+       void *tempmem;
 
        SIOUXSettings.asktosaveonclose = false;
        SIOUXSettings.userwindowtitle  = "\pMulticast DNS Searcher";
        SIOUXSettings.rows             = 40;
        SIOUXSettings.columns          = 132;
 
-       printf("Prototype Multicast DNS Searcher\n\n");
-       printf("WARNING! This is experimental software.\n\n");
-       printf("Multicast DNS is currently an experimental protocol.\n\n");
+       printf("Multicast DNS Searcher\n\n");
        printf("This software reports errors using MacsBug breaks,\n");
        printf("so if you don't have MacsBug installed your Mac may crash.\n\n");
        printf("******************************************************************************\n");
@@ -217,15 +229,23 @@ int main()
                mDNS_Init_DontAdvertiseLocalAddresses, mDNS_Init_NoInitCallback, mDNS_Init_NoInitCallbackContext);
        if (err) return(err);
 
+       // Make sure OT has a large enough memory pool for us to draw from at OTNotifier (interrupt) time
+       tempmem = OTAllocMem(0x10000);
+       if (tempmem) OTFreeMem(tempmem);
+       else printf("**** Warning: OTAllocMem couldn't pre-allocate 64K for us.\n");
+
        services.serviceinfolist.fHead = NULL;
        services.headerPrinted         = false;
        services.lostRecords           = false;
 
        while (!YieldSomeTime(35))
                {
-               // For debugging, use "#define __ONLYSYSTEMTASK__ 1" and call mDNSPlatformIdle() periodically.
-               // For shipping code, don't define __ONLYSYSTEMTASK__, and you don't need to call mDNSPlatformIdle()
+#if MDNS_ONLYSYSTEMTASK
+               // For debugging, use "#define MDNS_ONLYSYSTEMTASK 1" and call mDNSPlatformIdle() periodically.
+               // For shipping code, don't define MDNS_ONLYSYSTEMTASK, and you don't need to call mDNSPlatformIdle()
+               extern void mDNSPlatformIdle(mDNS *const m);
                mDNSPlatformIdle(&mDNSStorage); // Only needed for debugging version
+#endif
                if (mDNSStorage.mDNSPlatformStatus == mStatus_NoError && !DoneSetup)
                        {
                        domainname srvtype, srvdom;
@@ -235,7 +255,7 @@ int main()
                        MakeDomainNameFromDNSNameString(&srvdom, "local.");
                        err = mDNS_StartBrowse(&mDNSStorage, &browsequestion, &srvtype, &srvdom, mDNSInterface_Any, FoundInstance, &services);
                        if (err) break;
-                       err = mDNS_GetDomains(&mDNSStorage, &domainquestion, mDNS_DomainTypeBrowse, mDNSInterface_Any, FoundDomain, &services);
+                       err = mDNS_GetDomains(&mDNSStorage, &domainquestion, mDNS_DomainTypeBrowse, NULL, mDNSInterface_Any, FoundDomain, &services);
                        if (err) break;
                        }
 
index 4d137617e5c3acd2cbf9cc97ec38205c0d15f39f..c30c423acb48545140211acac7a6aa6e28ebfba1 100644 (file)
@@ -7,4 +7,42 @@ mDNSMacOS9.c and mDNSMacOS9.h are the Platform Support files that go below
 mDNS Core.
 
 "Mac OS Test Responder.c" and "Mac OS Test Searcher.c" build an example
-mDNS Responder and Searcher, respectively.
\ No newline at end of file
+standalone (embedded) mDNS Responder and Searcher, respectively.
+
+"mDNSLibrary.c" builds a CFM Shared Library that goes in the Extensions Folder
+
+The CFM Shared Library inplements the same "/usr/include/dns_sd.h" API
+that exists on OS X, Windows, Linux, etc., one exception:
+
+ - You don't need to call DNSServiceRefSockFD() to get a file descriptor,
+   and add that file descriptor to your select loop (or equivalent),
+   wait for data,
+   and then call DNSServiceProcessResult() every time data arrives.
+
+   On OS 9, your callback functions are called "by magic" without having
+   to do any of this. Of course no magic comes without a price, and
+   the magic being used here is an OT Notifier function. Your callback
+   functions are called directly from the OT Notifier function that
+   received the UDP packet from the wire, which is fast and efficient,
+   but it does mean that you're being called at OT Notifier time -- so
+   no QuickDraw calls. If you need to allocate memory in your callback
+   function, use OTAllocMem(), not NewPtr() or NewHandle(). Typically
+   what you'll do in your callback function is just update your program's
+   data structures, and leave screen updating and UI to some foreground
+   code.
+
+"Searcher.c" and "Responder.c" build sample applications that link with
+this CFM Shared Library in the Extensions Folder. You'll see that if
+you try to run them without first putting the "Multicast DNS & DNS-SD"
+library in the Extensions Folder and restarting, they will report an
+error message.
+
+"Searcher.c" builds a sample application that browses for HTTP servers.
+
+"Responder.c" builds a sample application that advertises some test
+services. By default it advertises a couple of (nonexistent) HTTP servers
+called "Web Server One" and "Web Server Two". In addition, if it finds that
+TCP port 548 is occupied, then it concludes that personal file sharing is
+running, and advertises the existence of an AFP server. Similarly, if it
+finds that TCP port 80 is occupied, then it concludes that personal Web
+sharing is running, advertises the existence of an HTTP server.
diff --git a/mDNSMacOS9/Responder.c b/mDNSMacOS9/Responder.c
new file mode 100644 (file)
index 0000000..d1612f8
--- /dev/null
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+
+$Log: Responder.c,v $
+Revision 1.2  2004/05/20 18:38:31  cheshire
+Fix build broken by removal of 'kDNSServiceFlagsAutoRename' from dns_sd.h
+
+Revision 1.1  2004/03/12 21:30:25  cheshire
+Build a System-Context Shared Library from mDNSCore, for the benefit of developers
+like Muse Research who want to be able to use mDNS/DNS-SD from GPL-licensed code.
+
+ */
+
+#include <stdio.h>                                             // For printf()
+#include <string.h>                                            // For strcpy()
+
+#include <Events.h>                                            // For WaitNextEvent()
+
+#include <OpenTransport.h>
+#include <OpenTptInternet.h>
+
+#include <SIOUX.h>                                             // For SIOUXHandleOneEvent()
+
+#include "dns_sd.h"
+
+typedef union { UInt8 b[2]; UInt16 NotAnInteger; } mDNSOpaque16;
+static UInt16 mDNSVal16(mDNSOpaque16 x) { return((UInt16)(x.b[0]<<8 | x.b[1])); }
+static mDNSOpaque16 mDNSOpaque16fromIntVal(UInt16 v)
+       { mDNSOpaque16 x; x.b[0] = (UInt8)(v >> 8); x.b[1] = (UInt8)(v & 0xFF); return(x); }
+
+typedef struct RegisteredService_struct RegisteredService;
+struct RegisteredService_struct
+       {
+       RegisteredService *next;
+       DNSServiceRef sdRef;
+       Boolean gotresult;
+       DNSServiceErrorType errorCode;
+       char namestr[64];
+       char typestr[kDNSServiceMaxDomainName];
+       char domstr [kDNSServiceMaxDomainName];
+       };
+
+static RegisteredService p1, p2, afp, http, njp;
+static RegisteredService *services = NULL, **nextservice = &services;
+
+static void RegCallback(DNSServiceRef sdRef, DNSServiceFlags flags, DNSServiceErrorType errorCode,
+                                               const char *name, const char *regtype, const char *domain, void *context)
+    {
+    RegisteredService *rs = (RegisteredService *)context;
+    (void)sdRef;       // Unused
+    (void)flags;       // Unused
+    rs->gotresult = true;
+    rs->errorCode = errorCode;
+    strcpy(rs->namestr, name);
+    strcpy(rs->typestr, regtype);
+    strcpy(rs->domstr,  domain);
+    }
+
+static DNSServiceErrorType RegisterService(RegisteredService *rs, mDNSOpaque16 OpaquePort,
+       const char name[], const char type[], const char domain[], const char txtinfo[])
+       {
+       DNSServiceErrorType err;
+       unsigned char txtbuffer[257];
+       strncpy((char*)txtbuffer+1, txtinfo, 255);
+       txtbuffer[256] = 0;
+       txtbuffer[0] = (unsigned char)strlen((char*)txtbuffer);
+       rs->gotresult = 0;
+       rs->errorCode = kDNSServiceErr_NoError;
+       err = DNSServiceRegister(&rs->sdRef, /* kDNSServiceFlagsAutoRename*/ 0, 0,
+               name, type, domain, NULL, OpaquePort.NotAnInteger, (unsigned short)(1+txtbuffer[0]), txtbuffer, RegCallback, rs);
+       if (err)
+               printf("RegisterService(%s %s %s) failed %d\n", name, type, domain, err);
+       else
+               { *nextservice = rs; nextservice = &rs->next; }
+       return(err);
+       }
+
+// RegisterFakeServiceForTesting() simulates the effect of services being registered on
+// dynamically-allocated port numbers. No real service exists on that port -- this is just for testing.
+static DNSServiceErrorType RegisterFakeServiceForTesting(RegisteredService *rs,
+       const char name[], const char type[], const char domain[], const char txtinfo[])
+       {
+       static UInt16 NextPort = 0xF000;
+       return RegisterService(rs, mDNSOpaque16fromIntVal(NextPort++), name, type, domain, txtinfo);
+       }
+
+// CreateProxyRegistrationForRealService() checks to see if the given port is currently
+// in use, and if so, advertises the specified service as present on that port.
+// This is useful for advertising existing real services (Personal Web Sharing, Personal
+// File Sharing, etc.) that currently don't register with mDNS Service Discovery themselves.
+static DNSServiceErrorType CreateProxyRegistrationForRealService(RegisteredService *rs,
+       const char *servicetype, UInt16 PortAsNumber, const char txtinfo[])
+       {
+       mDNSOpaque16 OpaquePort = mDNSOpaque16fromIntVal(PortAsNumber);
+       InetAddress ia;
+       TBind bindReq;
+       OSStatus err;
+       TEndpointInfo endpointinfo;
+       EndpointRef ep = OTOpenEndpoint(OTCreateConfiguration(kTCPName), 0, &endpointinfo, &err);
+       if (!ep || err) { printf("OTOpenEndpoint (CreateProxyRegistrationForRealService) failed %d", err); return(err); }
+
+       ia.fAddressType = AF_INET;
+       ia.fPort        = OpaquePort.NotAnInteger;
+       ia.fHost        = 0;
+       bindReq.addr.maxlen = sizeof(ia);
+       bindReq.addr.len    = sizeof(ia);
+       bindReq.addr.buf    = (UInt8*)&ia;
+       bindReq.qlen        = 0;
+       err = OTBind(ep, &bindReq, NULL);
+
+       if (err == kOTBadAddressErr)
+               err = RegisterService(rs, OpaquePort, "", servicetype, "local.", txtinfo);
+       else if (err)
+               printf("OTBind failed %d", err);
+
+       OTCloseProvider(ep);
+       return(err);
+       }
+
+// YieldSomeTime() just cooperatively yields some time to other processes running on classic Mac OS
+static Boolean YieldSomeTime(UInt32 milliseconds)
+       {
+       extern Boolean SIOUXQuitting;
+       EventRecord e;
+       WaitNextEvent(everyEvent, &e, milliseconds / 17, NULL);
+       SIOUXHandleOneEvent(&e);
+       return(SIOUXQuitting);
+       }
+
+int main()
+       {
+       OSStatus err;
+       RegisteredService *s;
+       
+       SIOUXSettings.asktosaveonclose = false;
+       SIOUXSettings.userwindowtitle = "\pMulticast DNS Responder";
+
+       printf("Multicast DNS Responder\n\n");
+       printf("This software reports errors using MacsBug breaks,\n");
+       printf("so if you don't have MacsBug installed your Mac may crash.\n\n");
+       printf("******************************************************************************\n\n");
+
+       err = InitOpenTransport();
+       if (err) { printf("InitOpenTransport failed %d", err); return(err); }
+
+       printf("Advertising Services...\n");
+
+#define SRSET 0
+#if SRSET==0
+       RegisterFakeServiceForTesting(&p1, "Web Server One", "_http._tcp.", "local.", "path=/index.html");
+       RegisterFakeServiceForTesting(&p2, "Web Server Two", "_http._tcp.", "local.", "path=/path.html");
+#elif SRSET==1
+       RegisterFakeServiceForTesting(&p1, "Epson Stylus 900N", "_printer._tcp.", "local.", "rn=lpq1");
+       RegisterFakeServiceForTesting(&p2, "HP LaserJet",       "_printer._tcp.", "local.", "rn=lpq2");
+#else
+       RegisterFakeServiceForTesting(&p1, "My Printer",        "_printer._tcp.", "local.", "rn=lpq3");
+       RegisterFakeServiceForTesting(&p2, "My Other Printer",  "_printer._tcp.", "local.", "lrn=pq4");
+#endif
+
+       // If AFP Server is running, register a record for it
+       CreateProxyRegistrationForRealService(&afp, "_afpovertcp._tcp.", 548, "");
+
+       // If Web Server is running, register a record for it
+       CreateProxyRegistrationForRealService(&http, "_http._tcp.",       80, "path=/index.html");
+
+       while (!YieldSomeTime(35))
+               for (s = services; s; s = s->next)
+                       if (s->gotresult)
+                               {
+                               printf("%s %s %s registered\n", s->namestr, s->typestr, s->domstr);
+                               s->gotresult = false;
+                               }
+       
+       for (s = services; s; s = s->next)
+               if (s->sdRef) DNSServiceRefDeallocate(s->sdRef);
+
+       CloseOpenTransport();
+       return(0);
+       }
diff --git a/mDNSMacOS9/Searcher.c b/mDNSMacOS9/Searcher.c
new file mode 100644 (file)
index 0000000..4d0d494
--- /dev/null
@@ -0,0 +1,259 @@
+/*
+ * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+
+$Log: Searcher.c,v $
+Revision 1.2  2004/05/27 06:30:21  cheshire
+Add code to test DNSServiceQueryRecord()
+
+Revision 1.1  2004/03/12 21:30:25  cheshire
+Build a System-Context Shared Library from mDNSCore, for the benefit of developers
+like Muse Research who want to be able to use mDNS/DNS-SD from GPL-licensed code.
+
+ */
+
+#include <stdio.h>                                             // For printf()
+#include <string.h>                                            // For strcpy()
+
+#include <Events.h>                                            // For WaitNextEvent()
+#include <CodeFragments.h>                             // For SIOkUnresolvedCFragSymbolAddress
+
+#include <SIOUX.h>                                             // For SIOUXHandleOneEvent()
+
+#include <OpenTransport.h>
+#include <OpenTptInternet.h>
+
+#include "dns_sd.h"
+
+#define ns_c_in 1
+#define ns_t_a 1
+
+typedef union { UInt8 b[2]; UInt16 NotAnInteger; } mDNSOpaque16;
+static UInt16 mDNSVal16(mDNSOpaque16 x) { return((UInt16)(x.b[0]<<8 | x.b[1])); }
+static mDNSOpaque16 mDNSOpaque16fromIntVal(UInt16 v)
+       { mDNSOpaque16 x; x.b[0] = (UInt8)(v >> 8); x.b[1] = (UInt8)(v & 0xFF); return(x); }
+
+typedef struct
+       {
+       OTLIFO serviceinfolist;
+       Boolean headerPrinted;
+       Boolean lostRecords;
+       } SearcherServices;
+
+typedef struct
+       {
+       SearcherServices *services;
+       char name[kDNSServiceMaxDomainName];
+       char type[kDNSServiceMaxDomainName];
+       char domn[kDNSServiceMaxDomainName];
+       char host[kDNSServiceMaxDomainName];
+       char text[kDNSServiceMaxDomainName];
+       InetHost      address;
+       mDNSOpaque16  notAnIntPort;
+       DNSServiceRef sdRef;
+       Boolean       add;
+       Boolean       dom;
+       OTLink        link;
+       } linkedServiceInfo;
+
+static SearcherServices services;
+
+// PrintServiceInfo prints the service information to standard out
+// A real application might want to do something else with the information
+static void PrintServiceInfo(SearcherServices *services)
+       {
+       OTLink *link = OTReverseList(OTLIFOStealList(&services->serviceinfolist));
+       
+       while (link)
+               {
+               linkedServiceInfo *s = OTGetLinkObject(link, linkedServiceInfo, link);
+
+               if (!services->headerPrinted)
+                       {
+                       printf("%-55s Type             Domain         Target Host     IP Address      Port Info\n", "Name");
+                       services->headerPrinted = true;
+                       }
+
+               if (s->dom)
+                       {
+                       if (s->add) printf("%-55s available for browsing\n", s->domn);
+                       else        printf("%-55s no longer available for browsing\n", s->domn);
+                       }
+               else
+                       {
+                       char ip[16];
+                       unsigned char *p = (unsigned char *)&s->address;
+                       sprintf(ip, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
+                       printf("%-55s %-16s %-14s ", s->name, s->type, s->domn);
+                       if (s->add) printf("%-15s %-15s %5d %s\n", s->host, ip, mDNSVal16(s->notAnIntPort), s->text);
+                       else        printf("Removed\n");
+                       }
+
+               link = link->fNext;
+               OTFreeMem(s);
+               }
+       }
+
+static void FoundInstanceAddress(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)
+       {
+       linkedServiceInfo *info = (linkedServiceInfo *)context;
+       SearcherServices *services = info->services;
+       (void)sdRef;                    // Unused
+       (void)interfaceIndex;   // Unused
+       (void)fullname;                 // Unused
+       (void)ttl;                              // Unused
+       if (errorCode == kDNSServiceErr_NoError)
+               if (flags & kDNSServiceFlagsAdd)
+                       if (rrclass == ns_c_in && rrtype == ns_t_a && rdlen == sizeof(info->address))
+                               {
+                               memcpy(&info->address, rdata, sizeof(info->address));
+                               DNSServiceRefDeallocate(info->sdRef);
+                               OTLIFOEnqueue(&services->serviceinfolist, &info->link);
+                               }
+       }
+
+static void FoundInstanceInfo(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex,
+       DNSServiceErrorType errorCode, const char *fullname, const char *hosttarget, uint16_t notAnIntPort,
+       uint16_t txtLen, const char *txtRecord, void *context)
+       {
+       linkedServiceInfo *info = (linkedServiceInfo *)context;
+       SearcherServices *services = info->services;
+       (void)sdRef;                    // Unused
+       (void)flags;                    // Unused
+       (void)interfaceIndex;   // Unused
+       (void)errorCode;                // Unused
+       (void)fullname;                 // Unused
+       strcpy(info->host, hosttarget);
+       if (txtLen == 0) info->text[0] = 0;
+       else
+               {
+               strncpy(info->text, txtRecord+1, txtRecord[0]);
+               info->text[txtRecord[0]] = 0;
+               }
+       info->notAnIntPort.NotAnInteger = notAnIntPort;
+       DNSServiceRefDeallocate(info->sdRef);
+       DNSServiceQueryRecord(&info->sdRef, 0, 0, info->host, ns_t_a, ns_c_in, FoundInstanceAddress, info);
+       }
+
+// When a new named instance of a service is found, FoundInstance() is called.
+// In this sample code we turn around and immediately to a DNSServiceResolve() to resolve that service name
+// to find its target host, port, and txtinfo, but a normal browing application would just display the name.
+// Resolving every single thing you find can be quite hard on the network, so you shouldn't do this
+// in a real application. Defer resolving until the client has picked which instance from the
+// long list of services is the one they want to use, and then resolve only that one.
+static void FoundInstance(DNSServiceRef client, DNSServiceFlags flags, uint32_t interface, DNSServiceErrorType errorCode,
+    const char *replyName, const char *replyType, const char *replyDomain, void *context)
+       {
+#pragma unused(client, interface, errorCode)
+       SearcherServices *services = (SearcherServices *)context;
+       linkedServiceInfo *info;
+
+       if (!services) { DebugStr("\pFoundInstance: services is NULL"); return; }
+       
+       info = (linkedServiceInfo *)OTAllocMem(sizeof(linkedServiceInfo));
+       if (!info) { services->lostRecords = true; return; }
+       
+       info->services = services;
+       strcpy(info->name, replyName);
+       strcpy(info->type, replyType);
+       strcpy(info->domn, replyDomain);
+       info->text[0] = 0;
+       info->add = (flags & kDNSServiceFlagsAdd) ? true : false;
+       info->dom = false;
+       
+       if (!info->add) // If TTL == 0 we're deleting a service,
+               OTLIFOEnqueue(&services->serviceinfolist, &info->link);
+       else                                                            // else we're adding a new service
+               DNSServiceResolve(&info->sdRef, 0, 0, info->name, info->type, info->domn, FoundInstanceInfo, info);
+       }
+
+// YieldSomeTime() just cooperatively yields some time to other processes running on classic Mac OS
+static Boolean YieldSomeTime(UInt32 milliseconds)
+       {
+       extern Boolean SIOUXQuitting;
+       EventRecord e;
+       WaitNextEvent(everyEvent, &e, milliseconds / 17, NULL);
+       SIOUXHandleOneEvent(&e);
+       return(SIOUXQuitting);
+       }
+
+int main()
+       {
+       OSStatus err;
+       void *tempmem;
+       DNSServiceRef sdRef;
+       DNSServiceErrorType dse;
+
+       SIOUXSettings.asktosaveonclose = false;
+       SIOUXSettings.userwindowtitle  = "\pMulticast DNS Searcher";
+       SIOUXSettings.rows             = 40;
+       SIOUXSettings.columns          = 160;
+
+       printf("DNS-SD Search Client\n\n");
+       printf("This software reports errors using MacsBug breaks,\n");
+       printf("so if you don't have MacsBug installed your Mac may crash.\n\n");
+       printf("******************************************************************************\n\n");
+
+       if (DNSServiceBrowse == (void*)kUnresolvedCFragSymbolAddress)
+               {
+               printf("Before you can use mDNS/DNS-SD clients, you need to place the \n");
+               printf("\"Multicast DNS & DNS-SD\" Extension in the Extensions Folder and restart\n");
+               return(-1);
+               }
+
+       err = InitOpenTransport();
+       if (err) { printf("InitOpenTransport failed %d", err); return(err); }
+
+       // Make sure OT has a large enough memory pool for us to draw from at OTNotifier (interrupt) time
+       tempmem = OTAllocMem(0x10000);
+       if (tempmem) OTFreeMem(tempmem);
+       else printf("**** Warning: OTAllocMem couldn't pre-allocate 64K for us.\n");
+
+       services.serviceinfolist.fHead = NULL;
+       services.headerPrinted         = false;
+       services.lostRecords           = false;
+
+       printf("Sending mDNS service lookup queries and waiting for responses...\n\n");
+    dse = DNSServiceBrowse(&sdRef, 0, 0, "_http._tcp", "", FoundInstance, &services);
+       if (dse == kDNSServiceErr_NoError)
+               {
+               while (!YieldSomeTime(35))
+                       {
+                       if (services.serviceinfolist.fHead)
+                               PrintServiceInfo(&services);
+
+                       if (services.lostRecords)
+                               {
+                               services.lostRecords = false;
+                               printf("**** Warning: Out of memory: Records have been missed.\n");
+                               }
+                       }
+               }
+
+       DNSServiceRefDeallocate(sdRef);
+       CloseOpenTransport();
+       return(0);
+       }
diff --git a/mDNSMacOS9/ShowInitIcon.c b/mDNSMacOS9/ShowInitIcon.c
new file mode 100755 (executable)
index 0000000..5844c5e
--- /dev/null
@@ -0,0 +1,160 @@
+// ShowInitIcon - version 1.0.1, May 30th, 1995
+// This code is intended to let INIT writers easily display an icon at startup time.
+// View in Geneva 9pt, 4-space tabs
+
+// Written by: Peter N Lewis <peter@mail.peter.com.au>, Jim Walker <JWWalker@aol.com>
+// and François Pottier <pottier@dmi.ens.fr>, with thanks to previous ShowINIT authors.
+// Send comments and bug reports to François Pottier.
+
+// This version features:
+// - Short and readable code.
+// - Correctly wraps around when more than one row of icons has been displayed.
+// - works with System 6
+// - Built with Universal Headers & CodeWarrior. Should work with other headers/compilers.
+
+#include <Memory.h>
+#include <Resources.h>
+#include <Icons.h>
+#include <OSUtils.h>
+#include "ShowInitIcon.h"
+
+// You should set SystemSixOrLater in your headers to avoid including glue for SysEnvirons.
+
+// ---------------------------------------------------------------------------------------------------------------------
+// Set this flag to 1 if you want to compile this file into a stand-alone resource (see note below).
+// Set it to 0 if you want to include this source file into your INIT project.
+
+#if 0
+#define ShowInitIcon main
+#endif
+
+// ---------------------------------------------------------------------------------------------------------------------
+// The ShowINIT mechanism works by having each INIT read/write data from these globals.
+// The MPW C compiler doesn't accept variables declared at an absolute address, so I use these macros instead.
+// Only one macro is defined per variable; there is no need to define a Set and a Get accessor like in <LowMem.h>.
+
+#define        LMVCheckSum             (* (unsigned short*) 0x928)
+#define        LMVCoord                (* (         short*) 0x92A)
+#define        LMHCoord                (* (         short*) 0x92C)
+#define        LMHCheckSum             (* (unsigned short*) 0x92E)
+
+// ---------------------------------------------------------------------------------------------------------------------
+// Prototypes for the subroutines. The main routine comes first; this is necessary to make THINK C's "Custom Header" option work.
+
+static unsigned short CheckSum (short x);
+static void ComputeIconRect (Rect* iconRect, Rect* screenBounds);
+static void AdvanceIconPosition (Rect* iconRect);
+static void DrawBWIcon (short iconID, Rect *iconRect);
+
+// ---------------------------------------------------------------------------------------------------------------------
+// Main routine.
+
+typedef struct {
+       QDGlobals                       qd;                                                                     // Storage for the QuickDraw globals
+       long                            qdGlobalsPtr;                                                   // A5 points to this place; it will contain a pointer to qd
+} QDStorage;
+
+pascal void ShowInitIcon (short iconFamilyID, Boolean advance)
+{
+       long                            oldA5;                                                          // Original value of register A5
+       QDStorage                       qds;                                                                    // Fake QD globals
+       CGrafPort                       colorPort;
+       GrafPort                        bwPort;
+       Rect                            destRect;
+       SysEnvRec               environment;                                                    // Machine configuration.
+       
+       oldA5 = SetA5((long) &qds.qdGlobalsPtr);                                                // Tell A5 to point to the end of the fake QD Globals
+       InitGraf(&qds.qd.thePort);                                                              // Initialize the fake QD Globals
+       
+       SysEnvirons(curSysEnvVers, &environment);                                       // Find out what kind of machine this is
+
+       ComputeIconRect(&destRect, &qds.qd.screenBits.bounds);                  // Compute where the icon should be drawn
+
+       if (environment.systemVersion >= 0x0700 && environment.hasColorQD) {
+               OpenCPort(&colorPort);
+               PlotIconID(&destRect, atNone, ttNone, iconFamilyID);
+               CloseCPort(&colorPort);
+       }
+       else {
+               OpenPort(&bwPort);
+               DrawBWIcon(iconFamilyID, &destRect);
+               ClosePort(&bwPort);
+       }
+       
+       if (advance)
+               AdvanceIconPosition (&destRect);
+               
+       SetA5(oldA5);                                                                                   // Restore A5 to its previous value
+}
+
+// ---------------------------------------------------------------------------------------------------------------------
+// A checksum is used to make sure that the data in there was left by another ShowINIT-aware INIT.
+
+static unsigned short CheckSum (short x)
+{
+       return (unsigned short)(((x << 1) | (x >> 15)) ^ 0x1021);
+}
+
+// ---------------------------------------------------------------------------------------------------------------------
+// ComputeIconRect computes where the icon should be displayed.
+
+static void ComputeIconRect (Rect* iconRect, Rect* screenBounds)
+{
+       if (CheckSum(LMHCoord) != LMHCheckSum)                                  // If we are first, we need to initialize the shared data.
+               LMHCoord = 8;
+       if (CheckSum(LMVCoord) != LMVCheckSum)
+               LMVCoord = (short)(screenBounds->bottom - 40);
+       
+       if (LMHCoord + 34 > screenBounds->right) {                                      // Check whether we must wrap
+               iconRect->left = 8;
+               iconRect->top = (short)(LMVCoord - 40);
+       }
+       else {
+               iconRect->left = LMHCoord;
+               iconRect->top = LMVCoord;
+       }
+       iconRect->right  = (short)(iconRect->left + 32);
+       iconRect->bottom = (short)(iconRect->top  + 32);
+}
+
+// AdvanceIconPosition updates the shared global variables so that the next extension will draw its icon beside ours.
+
+static void AdvanceIconPosition (Rect* iconRect)
+{
+       LMHCoord = (short)(iconRect->left + 40);                                        // Update the shared data
+       LMVCoord = iconRect->top;
+       LMHCheckSum = CheckSum(LMHCoord);
+       LMVCheckSum = CheckSum(LMVCoord);
+}
+
+// DrawBWIcon draws the 'ICN#' member of the icon family. It works under System 6.
+
+static void DrawBWIcon (short iconID, Rect *iconRect)
+{
+       Handle          icon;
+       BitMap          source, destination;
+       GrafPtr         port;
+       
+       icon = Get1Resource('ICN#', iconID);
+       if (icon != NULL) {
+               HLock(icon);
+                                                                                                               // Prepare the source and destination bitmaps.
+               source.baseAddr = *icon + 128;                                          // Mask address.
+               source.rowBytes = 4;
+               SetRect(&source.bounds, 0, 0, 32, 32);
+               GetPort(&port);
+               destination = port->portBits;
+                                                                                                               // Transfer the mask.
+               CopyBits(&source, &destination, &source.bounds, iconRect, srcBic, nil);
+                                                                                                               // Then the icon.
+               source.baseAddr = *icon;
+               CopyBits(&source, &destination, &source.bounds, iconRect, srcOr, nil);
+       }
+}
+
+// ---------------------------------------------------------------------------------------------------------------------
+// Notes
+
+// Checking for PlotIconID:
+// We (PNL) now check for system 7 and colour QD, and use colour graf ports and PlotIconID only if both are true
+// Otherwise we use B&W grafport and draw using PlotBWIcon.
diff --git a/mDNSMacOS9/ShowInitIcon.h b/mDNSMacOS9/ShowInitIcon.h
new file mode 100755 (executable)
index 0000000..cbf680c
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef __ShowInitIcon__
+#define __ShowInitIcon__
+
+#include <Types.h>
+
+// Usage: pass the ID of your icon family (ICN#/icl4/icl8) to have it drawn in the right spot.
+// If 'advance' is true, the next INIT icon will be drawn to the right of your icon. If it is false, the next INIT icon will overwrite
+// yours. You can use it to create animation effects by calling ShowInitIcon several times with 'advance' set to false.
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+pascal void ShowInitIcon (short iconFamilyID, Boolean advance);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __ShowInitIcon__ */
index dc4932a6665e1c78f31d5268727305f885a66db4..fdf6c0ee07628c8364217bfda06a1fbd5bcedd03 100644 (file)
Binary files a/mDNSMacOS9/mDNS.mcp and b/mDNSMacOS9/mDNS.mcp differ
diff --git a/mDNSMacOS9/mDNSLibrary.c b/mDNSMacOS9/mDNSLibrary.c
new file mode 100644 (file)
index 0000000..a8ac4a9
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+
+$Log: mDNSLibrary.c,v $
+Revision 1.1  2004/03/12 21:30:26  cheshire
+Build a System-Context Shared Library from mDNSCore, for the benefit of developers
+like Muse Research who want to be able to use mDNS/DNS-SD from GPL-licensed code.
+
+ */
+
+// Define the required CFM Shared Library entry and exit points
+#include <CodeFragments.h>
+#include "mDNSClientAPI.h"                             // Defines the interface to the client layer above
+#include "mDNSMacOS9.h"                                        // Defines the specific types needed to run mDNS on this platform
+
+mDNS mDNSStorage;
+static mDNS_PlatformSupport PlatformSupportStorage;
+#define RR_CACHE_SIZE 64
+static CacheRecord rrcachestorage[RR_CACHE_SIZE];
+
+mDNSlocal void mDNS_StatusCallback(mDNS *const m, mStatus result)
+       {
+       if (result == mStatus_GrowCache)
+               {
+               // If we've run out of cache space, then double the total cache size and give the memory to mDNSCore
+               mDNSu32 numrecords = m->rrcache_size;
+               CacheRecord *storage = OTAllocMem(sizeof(CacheRecord) * numrecords);
+               LogMsg("mStatus_GrowCache %d", numrecords);
+               if (storage) mDNS_GrowCache(m, storage, numrecords);
+               }
+       }
+
+extern pascal OSErr mDNS_CFMInit(const CFragInitBlock *theInitBlock);
+pascal OSErr mDNS_CFMInit(const CFragInitBlock *theInitBlock)
+       {
+       extern pascal OSErr __initialize(const CFragInitBlock *theInitBlock);
+       __initialize(theInitBlock);     // MUST do this first!
+               {
+               mStatus err;
+               THz oldZone = GetZone();
+               SetZone(SystemZone());
+               LogMsg("mDNS/DNS-SD with Macsbug breaks -- do not ship this version to customers");
+               err = mDNS_Init(&mDNSStorage, &PlatformSupportStorage, rrcachestorage, RR_CACHE_SIZE,
+                       mDNS_Init_AdvertiseLocalAddresses, mDNS_StatusCallback, mDNS_Init_NoInitCallbackContext);
+               SetZone(oldZone);
+               return((OSErr)err);
+               }
+       }
+       
+extern void mDNS_CFMTerm(void);
+void mDNS_CFMTerm(void)
+       {
+       extern pascal void  __terminate(void);
+       LogMsg("mDNS_CFMTerm");
+       mDNS_Close(&mDNSStorage);
+       __terminate();
+       }
diff --git a/mDNSMacOS9/mDNSLibraryLoader.c b/mDNSMacOS9/mDNSLibraryLoader.c
new file mode 100644 (file)
index 0000000..c708eac
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+
+$Log: mDNSLibraryLoader.c,v $
+Revision 1.1  2004/03/12 21:30:26  cheshire
+Build a System-Context Shared Library from mDNSCore, for the benefit of developers
+like Muse Research who want to be able to use mDNS/DNS-SD from GPL-licensed code.
+
+ */
+
+#include <Resources.h>
+#include <CodeFragments.h>
+#include "ShowInitIcon.h"
+
+extern pascal OSErr FragRegisterFileLibs(ConstFSSpecPtr fss, Boolean unregister);
+
+extern void main(void)
+       {
+       OSStatus err;
+       FCBPBRec fcbPB;
+       FSSpec fss;
+
+       // 1. Show our "icon march" icon
+       ShowInitIcon(128, true);
+
+       // 2. Find our FSSpec
+       fss.name[0] = 0;
+       fcbPB.ioNamePtr = fss.name;
+       fcbPB.ioVRefNum = 0;
+       fcbPB.ioRefNum = (short)CurResFile();
+       fcbPB.ioFCBIndx = 0;
+       err = PBGetFCBInfoSync(&fcbPB);
+
+       // 3. Tell CFM that we're a CFM library container file  
+       fss.vRefNum = fcbPB.ioFCBVRefNum;
+       fss.parID = fcbPB.ioFCBParID;
+       if (err == noErr) err = FragRegisterFileLibs(&fss, false);
+
+       // 4. Now that CFM knows we're a library container, tell it to go and get our library
+       if (err == noErr)
+               {
+               CFragConnectionID c;
+               Ptr m;
+               Str255 e;
+               THz oldZone = GetZone();
+               SetZone(SystemZone());
+               err = GetSharedLibrary("\pDarwin;mDNS", kPowerPCCFragArch, kLoadCFrag, &c, &m, e);
+               SetZone(oldZone);
+               }
+       }
+
+// There's no CFM stub library for the FragRegisterFileLibs() call, so we'll make our own
+#if __ide_target("FragRegisterFileLibsStub")
+#pragma export on
+pascal OSErr FragRegisterFileLibs(ConstFSSpecPtr fss, Boolean unregister)
+       {
+       (void)fss;                      // Unused
+       (void)unregister;       // Unused
+       return(0);
+       }
+#endif
diff --git a/mDNSMacOS9/mDNSLibraryResources.r b/mDNSMacOS9/mDNSLibraryResources.r
new file mode 100644 (file)
index 0000000..c77311c
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+ * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+
+$Log: mDNSLibraryResources.r,v $
+Revision 1.4  2004/06/10 20:28:16  cheshire
+Update version string to 1.0a66
+
+Revision 1.3  2004/06/05 00:37:12  cheshire
+Update version string to 1.0a65
+
+Revision 1.2  2004/05/27 06:24:21  cheshire
+Update version string to 1.0a64
+
+Revision 1.1  2004/03/12 21:30:26  cheshire
+Build a System-Context Shared Library from mDNSCore, for the benefit of developers
+like Muse Research who want to be able to use mDNS/DNS-SD from GPL-licensed code.
+
+ */
+
+#ifndef __TYPES.R__
+#include "Types.r"
+#endif
+
+/* Format is :
+ * Two-char BCD major version (0-99)
+ * One-char BCD minor version, One-char BCD bugfix version (0-9, 0-9)
+ * development/alpha/beta/final
+ * One-byte non-final build number (0-255)
+ * Version numbers can therefore range from 0.0.0 to 99.9.9,
+ * with a following build stage and build number (e.g. 2.0.1 beta 219)
+ */
+
+resource 'vers' (1, purgeable)
+       {
+   0x01, 0x00, alpha, 66, verUS,
+   "1.0a66",
+   "Multicast DNS & DNS Service Discovery 1.0a66"
+       };
+
+resource 'vers' (2, purgeable)
+       {
+   0x01, 0x00, alpha, 66, verUS,
+   "1.0a66",
+   "developer.apple.com/darwin/projects/rendezvous/"
+       };
+
+/* We need to load OT, so make sure the system heap has enough space for it */
+type 'sysz' { longint; };
+resource 'sysz' (0, purgeable) { 2500000 };
+
+resource 'BNDL' (128, purgeable, protected) {
+       'mDNS',
+       0,
+       {       /* array TypeArray: 2 elements */
+               /* [1] */
+               'FREF',
+               {       /* array IDArray: 1 elements */
+                       /* [1] */
+                       0, 128
+               },
+               /* [2] */
+               'ICN#',
+               {       /* array IDArray: 1 elements */
+                       /* [1] */
+                       0, 128
+               }
+       }
+};
+
+resource 'FREF' (128, purgeable, protected) {
+       'INIT',
+       0,
+       ""
+};
+
+resource 'icl8' (128, purgeable, protected) {
+       $"FDFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF"
+       $"FFFF FFFF FFFF FFFF FFFF FFFF FD00 0000"
+       $"FF00 0000 0000 0000 0000 0000 0000 0000"
+       $"0000 0000 0000 0000 0000 00F6 FF00 0000"
+       $"FF00 F6F6 F6F6 F6F6 F6F6 F6F6 F6F6 F6F6"
+       $"F6F6 F6F6 F6F6 F6F6 F6F6 F6F9 FF00 0000"
+       $"FF00 F6F6 F6F6 F6F6 F6F6 F6F6 F6F6 F6F6"
+       $"F6F6 F6F6 F6F6 F6F6 F6F6 F6F9 FD00 0000"
+       $"FF00 F6F6 F6F6 F6F6 F6F6 F6F6 F6F6 F6F6"
+       $"F6F6 F6F6 F6F6 F6F6 F6F6 F6F9 FE00 0000"
+       $"FF00 F6F6 F6F6 F6F6 F62B 07F6 F6F6 F6F6"
+       $"F6F6 F6F6 F6F6 F6F6 F6F6 F6F9 FE00 0000"
+       $"FF00 F6F6 F6F6 F6F6 3A16 402B F7F6 F6F6"
+       $"F6F6 F656 F9F9 F956 2BF6 F6F9 FE00 0000"
+       $"FF00 F6F6 F6F6 2B08 4116 4008 F8FA 2BF6"
+       $"F6F7 FAFA FA81 FAFA FAF7 F6F9 FE00 0000"
+       $"FF00 F9F6 F62B F92B 163A 172B F881 FAF6"
+       $"2BF8 F6F6 2BF7 8181 FA81 F6F9 FE00 FD00"
+       $"FF00 FFF9 F6F9 F9F8 2B2C 2BF6 F6F6 F8FA"
+       $"2BF6 F6F6 F6F6 F781 F956 F8F9 FEFD FFFD"
+       $"FFFF 00FE F5FA FA81 F7F6 F6F6 F6F6 F656"
+       $"56F6 F6F6 F6F6 F62B 2B2B F6F9 FEFF 00FF"
+       $"0000 00FF F5FA FAFA F6F6 F6F6 F6F6 2BF6"
+       $"F7F8 F6F6 F6F6 F607 3A16 39F9 FF00 F9FF"
+       $"0000 00FF 00FA 81FA F6F6 F6F6 F62B 2BF6"
+       $"F6F8 F6F6 F6F6 F633 1C3B 1CF6 F6F6 F9FF"
+       $"0000 00FE 0056 81FA F6F6 F6F6 F6F8 F6F6"
+       $"F6F6 F8F6 F6F6 F62C 163A 3AF6 F6F6 F9FF"
+       $"0000 00FE 00F6 8181 2BF6 F6F6 F72B F6F6"
+       $"F6F6 F62B F6F6 2B2B 2C32 F6F6 F6F6 F9FF"
+       $"0000 00FE 00F6 2BFA 81F6 F6F6 F9F6 F6F6"
+       $"F6F6 F62B F6F7 FA81 F8F6 F6F6 F6F6 F9FF"
+       $"0000 00FE 00F6 F6F6 F7F9 F72B F9F6 F6F6"
+       $"F62B F756 F9FA F9F7 F6F6 F6F6 F6F6 F9FF"
+       $"0000 00FE 00F6 F6F6 F6F6 F6F9 F82B 2BF7"
+       $"F7F7 F72B F8F6 F6F6 F6F6 F6F6 F6F6 F9FF"
+       $"0000 00FE 00F6 F6F6 F6F6 F681 2BF6 F6F6"
+       $"F6F6 F6F6 F7F6 F6F6 F6F6 F6F6 F6F6 F9FF"
+       $"0000 00FE 00F6 F6F6 F6F6 2B81 F7F6 F6F6"
+       $"F6F6 F6F6 562B F6F6 F6F6 F6F6 F9F6 F9FF"
+       $"0000 00FE 00F6 F6F6 F6F6 F7FB F7F6 F6F6"
+       $"F6F6 F6F6 FAF7 F6F6 F6F6 F6F9 FEF9 F9FF"
+       $"FFFF 00FE 00F6 F6F6 F6F6 F7F7 2BF6 F6F6"
+       $"F6F6 F6F8 81F7 F6F6 F6F6 F6F9 FEFF F9FF"
+       $"FF00 FF00 00F6 F6F6 F6F6 F60E 3A16 32F6"
+       $"F6F6 56FA 812B F6F6 F6F6 F6F9 FEFD FFFD"
+       $"FF00 0000 F6F6 F6F6 F6F6 F640 1640 16F6"
+       $"F9F9 FA81 F9F6 F6F6 F6F6 F6F9 FE00 FD00"
+       $"FF00 F6F6 F6F6 F6F6 F6F6 F633 173A 332B"
+       $"FAFA 8181 2BF6 F6F6 F6F6 F6F9 FE00 0000"
+       $"FF00 F6F6 F6F6 F6F6 F6F6 F6F6 3232 F6F9"
+       $"8181 FA2B F6F6 F6F6 F6F6 F6F9 FE00 0000"
+       $"FF00 F6F6 F6F6 F6F6 F6F6 F6F6 F6F6 2BF8"
+       $"F82B F6F6 F6F6 F6F6 F6F6 F6F9 FE00 0000"
+       $"FF00 F6F6 F6F6 F6F6 F6F6 F6F6 F6F6 F6F6"
+       $"F6F6 F6F6 F6F6 F6F6 F6F6 F6F9 FE00 0000"
+       $"FF00 F6F6 F6F6 F6F6 F6F6 F6F6 F6F6 F6F6"
+       $"F6F6 F6F6 F6F6 F6F6 F6F6 F6F9 FD00 0000"
+       $"FF00 F6F6 F6F6 F6F6 F6F6 F6F6 F6F6 F6F6"
+       $"F6F6 F6F6 F6F6 F6F6 F6F6 F6F9 FF00 0000"
+       $"FFF6 F9F9 F9F9 F9F9 F9F9 F9F9 F9F9 F9F9"
+       $"F9F9 F9F9 F9F9 F9F9 F9F9 F9F9 FF00 0000"
+       $"FDFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF"
+       $"FFFF FFFF FFFF FFFF FFFF FFFF FD"
+};
+
+data 'mDNS' (0, "Owner resource") {
+       $"0644 6172 7769 6E"                                  /* .Darwin */
+};
+
+resource 'ICN#' (128) {
+       {       /* array: 2 elements */
+               /* [1] */
+               $"FFFF FFF8 8000 0008 8000 0008 8000 0008"
+               $"8000 0008 80E0 0408 81FC 3F88 83FE 7FC8"
+               $"87FF EFEA A7E3 83EF D781 81ED 1F02 C1E9"
+               $"1706 61F1 1704 21E1 178C 33C1 13C8 1781"
+               $"10F8 FF01 101F F801 1018 0801 1038 0C01"
+               $"1038 0C09 D03C 1C0D A01E 7C0F 801F F80A"
+               $"801F F808 800F F008 8003 C008 8000 0008"
+               $"8000 0008 8000 0008 8000 0008 FFFF FFF8",
+               /* [2] */
+               $"FFFF FFF8 FFFF FFF8 FFFF FFF8 FFFF FFF8"
+               $"FFFF FFF8 FFFF FFF8 FFFF FFF8 FFFF FFF8"
+               $"FFFF FFFA FFFF FFFF DFFF FFFF 1FFF FFFF"
+               $"1FFF FFFF 1FFF FFFF 1FFF FFFF 1FFF FFFF"
+               $"1FFF FFFF 1FFF FFFF 1FFF FFFF 1FFF FFFF"
+               $"1FFF FFFF DFFF FFFF FFFF FFFF FFFF FFFA"
+               $"FFFF FFF8 FFFF FFF8 FFFF FFF8 FFFF FFF8"
+               $"FFFF FFF8 FFFF FFF8 FFFF FFF8 FFFF FFF8"
+       }
+};
+
+resource 'ics#' (128, purgeable) {
+       {       /* array: 2 elements */
+               /* [1] */
+               $"FFFE 8002 8002 8C02 DE73 D19B 5299 5451"
+               $"4C61 47C1 C443 C483 8702 8302 8002 FFFE",
+               /* [2] */
+               $"FFFE FFFE FFFE FFFE FFFF FFFF 7FFF 7FFF"
+               $"7FFF 7FFF FFFF FFFF FFFE FFFE FFFE FFFE"
+       }
+};
+
+resource 'ics8' (128) {
+       $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FF00"
+       $"FFF6 F6F6 F6F6 F6F6 F6F6 F6F6 F6F6 FD00"
+       $"FFF6 F6F6 32F6 F6F6 F6F6 F7F7 F6F6 FF00"
+       $"FFF6 F632 2233 81F6 2B56 81AC FBF6 FF00"
+       $"FFFE FAF9 2CF6 2BFA 2BF6 F6F8 FAF8 FEFF"
+       $"FFFD FCFA F6F6 F62B F8F6 F6F6 3333 FEFF"
+       $"00FE 81F9 F6F6 2BF6 F62B F6F6 4040 F6FF"
+       $"00FF 2BFB 2BF6 F7F6 F62B F6F9 32F6 F6FF"
+       $"00FE F6F6 F7F8 F7F6 2BF8 56F8 F6F6 F6FF"
+       $"00FE F6F6 F6FA F6F6 F6F6 F7F6 F6F6 F6FF"
+       $"FFFE F6F6 F6FA 2BF6 F6F6 FAF6 F6F6 FEFF"
+       $"FFFE F6F6 F632 3AF6 2BF9 81F6 F6F6 FEFF"
+       $"FFF6 F6F6 F632 4632 FCAC F7F6 F6F6 FE00"
+       $"FFF6 F6F6 F6F6 F6F8 562B F6F6 F6F6 FE00"
+       $"FFF6 F6F6 F6F6 F6F6 F6F6 F6F6 F6F6 FE00"
+       $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FF"
+};
+
index cdb49b36bdcb67e13f3b34e64843618181f20e23..65631125b8202498b04dc588a6716aa6b56f72a8 100644 (file)
@@ -3,6 +3,8 @@
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
     Change History (most recent first):
 
 $Log: mDNSMacOS9.c,v $
+Revision 1.29  2004/05/26 20:53:16  cheshire
+Remove unncecessary "return( -1 );" at the end of mDNSPlatformUTC()
+
+Revision 1.28  2004/05/20 18:39:06  cheshire
+Fix build broken by addition of mDNSPlatformUTC requirement
+
+Revision 1.27  2004/04/21 02:49:11  cheshire
+To reduce future confusion, renamed 'TxAndRx' to 'McastTxRx'
+
+Revision 1.26  2004/04/09 17:43:03  cheshire
+Make sure to set the McastTxRx field so that duplicate suppression works correctly
+
+Revision 1.25  2004/03/15 18:55:38  cheshire
+Comment out debugging message
+
+Revision 1.24  2004/03/12 21:30:26  cheshire
+Build a System-Context Shared Library from mDNSCore, for the benefit of developers
+like Muse Research who want to be able to use mDNS/DNS-SD from GPL-licensed code.
+
+Revision 1.23  2004/02/09 23:24:43  cheshire
+Need to set TTL 255 to interoperate with peers that check TTL (oops!)
+
+Revision 1.22  2004/01/27 20:15:23  cheshire
+<rdar://problem/3541288>: Time to prune obsolete code for listening on port 53
+
+Revision 1.21  2004/01/24 04:59:16  cheshire
+Fixes so that Posix/Linux, OS9, Windows, and VxWorks targets build again
+
+Revision 1.20  2003/11/14 20:59:09  cheshire
+Clients can't use AssignDomainName macro because mDNSPlatformMemCopy is defined in mDNSPlatformFunctions.h.
+Best solution is just to combine mDNSClientAPI.h and mDNSPlatformFunctions.h into a single file.
+
 Revision 1.19  2003/08/18 23:09:20  cheshire
 <rdar://problem/3382647> mDNSResponder divide by zero in mDNSPlatformTimeNow()
 
@@ -31,15 +65,14 @@ Update to APSL 2.0
 
  */
 
+#include <stdio.h>
+#include <stdarg.h>                                            // For va_list support
+
 #include <LowMem.h>                                            // For LMGetCurApName()
 #include <TextUtils.h>                                 // For smSystemScript
 #include <UnicodeConverter.h>                  // For ConvertFromPStringToUnicode()
 
-#include <stdio.h>
-#include <stdarg.h>                                            // For va_list support
-
 #include "mDNSClientAPI.h"                             // Defines the interface provided to the client layer above
-#include "mDNSPlatformFunctions.h"             // Defines the interface to the supporting layer below
 
 #include "mDNSMacOS9.h"                                        // Defines the specific types needed to run mDNS on this platform
 
@@ -47,17 +80,29 @@ Update to APSL 2.0
 // Constants
 
 static const TSetBooleanOption kReusePortOption =
-       { sizeof(TSetBooleanOption),      INET_IP, IP_REUSEPORT,      0, true };
+       { kOTBooleanOptionSize,          INET_IP, IP_REUSEPORT,      0, true };
+
+// IP_RCVDSTADDR with TSetByteOption/kOTOneByteOptionSize works on OS 9, OS X Classic, and OS 9 Carbon,
+// but gives error #-3151 (kOTBadOptionErr) on OS X Carbon.
+// If we instead use TSetBooleanOption/kOTBooleanOptionSize then OTOptionManagement on OS X Carbon
+// no longer returns -3151 but it still doesn't actually work -- no destination addresses
+// are delivered by OTRcvUData. I think it's just a bug in OS X Carbon.
+static const TSetByteOption kRcvDestAddrOption =
+       { kOTOneByteOptionSize,          INET_IP, IP_RCVDSTADDR,     0, true };
+//static const TSetBooleanOption kRcvDestAddrOption =
+//     { kOTBooleanOptionSize,          INET_IP, IP_RCVDSTADDR,     0, true };
 
-// IP_RCVDSTADDR gives error #-3151 (kOTBadOptionErr)
-static const TSetBooleanOption kRcvDestAddrOption =
-       { sizeof(TSetBooleanOption),      INET_IP, IP_REUSEPORT,     0, true };
+static const TSetByteOption kSetUnicastTTLOption =
+       { kOTOneByteOptionSize,          INET_IP, IP_TTL,            0, 255 };
+
+static const TSetByteOption kSetMulticastTTLOption =
+       { kOTOneByteOptionSize,          INET_IP, IP_MULTICAST_TTL,  0, 255 };
 
 static const TIPAddMulticastOption kAddLinkMulticastOption  =
        { sizeof(TIPAddMulticastOption), INET_IP, IP_ADD_MEMBERSHIP, 0, { 224,  0,  0,251 }, { 0,0,0,0 } };
 
-static const TIPAddMulticastOption kAddAdminMulticastOption =
-       { sizeof(TIPAddMulticastOption), INET_IP, IP_ADD_MEMBERSHIP, 0, { 239,255,255,251 }, { 0,0,0,0 } };
+//static const TIPAddMulticastOption kAddAdminMulticastOption =
+//     { sizeof(TIPAddMulticastOption), INET_IP, IP_ADD_MEMBERSHIP, 0, { 239,255,255,251 }, { 0,0,0,0 } };
 
 // Bind endpoint to port number. Don't specify any specific IP address --
 // we want to receive unicasts on all interfaces, as well as multicasts.
@@ -72,6 +117,14 @@ static const TNetbuf zeroTNetbuf = { 0 };
 // ***************************************************************************
 // Functions
 
+mDNSlocal void SafeDebugStr(unsigned char *buffer)
+       {
+       int i;
+       // Don't want semicolons in MacsBug messages -- they signify commands to execute
+       for (i=1; i<= buffer[0]; i++) if (buffer[i] == ';') buffer[i] = '.';
+       DebugStr(buffer);
+       }
+
 #if MDNS_DEBUGMSGS
 mDNSexport void debugf_(const char *format, ...)
        {
@@ -80,16 +133,21 @@ mDNSexport void debugf_(const char *format, ...)
        va_start(ptr,format);
        buffer[0] = (unsigned char)mDNS_vsnprintf((char*)buffer+1, 255, format, ptr);
        va_end(ptr);
-#if __ONLYSYSTEMTASK__
+#if MDNS_ONLYSYSTEMTASK
        buffer[1+buffer[0]] = 0;
        fprintf(stderr, "%s\n", buffer+1);
        fflush(stderr);
 #else
-       DebugStr(buffer);
+       SafeDebugStr(buffer);
 #endif
        }
 #endif
 
+#if MDNS_BUILDINGSHAREDLIBRARY >= 2
+// When building the non-debug version of the Extension, intended to go on end-user systems, we don't want
+// MacsBug breaks for *anything*, not even for the serious LogMsg messages that on OS X would be written to syslog
+mDNSexport void LogMsg(const char *format, ...) { (void)format; }
+#else
 mDNSexport void LogMsg(const char *format, ...)
        {
        unsigned char buffer[256];
@@ -97,24 +155,27 @@ mDNSexport void LogMsg(const char *format, ...)
        va_start(ptr,format);
        buffer[0] = (unsigned char)mDNS_vsnprintf((char*)buffer+1, 255, format, ptr);
        va_end(ptr);
-#if __ONLYSYSTEMTASK__
+#if MDNS_ONLYSYSTEMTASK
        buffer[1+buffer[0]] = 0;
        fprintf(stderr, "%s\n", buffer+1);
        fflush(stderr);
 #else
-       DebugStr(buffer);
+       SafeDebugStr(buffer);
 #endif
        }
+#endif
 
 mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end,
-       mDNSInterfaceID InterfaceID, mDNSIPPort srcPort, const mDNSAddr *dst, mDNSIPPort dstPort)
+       mDNSInterfaceID InterfaceID, const mDNSAddr *dst, mDNSIPPort dstPort)
        {
        // Note: If we did multi-homing, we'd have to use the InterfaceID parameter to specify from which interface to send this response
-       #pragma unused(InterfaceID, srcPort)
+       #pragma unused(InterfaceID)
 
        InetAddress InetDest;
        TUnitData senddata;
        
+       if (dst->type != mDNSAddrType_IPv4) return(mStatus_NoError);
+
        InetDest.fAddressType = AF_INET;
        InetDest.fPort        = dstPort.NotAnInteger;
        InetDest.fHost        = dst->ip.v4.NotAnInteger;
@@ -136,7 +197,7 @@ mDNSlocal OSStatus readpacket(mDNS *m)
        mDNSInterfaceID interface;
        mDNSIPPort senderport;
        InetAddress sender;
-       char options[512];
+       char options[256];
        DNSMessage packet;
        TUnitData recvdata;
        OTFlags flags = 0;
@@ -160,11 +221,28 @@ mDNSlocal OSStatus readpacket(mDNS *m)
        senderaddr.type = mDNSAddrType_IPv4;
        senderaddr.ip.v4.NotAnInteger = sender.fHost;
        senderport.NotAnInteger = sender.fPort;
+       
        destaddr.type = mDNSAddrType_IPv4;
-       destaddr.ip.v4  = AllDNSLinkGroup;              // For now, until I work out how to get the dest address, assume it was sent to AllDNSLinkGroup
+       destaddr.ip.v4  = zeroIPAddr;
+
+       #if OTCARBONAPPLICATION
+       // IP_RCVDSTADDR is known to fail on OS X Carbon, so we'll just assume the packet was probably multicast
+       destaddr.ip.v4  = AllDNSLinkGroup;
+       #endif
+
+       if (recvdata.opt.len)
+               {
+               TOption *c = nil;
+               while (1)
+                       {
+                       err = OTNextOption(recvdata.opt.buf, recvdata.opt.len, &c);
+                       if (err || !c) break;
+                       if (c->level == INET_IP && c->name == IP_RCVDSTADDR && c->len - kOTOptionHeaderSize == sizeof(destaddr.ip.v4))
+                               mDNSPlatformMemCopy(c->value, &destaddr.ip.v4, sizeof(destaddr.ip.v4));
+                       }
+               }
+
        interface = m->HostInterfaces->InterfaceID;
-       
-       if (recvdata.opt.len) debugf("readpacket: got some option data at %X, len %d", options, recvdata.opt.len);
 
        if      (flags & T_MORE)                                debugf("ERROR: OTRcvUData() buffer too small (T_MORE set)");
        else if (recvdata.addr.len < sizeof(InetAddress))       debugf("ERROR: recvdata.addr.len (%d) too short", recvdata.addr.len);
@@ -174,15 +252,51 @@ mDNSlocal OSStatus readpacket(mDNS *m)
        return(err);
        }
 
+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 int mDNSPlatformReadTCP(int sd, void *buf, int buflen)
+       {
+       (void)sd;                       // Unused
+       (void)buf;                      // Unused
+       (void)buflen;           // Unused
+       return(0);
+       }
+
+mDNSexport int mDNSPlatformWriteTCP(int sd, const char *msg, int len)
+       {
+       (void)sd;                       // Unused
+       (void)msg;                      // Unused
+       (void)len;                      // Unused
+       return(0);
+       }
 
 mDNSlocal void mDNSOptionManagement(mDNS *const m)
        {
        OSStatus err;
 
        // Make sure the length in the TNetbuf agrees with the length in the TOptionHeader
-       m->p->optReq.opt.len = m->p->optBlock.h.len;
+       m->p->optReq.opt.len    = m->p->optBlock.h.len;
+       m->p->optReq.opt.maxlen = m->p->optBlock.h.len;
+       if (m->p->optReq.opt.maxlen < 4)
+               m->p->optReq.opt.maxlen = 4;
+
        err = OTOptionManagement(m->p->ep, &m->p->optReq, NULL);
-       if (err) debugf("OTOptionManagement failed %d", err);
+       if (err) LogMsg("OTOptionManagement failed %d", err);
        }
 
 mDNSlocal void mDNSinitComplete(mDNS *const m, mStatus result)
@@ -201,50 +315,63 @@ mDNSlocal pascal void mDNSNotifier(void *contextPtr, OTEventCode code, OTResult
                        {
                        OSStatus err;
                        InetInterfaceInfo interfaceinfo;
-                       if (result) { debugf("T_OPENCOMPLETE failed %d", result); mDNSinitComplete(m, result); return; }
+                       if (result) { LogMsg("T_OPENCOMPLETE failed %d", result); mDNSinitComplete(m, result); return; }
                        //debugf("T_OPENCOMPLETE");
                        m->p->ep = (EndpointRef)cookie;
                        //debugf("OTInetGetInterfaceInfo");
                        // (In future may want to loop over all interfaces instead of just using kDefaultInetInterface)
                        err = OTInetGetInterfaceInfo(&interfaceinfo, kDefaultInetInterface);
-                       if (err) { debugf("OTInetGetInterfaceInfo failed %d", err); mDNSinitComplete(m, err); return; }
+                       if (err) { LogMsg("OTInetGetInterfaceInfo failed %d", err); mDNSinitComplete(m, err); return; }
 
                        // Make our basic standard host resource records (address, PTR, etc.)
+                       m->p->interface.InterfaceID           = (mDNSInterfaceID)&m->p->interface;
                        m->p->interface.ip.type               = mDNSAddrType_IPv4;
                        m->p->interface.ip.ip.v4.NotAnInteger = interfaceinfo.fAddress;
                        m->p->interface.Advertise             = m->AdvertiseLocalAddresses;
-                       m->p->interface.InterfaceID           = (mDNSInterfaceID)&m->p->interface;
-                       mDNS_RegisterInterface(m, &m->p->interface);
+                       m->p->interface.McastTxRx             = mDNStrue;
                        }
                        
                case T_OPTMGMTCOMPLETE:
-                       if (result) { debugf("T_OPTMGMTCOMPLETE failed %d", result); mDNSinitComplete(m, result); return; }
-                       //debugf("T_OPTMGMTCOMPLETE");
+               case T_BINDCOMPLETE:
+                       // IP_RCVDSTADDR is known to fail on OS X Carbon, so we don't want to abort for that error
+                       // (see comment above at the definition of kRcvDestAddrOption)
+                       #if OTCARBONAPPLICATION
+                       if (result && m->p->mOTstate == mOT_RcvDestAddr)
+                               LogMsg("Carbon IP_RCVDSTADDR option failed %d; continuing anyway", result);
+                       else
+                       #endif
+                       if (result) { LogMsg("T_OPTMGMTCOMPLETE/T_BINDCOMPLETE %d failed %d", m->p->mOTstate, result); mDNSinitComplete(m, result); return; }
+                       //LogMsg("T_OPTMGMTCOMPLETE/T_BINDCOMPLETE %d", m->p->mOTstate);
                        switch (++m->p->mOTstate)
                                {
                                case mOT_ReusePort:             m->p->optBlock.b = kReusePortOption;         mDNSOptionManagement(m); break;
-                               case mOT_RcvDestAddr:   m->p->optBlock.b = kRcvDestAddrOption;       mDNSOptionManagement(m); break;
+                               case mOT_RcvDestAddr:   m->p->optBlock.i = kRcvDestAddrOption;       mDNSOptionManagement(m); break;
+                               case mOT_SetUTTL:               m->p->optBlock.i = kSetUnicastTTLOption;     mDNSOptionManagement(m); break;
+                               case mOT_SetMTTL:               m->p->optBlock.i = kSetMulticastTTLOption;   mDNSOptionManagement(m); break;
                                case mOT_LLScope:               m->p->optBlock.m = kAddLinkMulticastOption;  mDNSOptionManagement(m); break;
-                               case mOT_AdminScope:    m->p->optBlock.m = kAddAdminMulticastOption; mDNSOptionManagement(m); break;
+//                             case mOT_AdminScope:    m->p->optBlock.m = kAddAdminMulticastOption; mDNSOptionManagement(m); break;
                                case mOT_Bind:                  OTBind(m->p->ep, (TBind*)&mDNSbindReq, NULL); break;
+                               case mOT_Ready:         mDNSinitComplete(m, mStatus_NoError);
+                                                                               // Can't do mDNS_RegisterInterface until *after* mDNSinitComplete has set m->mDNSPlatformStatus to mStatus_NoError
+                                                                               mDNS_RegisterInterface(m, &m->p->interface);
+                                                                               break;
+                               default:                LogMsg("Unexpected m->p->mOTstate %d", m->p->mOTstate-1);
                                }
                        break;
 
-               case T_BINDCOMPLETE:
-                       if (result) { debugf("T_BINDCOMPLETE failed %d", result); return; }
-                       if (m->p->mOTstate != mOT_Bind) { debugf("T_BINDCOMPLETE in wrong mDNS state %d", m->p->mOTstate); return; }
-                       m->p->mOTstate++;
-                       //debugf("T_BINDCOMPLETE");
-                       mDNSinitComplete(m, mStatus_NoError);
-                       break;
-
                case T_DATA:
                        //debugf("T_DATA");
                        while (readpacket(m) == kOTNoError) continue;   // Read packets until we run out
                        break;
 
-               case kOTProviderWillClose:
+               case kOTProviderWillClose: LogMsg("kOTProviderWillClose"); break;
                case kOTProviderIsClosed:               // Machine is going to sleep, shutting down, or reconfiguring IP
+                       LogMsg("kOTProviderIsClosed");
+                       if (m->p->mOTstate == mOT_Ready)
+                               {
+                               m->p->mOTstate = mOT_Closed;
+                               mDNS_DeregisterInterface(m, &m->p->interface);
+                               }
                        if (m->p->ep) { OTCloseProvider(m->p->ep); m->p->ep = NULL; }
                        break;                                          // Do we need to do anything?
 
@@ -253,7 +380,7 @@ mDNSlocal pascal void mDNSNotifier(void *contextPtr, OTEventCode code, OTResult
                }
        }
 
-#if __ONLYSYSTEMTASK__
+#if MDNS_ONLYSYSTEMTASK
 
 static Boolean     ONLYSYSTEMTASKevent;
 static void       *ONLYSYSTEMTASKcontextPtr;
@@ -275,22 +402,17 @@ mDNSlocal pascal void CallmDNSNotifier(void *contextPtr, OTEventCode code, OTRes
        {
        mDNS *const m = (mDNS *const)contextPtr;
        if (!m) debugf("mDNSNotifier FATAL ERROR! No context");
-       
-       // Increment m->p->nesting to indicate to mDNSPlatformLock that there's no need
-       // to call OTEnterNotifier() (because we're already in OTNotifier context)
-       if (m->p->nesting) DebugStr("\pCallmDNSNotifier ERROR! OTEnterNotifier is supposed to suppress notifier callbacks");
-       m->p->nesting++;
+       if (m->p->nesting) LogMsg("CallmDNSNotifier ERROR! OTEnterNotifier is supposed to suppress notifier callbacks");
        mDNSNotifier(contextPtr, code, result, cookie);
-       m->p->nesting--;
-       ScheduleNextTimerCallback(m);
        }
 
 #endif
 
+static OTNotifyUPP CallmDNSNotifierUPP;
+
 mDNSlocal OSStatus mDNSOpenEndpoint(const mDNS *const m)
        {
        OSStatus err;
-       TEndpointInfo endpointinfo;
        // m->optReq is pre-set to point to the shared m->optBlock
        // m->optBlock is filled in by each OTOptionManagement call
        m->p->optReq.opt.maxlen = sizeof(m->p->optBlock);
@@ -302,14 +424,8 @@ mDNSlocal OSStatus mDNSOpenEndpoint(const mDNS *const m)
        //printf("Opening endpoint now...\n");
        m->p->ep = NULL;
        m->p->mOTstate = mOT_Start;
-//     err = OTAsyncOpenEndpoint(OTCreateConfiguration("udp(RxICMP=1)"), 0, &endpointinfo, CallmDNSNotifier, (void*)m); // works
-//     err = OTAsyncOpenEndpoint(OTCreateConfiguration("udp(RxICMP)"), 0, &endpointinfo, CallmDNSNotifier, (void*)m); // -3151 bad option
-//     err = OTAsyncOpenEndpoint(OTCreateConfiguration("udp,ip(RxICMP=1)"), 0, &endpointinfo, CallmDNSNotifier, (void*)m); // -3151
-//     err = OTAsyncOpenEndpoint(OTCreateConfiguration("udp,ip"), 0, &endpointinfo, CallmDNSNotifier, (void*)m); // works
-//     err = OTAsyncOpenEndpoint(OTCreateConfiguration("udp,rawip"), 0, &endpointinfo, CallmDNSNotifier, (void*)m); // -3221 invalid arg
-       err = OTAsyncOpenEndpoint(OTCreateConfiguration(kUDPName), 0, &endpointinfo, NewOTNotifyUPP(CallmDNSNotifier), (void*)m);
-       if (err) { debugf("ERROR: OTAsyncOpenEndpoint(UDP) failed with error <%d>", err); return(err); }
-       
+       err = OTAsyncOpenEndpoint(OTCreateConfiguration(kUDPName), 0, NULL, CallmDNSNotifierUPP, (void*)m);
+       if (err) { LogMsg("ERROR: OTAsyncOpenEndpoint(UDP) failed with error <%d>", err); return(err); }
        return(kOTNoError);
        }
 
@@ -333,10 +449,23 @@ mDNSlocal pascal void ClientNotifier(void *contextPtr, OTEventCode code, OTResul
 
        switch (code)
                {
-               case xOTStackIsLoading:   break;
-               case xOTStackWasLoaded:   m->mDNSPlatformStatus = mStatus_Waiting; m->p->mOTstate = mOT_Reset; break;
-               case xOTStackIsUnloading: break;
-               case kOTPortNetworkChange: break;
+               case xOTStackIsLoading:         break;
+               case xOTStackWasLoaded:         if (m->p->mOTstate == mOT_Closed)
+                                                                               {
+                                                                               LogMsg("kOTStackWasLoaded: Re-opening endpoint");
+                                                                               if (m->p->ep)
+                                                                                       LogMsg("kOTStackWasLoaded: ERROR: m->p->ep already set");
+                                                                               m->mDNSPlatformStatus = mStatus_Waiting;
+                                                                               m->p->mOTstate = mOT_Reset;
+                                                                               #if !MDNS_ONLYSYSTEMTASK
+                                                                               mDNSOpenEndpoint(m);
+                                                                               #endif
+                                                                               }
+                                                                       else
+                                                                               LogMsg("kOTStackWasLoaded (no action)");
+                                                                       break;
+               case xOTStackIsUnloading:       break;
+               case kOTPortNetworkChange:      break;
                default: debugf("ClientNotifier unknown code %X, %X, %d", contextPtr, code, result); break;
                }
        }
@@ -393,18 +522,20 @@ mDNSlocal void GetUserSpecifiedComputerName(domainlabel *const namelabel)
 
 static pascal void mDNSTimerTask(void *arg)
        {
-#if __ONLYSYSTEMTASK__
+#if MDNS_ONLYSYSTEMTASK
 #pragma unused(arg)
        ONLYSYSTEMTASKevent = true;
 #else
        mDNS *const m = (mDNS *const)arg;
-       // Increment m->p->nesting to indicate to mDNSPlatformLock that there's no need
-       // to call OTEnterNotifier() (because we're already in OTNotifier context)
-       if (m->p->nesting) DebugStr("\pmDNSTimerTask ERROR! OTEnterNotifier is supposed to suppress timer callbacks too");
-       m->p->nesting++;
-       mDNS_Execute(m);
-       m->p->nesting--;
-       ScheduleNextTimerCallback(m);
+       if (!m->p->ep) LogMsg("mDNSTimerTask NO endpoint");
+       if (m->mDNS_busy) LogMsg("mDNS_busy");
+       if (m->p->nesting) LogMsg("mDNSTimerTask ERROR! OTEnterNotifier is supposed to suppress timer callbacks too");
+       
+       // If our timer fires at a time when we have no endpoint, ignore it --
+       // once we reopen our endpoint and get our T_BINDCOMPLETE message we'll call
+       // mDNS_RegisterInterface(), which does a lock/unlock, which retriggers the timer.
+       // Likewise, if m->mDNS_busy or m->p->nesting, we'll catch this on the unlock
+       if (m->p->ep && m->mDNS_busy == 0 && m->p->nesting == 0) mDNS_Execute(m);
 #endif
        }
 
@@ -414,8 +545,22 @@ long sleep, wake, mode;
 
 mDNSexport mStatus mDNSPlatformInit(mDNS *const m)
        {
-       OSStatus err;
+       OSStatus err = InitOpenTransport();
+
+       ClientNotifierContext = m;
+       // Note: OTRegisterAsClient returns kOTNotSupportedErr when running as Carbon code on OS X
+       // -- but that's okay, we don't need a ClientNotifier when running as Carbon code on OS X
+       OTRegisterAsClient(NULL, NewOTNotifyUPP(ClientNotifier));
        
+       m->p->OTTimerTask = OTCreateTimerTask(NewOTProcessUPP(mDNSTimerTask), m);
+       m->p->nesting     = 0;
+
+#if TEST_SLEEP
+       sleep = TickCount() + 600;
+       wake = TickCount() + 1200;
+       mode = 0;
+#endif
+
        // Set up the nice label
        m->nicelabel.c[0] = 0;
        GetUserSpecifiedComputerName(&m->nicelabel);
@@ -429,39 +574,37 @@ mDNSexport mStatus mDNSPlatformInit(mDNS *const m)
 
        mDNS_GenerateFQDN(m);
 
-       ClientNotifierContext = m;
-
-#if !TARGET_API_MAC_CARBON
-       err = OTRegisterAsClient(LMGetCurApName(), NewOTNotifyUPP(ClientNotifier));
-       if (err) debugf("OTRegisterAsClient failed %d", err);
-#endif
-       
+       // When it's finished mDNSOpenEndpoint asynchronously calls mDNSinitComplete() and then mDNS_RegisterInterface()
+       CallmDNSNotifierUPP = NewOTNotifyUPP(CallmDNSNotifier);
        err = mDNSOpenEndpoint(m);
-       if (err) { debugf("mDNSOpenEndpoint failed %d", err); return(err); }
-
-       m->p->OTTimerTask = OTCreateTimerTask(NewOTProcessUPP(mDNSTimerTask), m);
-       m->p->nesting     = 0;
-
-#if TEST_SLEEP
-       sleep = TickCount() + 600;
-       wake = TickCount() + 1200;
-       mode = 0;
-#endif
-
+       if (err)
+               {
+               LogMsg("mDNSOpenEndpoint failed %d", err);
+               if (m->p->OTTimerTask) OTDestroyTimerTask(m->p->OTTimerTask);
+               OTUnregisterAsClient();
+               CloseOpenTransport();
+               }
        return(err);
        }
 
 extern void mDNSPlatformClose (mDNS *const m)
        {
-       if (m->p->OTTimerTask) { OTDestroyTimerTask(m->p->OTTimerTask); m->p->OTTimerTask = 0;    }
+       if (m->p->mOTstate == mOT_Ready)
+               {
+               m->p->mOTstate = mOT_Closed;
+               mDNS_DeregisterInterface(m, &m->p->interface);
+               }
        if (m->p->ep)          { OTCloseProvider   (m->p->ep);          m->p->ep          = NULL; }
+       if (m->p->OTTimerTask) { OTDestroyTimerTask(m->p->OTTimerTask); m->p->OTTimerTask = 0;    }
+
+       OTUnregisterAsClient();
        CloseOpenTransport();
        }
 
+#if MDNS_ONLYSYSTEMTASK
 extern void mDNSPlatformIdle(mDNS *const m);
 mDNSexport void mDNSPlatformIdle(mDNS *const m)
        {
-#if __ONLYSYSTEMTASK__
        while (ONLYSYSTEMTASKcontextPtr)
                {
                void *contextPtr = ONLYSYSTEMTASKcontextPtr;
@@ -473,7 +616,6 @@ mDNSexport void mDNSPlatformIdle(mDNS *const m)
                ONLYSYSTEMTASKevent = false;
                mDNS_Execute(m);
                }
-#endif
 
        if (m->p->mOTstate == mOT_Reset)
                {
@@ -494,42 +636,42 @@ mDNSexport void mDNSPlatformIdle(mDNS *const m)
                                break;
                }
 #endif
-
        }
+#endif
 
 mDNSexport void    mDNSPlatformLock(const mDNS *const m)
        {
        if (!m) { DebugStr("\pmDNSPlatformLock m NULL!"); return; }
        if (!m->p) { DebugStr("\pmDNSPlatformLock m->p NULL!"); return; }
-       if (!m->p->ep) { DebugStr("\pmDNSPlatformLock m->p->ep NULL!"); return; }
 
        // If we try to call OTEnterNotifier and fail because we're already running at
        // Notifier context, then make sure we don't do the matching OTLeaveNotifier() on exit.
-       if (m->p->nesting || OTEnterNotifier(m->p->ep) == false) m->p->nesting++;
+       // If we haven't even opened our endpoint yet, then just increment m->p->nesting for the same reason
+       if (m->p->mOTstate == mOT_Ready && !m->p->ep) DebugStr("\pmDNSPlatformLock: m->p->mOTstate == mOT_Ready && !m->p->ep");
+       if (!m->p->ep || m->p->nesting || OTEnterNotifier(m->p->ep) == false) m->p->nesting++;
        }
 
 mDNSlocal void ScheduleNextTimerCallback(const mDNS *const m)
        {
-       SInt32 interval;
-       interval = m->NextScheduledEvent - mDNSPlatformTimeNow();
-       if      (interval < 0)                 interval = 0;
-       else if (interval > 0x7FFFFFFF / 1000) interval = 0x7FFFFFFF / mDNSPlatformOneSecond;
-       else                                   interval = interval * 1000 / mDNSPlatformOneSecond;
-       //debugf("mDNSPlatformScheduleTask Interval %d", interval);
-       OTScheduleTimerTask(m->p->OTTimerTask, (OTTimeout)interval);
+       if (m->mDNSPlatformStatus == mStatus_NoError)
+               {
+               SInt32 interval = m->NextScheduledEvent - mDNSPlatformTimeNow();
+               if      (interval < 1)                 interval = 1;
+               else if (interval > 0x70000000 / 1000) interval = 0x70000000 / mDNSPlatformOneSecond;
+               else                                   interval = (interval * 1000 + mDNSPlatformOneSecond-1)/ mDNSPlatformOneSecond;
+               OTScheduleTimerTask(m->p->OTTimerTask, (OTTimeout)interval);
+               }
        }
 
 mDNSexport void    mDNSPlatformUnlock(const mDNS *const m)
        {
        if (!m) { DebugStr("\pmDNSPlatformUnlock m NULL!"); return; }
        if (!m->p) { DebugStr("\pmDNSPlatformUnlock m->p NULL!"); return; }
-       if (!m->p->ep) { DebugStr("\pmDNSPlatformUnlock m->p->ep NULL!"); return; }
+
+       if (m->p->ep && m->mDNS_busy == 0) ScheduleNextTimerCallback(m);
+
        if (m->p->nesting) m->p->nesting--;
-       else
-               {
-               ScheduleNextTimerCallback(m);
-               OTLeaveNotifier(m->p->ep);
-               }
+       else OTLeaveNotifier(m->p->ep);
        }
 
 mDNSexport void     mDNSPlatformStrCopy(const void *src,       void *dst)             { OTStrCopy((char*)dst, (char*)src); }
@@ -542,3 +684,17 @@ mDNSexport void     mDNSPlatformMemFree    (void *mem)
 mDNSexport mStatus  mDNSPlatformTimeInit(mDNSs32 *timenow) { *timenow = mDNSPlatformTimeNow(); return(mStatus_NoError); }
 mDNSexport SInt32   mDNSPlatformTimeNow()                                             { return((SInt32)TickCount()); }
 mDNSexport SInt32   mDNSPlatformOneSecond = 60;
+
+mDNSexport mDNSs32     mDNSPlatformUTC(void)
+       {
+       // Classic Mac OS since Midnight, 1st Jan 1904
+       // Standard Unix counts from 1970
+       // This value adjusts for the 66 years and 17 leap-days difference
+       mDNSu32 SecsSince1904;
+       MachineLocation ThisLocation;
+       #define TIME_ADJUST (((1970 - 1904) * 365 + 17) * 24 * 60 * 60)
+       #define ThisLocationGMTdelta ((ThisLocation.u.gmtDelta << 8) >> 8)
+       GetDateTime(&SecsSince1904);
+       ReadLocation(&ThisLocation);
+       return((mDNSs32)(SecsSince1904 - ThisLocationGMTdelta - TIME_ADJUST));
+       }
index d707f9ffbf4bb28c8d4d0bca29b78f9fbc790523..03c7bd5a8ec24f75e9f35891d513042833a6e1c4 100755 (executable)
@@ -3,6 +3,8 @@
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
     Change History (most recent first):
 
 $Log: mDNSMacOS9.h,v $
+Revision 1.10  2004/03/12 21:30:26  cheshire
+Build a System-Context Shared Library from mDNSCore, for the benefit of developers
+like Muse Research who want to be able to use mDNS/DNS-SD from GPL-licensed code.
+
+Revision 1.9  2004/02/09 23:25:35  cheshire
+Need to set TTL 255 to interoperate with peers that check TTL (oops!)
+
 Revision 1.8  2003/08/12 19:56:24  cheshire
 Update to APSL 2.0
 
@@ -31,28 +40,33 @@ Update to APSL 2.0
 // ***************************************************************************
 // Classic Mac (Open Transport) structures
 
+//#include <Files.h>   // OpenTransport.h requires this
 #include <OpenTransport.h>
 #include <OpenTptInternet.h>
 #include <OpenTptClient.h>
 
 typedef enum
        {
-       mOT_Reset = 0,
-       mOT_Start,
-       mOT_ReusePort,
-       mOT_RcvDestAddr,
-       mOT_LLScope,
-       mOT_AdminScope,
-       mOT_Bind,
-       mOT_Ready
+       mOT_Closed = 0,         // We got kOTProviderIsClosed message
+       mOT_Reset,                      // We got xOTStackWasLoaded message
+       mOT_Start,                      // We've called OTAsyncOpenEndpoint
+       mOT_ReusePort,          // Have just done kReusePortOption
+       mOT_RcvDestAddr,        // Have just done kRcvDestAddrOption
+       mOT_SetUTTL,            // Have just done kSetUnicastTTLOption
+       mOT_SetMTTL,            // Have just done kSetMulticastTTLOption
+       mOT_LLScope,            // Have just done kAddLinkMulticastOption
+//     mOT_AdminScope,         // Have just done kAddAdminMulticastOption
+       mOT_Bind,                       // We've just called OTBind
+       mOT_Ready                       // Got T_BINDCOMPLETE; Interface is registered and active
        } mOT_State;
 
 typedef struct { TOptionHeader h; mDNSv4Addr multicastGroupAddress; mDNSv4Addr InterfaceAddress; } TIPAddMulticastOption;
+typedef struct { TOptionHeader h; UInt8 val; } TSetByteOption;
 typedef struct { TOptionHeader h; UInt32 flag; } TSetBooleanOption;
 
 // TOptionBlock is a union of various types.
 // What they all have in common is that they all start with a TOptionHeader.
-typedef union  { TOptionHeader h; TIPAddMulticastOption m; TSetBooleanOption b; } TOptionBlock;
+typedef union  { TOptionHeader h; TIPAddMulticastOption m; TSetByteOption i; TSetBooleanOption b; } TOptionBlock;
 
 struct mDNS_PlatformSupport_struct
        {
diff --git a/mDNSMacOS9/mDNSPrefix.h b/mDNSMacOS9/mDNSPrefix.h
new file mode 100644 (file)
index 0000000..3d1b0aa
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+
+$Log: mDNSPrefix.h,v $
+Revision 1.2  2004/05/21 01:57:08  cheshire
+Add macros for malloc() and free() so that dnssd_clientlib.c can use them
+
+Revision 1.1  2004/03/12 21:30:26  cheshire
+Build a System-Context Shared Library from mDNSCore, for the benefit of developers
+like Muse Research who want to be able to use mDNS/DNS-SD from GPL-licensed code.
+
+ */
+
+// Global definitions that apply to all source files
+//
+// Symbols that are defined here are available within all source files.
+// This is the equivalent of using using "-d SYMBOL=VALUE" in a Makefile
+// in command-line build environments.
+
+// For normal DeferredTask time execution, set MDNS_ONLYSYSTEMTASK to 0
+// For easier debugging, set MDNS_ONLYSYSTEMTASK to 1, and OT Notifier executions
+// will be deferred until SystemTask time. (This option is available only for building
+// the standalone application samples that have their own event loop -- don't try
+// to build the System Extension with MDNS_ONLYSYSTEMTASK set because it won't work.)
+
+#if   __ide_target("Standalone TestResponder")           || __ide_target("Standalone TestSearcher")
+#define TARGET_API_MAC_CARBON 1
+#define OTCARBONAPPLICATION 1
+#define MDNS_ONLYSYSTEMTASK 0
+#define MDNS_DEBUGMSGS 0
+#elif __ide_target("Standalone TestResponder (Debug)")   || __ide_target("Standalone TestSearcher (Debug)")
+#define TARGET_API_MAC_CARBON 1
+#define OTCARBONAPPLICATION 1
+#define MDNS_ONLYSYSTEMTASK 1
+#define MDNS_DEBUGMSGS 1
+#elif __ide_target("Standalone TestResponder (Classic)") || __ide_target("Standalone TestSearcher (Classic)")
+#define MDNS_ONLYSYSTEMTASK 0
+#define MDNS_DEBUGMSGS 0
+#elif __ide_target("CFM Library for Extensions Folder")
+#define MDNS_BUILDINGSHAREDLIBRARY 2
+#elif __ide_target("CFM Library for Extensions (Debug)")
+#define MDNS_DEBUGMSGS 0
+#define MDNS_BUILDINGSHAREDLIBRARY 1
+#elif __ide_target("CFM Stub for clients to link against")
+#define MDNS_BUILDINGSTUBLIBRARY 1
+#else
+#error Options for this target not found in prefix file
+#endif
+
+// dnssd_clientlib.c assumes malloc() and free(), so we #define them here to be the OT equivalents
+#if MDNS_BUILDINGSHAREDLIBRARY || MDNS_BUILDINGSTUBLIBRARY
+#define malloc(x) OTAllocMem(x)
+#define free(x) OTFreeMem(x)
+#endif
diff --git a/mDNSMacOS9/mDNSPrefixCarbon.h b/mDNSMacOS9/mDNSPrefixCarbon.h
deleted file mode 100644 (file)
index 95f1a48..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- * 
- * @APPLE_LICENSE_HEADER_END@
-
-    Change History (most recent first):
-
-$Log: mDNSPrefixCarbon.h,v $
-Revision 1.5  2003/08/12 19:56:24  cheshire
-Update to APSL 2.0
-
- */
-
-// Global options for the Mac OS Test Responder target.
-// Symbols defined here are available within all source files, like symbols
-// defined globally for a project using "-d SYMBOL=VALUE" in Unix Makefiles
-
-// For normal DeferredTask time execution, set __ONLYSYSTEMTASK__ to 0
-// For easier debugging, set __ONLYSYSTEMTASK__ to 1, and OT Notifier executions
-// will be deferred until SystemTask time
-
-#define TARGET_API_MAC_CARBON 1
-#define OTCARBONAPPLICATION 1
-
-#define __ONLYSYSTEMTASK__ 1
-#define MDNS_DEBUGMSGS 0
diff --git a/mDNSMacOS9/mDNSPrefixCarbonDebug.h b/mDNSMacOS9/mDNSPrefixCarbonDebug.h
deleted file mode 100644 (file)
index 2c31a97..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- * 
- * @APPLE_LICENSE_HEADER_END@
-
-    Change History (most recent first):
-
-$Log: mDNSPrefixCarbonDebug.h,v $
-Revision 1.5  2003/08/12 19:56:24  cheshire
-Update to APSL 2.0
-
- */
-
-// Global options for the Mac OS Test Responder target.
-// Symbols defined here are available within all source files, like symbols
-// defined globally for a project using "-d SYMBOL=VALUE" in Unix Makefiles
-
-// For normal DeferredTask time execution, set __ONLYSYSTEMTASK__ to 0
-// For easier debugging, set __ONLYSYSTEMTASK__ to 1, and OT Notifier executions
-// will be deferred until SystemTask time
-
-#define TARGET_API_MAC_CARBON 1
-#define OTCARBONAPPLICATION 1
-
-#define __ONLYSYSTEMTASK__ 1
-#define MDNS_DEBUGMSGS 1
diff --git a/mDNSMacOS9/mDNSPrefixClassic.h b/mDNSMacOS9/mDNSPrefixClassic.h
deleted file mode 100644 (file)
index d275361..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- * 
- * @APPLE_LICENSE_HEADER_END@
-
-    Change History (most recent first):
-
-$Log: mDNSPrefixClassic.h,v $
-Revision 1.5  2003/08/12 19:56:24  cheshire
-Update to APSL 2.0
-
- */
-
-// Global options for the Mac OS Test Responder target.
-// Symbols defined here are available within all source files, like symbols
-// defined globally for a project using "-d SYMBOL=VALUE" in Unix Makefiles
-
-// For normal DeferredTask time execution, set __ONLYSYSTEMTASK__ to 0
-// For easier debugging, set __ONLYSYSTEMTASK__ to 1, and OT Notifier executions
-// will be deferred until SystemTask time
-
-#define __ONLYSYSTEMTASK__ 1
-#define MDNS_DEBUGMSGS 0
diff --git a/mDNSMacOSX/Applications/DNSServiceBrowser/BrowserController.h b/mDNSMacOSX/Applications/DNSServiceBrowser/BrowserController.h
deleted file mode 100755 (executable)
index f58c914..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- * 
- * @APPLE_LICENSE_HEADER_END@
-
-    Change History (most recent first):
-
-$Log: BrowserController.h,v $
-Revision 1.7  2003/08/12 19:55:07  cheshire
-Update to APSL 2.0
-
- */
-
-#import <Cocoa/Cocoa.h>
-#import <DNSServiceDiscovery/DNSServiceDiscovery.h>
-
-#include <netinet/in.h>
-
-@interface BrowserController : NSObject
-{
-    IBOutlet id domainField;
-    IBOutlet id nameField;
-    IBOutlet id typeField;
-
-    IBOutlet id serviceDisplayTable;
-    IBOutlet id typeColumn;
-    IBOutlet id nameColumn;
-    IBOutlet id serviceTypeField;
-    IBOutlet id serviceNameField;
-
-    IBOutlet id ipAddressField;
-    IBOutlet id portField;
-    IBOutlet id textField;
-    
-    NSMutableArray *srvtypeKeys;
-    NSMutableArray *srvnameKeys;
-    NSMutableArray *domainKeys;
-    NSMutableArray *nameKeys;
-    NSString *Domain;
-    NSString *SrvType;
-    NSString *SrvName;
-    NSString *Name;
-
-    dns_service_discovery_ref  browse_client;
-
-}
-
-- (IBAction)handleDomainClick:(id)sender;
-- (IBAction)handleNameClick:(id)sender;
-- (IBAction)handleTypeClick:(id)sender;
-
-- (IBAction)connect:(id)sender;
-
-- (IBAction)handleTableClick:(id)sender;
-- (IBAction)removeSelected:(id)sender;
-- (IBAction)addNewService:(id)sender;
-
-- (IBAction)update:(NSString *)Type Domain:(NSString *)Domain;
-- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication;
-- (IBAction)loadDomains:(id)sender;
-
-- (void)updateBrowseWithResult:(int)type name:(NSString *)name type:(NSString *)resulttype domain:(NSString *)domain flags:(int)flags;
-- (void)updateEnumWithResult:(int)resultType domain:(NSString *)domain flags:(int)flags;
-- (void)resolveClientWithInterface:(struct sockaddr *)interface address:(struct sockaddr *)address txtRecord:(NSString *)txtRecord;
-
-@end
\ No newline at end of file
diff --git a/mDNSMacOSX/Applications/DNSServiceBrowser/BrowserController.m b/mDNSMacOSX/Applications/DNSServiceBrowser/BrowserController.m
deleted file mode 100755 (executable)
index 1dbe2a4..0000000
+++ /dev/null
@@ -1,541 +0,0 @@
-/*
- * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- * 
- * @APPLE_LICENSE_HEADER_END@
-
-    Change History (most recent first):
-
-$Log: BrowserController.m,v $
-Revision 1.18  2003/08/12 19:55:07  cheshire
-Update to APSL 2.0
-
- */
-
-#import "BrowserController.h"
-
-#include "arpa/inet.h"
-
-void
-MyHandleMachMessage ( CFMachPortRef port, void * msg, CFIndex size, void * info )
-{
-    DNSServiceDiscovery_handleReply(msg);
-}
-
-void browse_reply (
-                   DNSServiceBrowserReplyResultType    resultType,             // One of DNSServiceBrowserReplyResultType
-                   const char          *replyName,
-                   const char          *replyType,
-                   const char          *replyDomain,
-                   DNSServiceDiscoveryReplyFlags       flags,                  // DNS Service Discovery reply flags information
-                   void        *context
-                   )
-{
-    [[NSApp delegate] updateBrowseWithResult:resultType name:[NSString stringWithUTF8String:replyName] type:[NSString stringWithUTF8String:replyType] domain:[NSString stringWithUTF8String:replyDomain] flags:flags];
-    return;
-}
-
-void enum_reply (
-                 DNSServiceDomainEnumerationReplyResultType    resultType,
-                 const char    *replyDomain,
-                 DNSServiceDiscoveryReplyFlags         flags,
-                 void  *context
-                 )
-{
-    [[NSApp delegate] updateEnumWithResult:resultType domain:[NSString stringWithUTF8String:replyDomain] flags:flags];
-
-    return;
-}
-
-void resolve_reply (
-                    struct sockaddr    *interface,
-                    struct sockaddr    *address,
-                    const char                 *txtRecord,
-                    DNSServiceDiscoveryReplyFlags              flags,
-                    void               *context
-                    )
-{
-    [[NSApp delegate] resolveClientWithInterface:interface address:address txtRecord:[NSString stringWithUTF8String:txtRecord]];
-
-    return;
-}
-
-@implementation BrowserController              //Begin implementation of BrowserController methods
-
-- (void)registerDefaults
-{
-    NSMutableDictionary *regDict = [NSMutableDictionary dictionary];
-
-    NSArray *typeArray = [NSArray arrayWithObjects:@"_ftp._tcp.",          @"_tftp._tcp.",
-                                                                                                  @"_ssh._tcp.",          @"_telnet._tcp.",
-                                                                                                  @"_http._tcp.",
-                                                                                                  @"_printer._tcp.",      @"_ipp._tcp.",
-                                                                                                  @"_ichat._tcp.",        @"_eppc._tcp.",
-                                                                                                  @"_afpovertcp._tcp.",   @"_afpovertcp._tcp.",   @"_MacOSXDupSuppress._tcp.", nil];
-    NSArray *nameArray = [NSArray arrayWithObjects:@"File Transfer (ftp)", @"Trivial File Transfer (tftp)",
-                                                      @"Secure Shell (ssh)",  @"Telnet",
-                                                      @"Web Server (http)",
-                                                      @"LPR Printer",         @"IPP Printer",
-                                                                                                  @"iChat",               @"Remote AppleEvents",
-                                                                                                  @"AppleShare Server",   @"SMB File Server",     @"Mystery Service", nil];
-
-    [regDict setObject:typeArray forKey:@"SrvTypeKeys"];
-    [regDict setObject:nameArray forKey:@"SrvNameKeys"];
-
-    [[NSUserDefaults standardUserDefaults] registerDefaults:regDict];
-}
-
-
-- (id)init
-{
-    [self registerDefaults];
-
-    browse_client = nil;
-
-    return [super init];
-}
-
-- (void)awakeFromNib                           //BrowserController startup procedure
-{
-    SrvType=NULL;
-    Domain=NULL;
-    srvtypeKeys = [NSMutableArray array];      //Define arrays for Type, Domain, and Name
-    srvnameKeys = [NSMutableArray array];
-
-    domainKeys = [NSMutableArray array];
-    [domainKeys retain];
-
-    nameKeys = [NSMutableArray array];
-    [nameKeys retain];
-
-    [srvtypeKeys retain];                              //Keep arrays in memory until BrowserController closes
-    [srvnameKeys retain];                              //Keep arrays in memory until BrowserController closes
-    [typeField setDataSource:self];            //Set application fields' data source to BrowserController
-    [typeField sizeLastColumnToFit];           //and set column sizes to use their whole table's width.
-    [nameField setDataSource:self];
-    [nameField sizeLastColumnToFit];
-    [domainField setDataSource:self];
-    [domainField sizeLastColumnToFit];
-
-    [nameField setDoubleAction:@selector(connect:)];
-
-    //[srvtypeKeys addObject:@"_ftp._tcp."];   //Add supported protocols and domains to their
-    //[srvnameKeys addObject:@"File Transfer (ftp)"];
-    //[srvtypeKeys addObject:@"_printer._tcp."];               //respective arrays
-    //[srvnameKeys addObject:@"Printer (lpr)"];
-    //[srvtypeKeys addObject:@"_http._tcp."];          //respective arrays
-    //[srvnameKeys addObject:@"Web Server (http)"];
-    //[srvtypeKeys addObject:@"_afp._tcp."];           //respective arrays
-    //[srvnameKeys addObject:@"AppleShare Server (afp)"];
-
-    [ipAddressField setStringValue:@""];
-    [portField setStringValue:@""];
-    [textField setStringValue:@""];
-
-    [srvtypeKeys addObjectsFromArray:[[NSUserDefaults standardUserDefaults] arrayForKey:@"SrvTypeKeys"]];
-    [srvnameKeys addObjectsFromArray:[[NSUserDefaults standardUserDefaults] arrayForKey:@"SrvNameKeys"]];
-
-
-    [typeField reloadData];                            //Reload (redraw) data in fields
-    [domainField reloadData];
-
-    [self loadDomains:self];
-
-}
-
-- (void)dealloc                                                //Deallocation method
-{
-    [srvtypeKeys release];
-    [srvnameKeys release];
-    [nameKeys release];
-    [domainKeys release];
-}
-
--(void)tableView:(NSTableView *)theTableView setObjectValue:(id)object forTableColumn:(NSTableColumn *)tableColumn row:(int)row
-{
-    if (row<0) return;
-}
-
-- (int)numberOfRowsInTableView:(NSTableView *)theTableView     //Begin mandatory TableView methods
-{
-    if (theTableView == typeField)
-    {
-        return [srvnameKeys count];
-    }
-    if (theTableView == domainField)
-    {
-        return [domainKeys count];
-    }
-    if (theTableView == nameField)
-    {
-        return [nameKeys count];
-    }
-    if (theTableView == serviceDisplayTable)
-    {
-        return [srvnameKeys count];
-    }
-    return 0;
-}
-
-- (id)tableView:(NSTableView *)theTableView objectValueForTableColumn:(NSTableColumn *)theColumn row:(int)rowIndex
-{
-    if (theTableView == typeField)
-    {
-        return [srvnameKeys objectAtIndex:rowIndex];
-    }
-    if (theTableView == domainField)
-    {
-        return [domainKeys objectAtIndex:rowIndex];
-    }
-    if (theTableView == nameField)
-    {
-        return [[nameKeys sortedArrayUsingSelector:@selector(compare:)] objectAtIndex:rowIndex];
-    }
-    if (theTableView == serviceDisplayTable)
-    {
-        if (theColumn == typeColumn) {
-            return [srvtypeKeys objectAtIndex:rowIndex];
-        }
-        if (theColumn == nameColumn) {
-            return [srvnameKeys objectAtIndex:rowIndex];
-        }
-        return 0;
-    }
-    else
-        return(0);
-}                                              //End of mandatory TableView methods
-
-- (IBAction)handleTypeClick:(id)sender         //Handle clicks for Type
-{
-    int index=[sender selectedRow];                            //Find index of selected row
-    if (index==-1) return;                                     //Error checking
-    SrvType = [srvtypeKeys objectAtIndex:index];               //Save desired Type
-    SrvName = [srvnameKeys objectAtIndex:index];               //Save desired Type
-
-    [ipAddressField setStringValue:@""];
-    [portField setStringValue:@""];
-    [textField setStringValue:@""];
-
-    [self update:SrvType Domain:Domain];               //If Type and Domain are set, update records
-}
-
-- (IBAction)handleDomainClick:(id)sender                       //Handle clicks for Domain
-{
-    int index=[sender selectedRow];                            //Find index of selected row
-    if (index==-1) return;                                     //Error checking
-    Domain = [domainKeys objectAtIndex:index];                 //Save desired Domain
-
-    [ipAddressField setStringValue:@""];
-    [portField setStringValue:@""];
-    [textField setStringValue:@""];
-
-    if (SrvType!=NULL) [self update:SrvType Domain:Domain];    //If Type and Domain are set, update records
-}
-
-- (IBAction)handleNameClick:(id)sender                         //Handle clicks for Name
-{
-    int index=[sender selectedRow];                            //Find index of selected row
-    if (index==-1) return;                                     //Error checking
-    Name=[[nameKeys sortedArrayUsingSelector:@selector(compare:)] objectAtIndex:index];                        //Save desired name
-
-    {
-        CFMachPortRef           cfMachPort;
-        CFMachPortContext       context;
-        Boolean                 shouldFreeInfo;
-        dns_service_discovery_ref      dns_client;
-        mach_port_t                    port;
-        CFRunLoopSourceRef             rls;
-
-        context.version                 = 1;
-        context.info                    = 0;
-        context.retain                  = NULL;
-        context.release                 = NULL;
-        context.copyDescription            = NULL;
-
-               [ipAddressField setStringValue:@"?"];
-               [portField setStringValue:@"?"];
-               [textField setStringValue:@"?"];
-        // start an enumerator on the local server
-        dns_client = DNSServiceResolverResolve
-            (
-             (char *)[Name UTF8String],
-             (char *)[SrvType UTF8String],
-             (char *)(Domain?[Domain UTF8String]:""),
-             resolve_reply,
-             nil
-             );
-
-        port = DNSServiceDiscoveryMachPort(dns_client);
-
-        if (port) {
-            cfMachPort = CFMachPortCreateWithPort ( kCFAllocatorDefault, port, ( CFMachPortCallBack ) MyHandleMachMessage,&context,&shouldFreeInfo );
-
-            /* Create and add a run loop source for the port */
-            rls = CFMachPortCreateRunLoopSource(NULL, cfMachPort, 0);
-            CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
-            CFRelease(rls);
-        } else {
-            printf("Could not obtain client port\n");
-            return;
-        }
-    }
-}
-
-- (IBAction)loadDomains:(id)sender
-{
-    CFMachPortRef           cfMachPort;
-    CFMachPortContext       context;
-    Boolean                 shouldFreeInfo;
-    dns_service_discovery_ref  dns_client;
-    mach_port_t                        port;
-    CFRunLoopSourceRef         rls;
-
-    context.version                 = 1;
-    context.info                    = 0;
-    context.retain                  = NULL;
-    context.release                 = NULL;
-    context.copyDescription        = NULL;
-
-    // start an enumerator on the local server
-    dns_client =  DNSServiceDomainEnumerationCreate
-        (
-         0,
-         enum_reply,
-         nil
-         );
-
-    port = DNSServiceDiscoveryMachPort(dns_client);
-
-    if (port) {
-        cfMachPort = CFMachPortCreateWithPort ( kCFAllocatorDefault, port, ( CFMachPortCallBack ) MyHandleMachMessage,&context,&shouldFreeInfo );
-
-        /* Create and add a run loop source for the port */
-        rls = CFMachPortCreateRunLoopSource(NULL, cfMachPort, 0);
-        CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
-        CFRelease(rls);
-    } else {
-        printf("Could not obtain client port\n");
-        return;
-    }
-}
-
-- (IBAction)update:theType Domain:theDomain;           //The Big Kahuna: Fetch PTR records and update application
-{
-    const char * DomainC;
-    const char * TypeC=[theType UTF8String];           //Type in C string format
-
-    if (theDomain) {
-        DomainC = [theDomain UTF8String];      //Domain in C string format
-    } else {
-        DomainC = "";
-    }
-
-    [nameKeys removeAllObjects];       //Get rid of displayed records if we're going to go get new ones
-    [nameField reloadData];            //Reload (redraw) names to show the old data is gone
-
-    // get rid of the previous browser if one exists
-    if (browse_client) {
-        DNSServiceDiscoveryDeallocate(browse_client);
-        browse_client = nil;
-    }
-
-    // now create a browser to return the values for the nameField ...
-    {
-        CFMachPortRef           cfMachPort;
-        CFMachPortContext       context;
-        Boolean                 shouldFreeInfo;
-        mach_port_t                    port;
-        CFRunLoopSourceRef             rls;
-
-        context.version                 = 1;
-        context.info                    = 0;
-        context.retain                  = NULL;
-        context.release                 = NULL;
-        context.copyDescription            = NULL;
-
-        // start an enumerator on the local server
-        browse_client = DNSServiceBrowserCreate
-            (
-             (char *)TypeC,
-             (char *)DomainC,
-             browse_reply,
-             nil
-             );
-
-        port = DNSServiceDiscoveryMachPort(browse_client);
-
-        if (port) {
-            cfMachPort = CFMachPortCreateWithPort ( kCFAllocatorDefault, port, ( CFMachPortCallBack ) MyHandleMachMessage,&context,&shouldFreeInfo );
-
-            /* Create and add a run loop source for the port */
-            rls = CFMachPortCreateRunLoopSource(NULL, cfMachPort, 0);
-            CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
-            CFRelease(rls);
-        } else {
-            printf("Could not obtain client port\n");
-            return;
-        }
-    }
-
-}
-
-
-- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication //Quit when main window is closed
-{
-    return YES;
-}
-
-- (BOOL)windowShouldClose:(NSWindow *)sender   //Save domains to our domain file when quitting
-{
-    [domainField reloadData];
-    return YES;
-}
-
-- (void)updateEnumWithResult:(int)resultType domain:(NSString *)domain flags:(int)flags
-{
-    // new domain received
-    if (DNSServiceDomainEnumerationReplyAddDomain == resultType || DNSServiceDomainEnumerationReplyAddDomainDefault == resultType) {
-        // add the domain to the list
-        [domainKeys addObject:domain];
-    } else {
-        // remove the domain from the list
-        NSEnumerator *dmnEnum = [domainKeys objectEnumerator];
-        NSString *aDomain = nil;
-
-        while (aDomain = [dmnEnum nextObject]) {
-            if ([aDomain isEqualToString:domain]) {
-                [domainKeys removeObject:domain];
-                break;
-            }
-        }
-    }
-    // update the domain table
-    [domainField reloadData];
-    return;
-}
-
-
-
-- (void)updateBrowseWithResult:(int)type name:(NSString *)name type:(NSString *)resulttype domain:(NSString *)domain flags:(int)flags
-{
-
-    //NSLog(@"Received result %@ %@ %@ %d", name, resulttype, domain, type);
-
-    if (([domain isEqualToString:Domain] || [domain isEqualToString:@"local."]) && [resulttype isEqualToString:SrvType]) {
-
-        if (type == DNSServiceBrowserReplyRemoveInstance) {
-            if ([nameKeys containsObject:name]) {
-                [nameKeys removeObject:name];
-            }
-        }
-        if (type == DNSServiceBrowserReplyAddInstance) {
-            if (![nameKeys containsObject:name]) {
-                [nameKeys addObject:name];
-            }
-        }
-
-               // If not expecting any more data, then reload (redraw) Name TableView with newly found data
-               if ((flags & kDNSServiceDiscoveryMoreRepliesImmediately) == 0)
-                       [nameField reloadData];
-    }
-    return;
-}
-
-- (void)resolveClientWithInterface:(struct sockaddr *)interface address:(struct sockaddr *)address txtRecord:(NSString *)txtRecord
-{
-       if (address->sa_family != AF_INET) return; // For now we only handle IPv4
-    //printf("interface length = %d, port = %d, family = %d, address = %s\n", ((struct sockaddr_in *)interface)->sin_len, ((struct sockaddr_in *)interface)->sin_port, ((struct sockaddr_in *)interface)->sin_family, inet_ntoa(((struct in_addr)((struct sockaddr_in *)interface)->sin_addr)));
-    //printf("address length = %d, port = %d, family = %d, address = %s\n", ((struct sockaddr_in *)address)->sin_len, ((struct sockaddr_in *)address)->sin_port, ((struct sockaddr_in *)address)->sin_family, inet_ntoa(((struct in_addr)((struct sockaddr_in *)address)->sin_addr)));
-    NSString *ipAddr = [NSString stringWithCString:inet_ntoa(((struct in_addr)((struct sockaddr_in *)address)->sin_addr))];
-    int port = ((struct sockaddr_in *)address)->sin_port;
-
-    [ipAddressField setStringValue:ipAddr];
-    [portField setIntValue:port];
-    [textField setStringValue:txtRecord];
-
-    return;
-}
-
-- (void)connect:(id)sender
-{
-    NSString *ipAddr = [ipAddressField stringValue];
-    int port = [portField intValue];
-    NSString *txtRecord = [textField stringValue];
-
-    if (!txtRecord) txtRecord = @"";
-
-    if (!ipAddr || !port) return;
-
-    if      ([SrvType isEqualToString:@"_ftp._tcp."])        [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"ftp://%@:%d/",    ipAddr, port]]];
-    else if ([SrvType isEqualToString:@"_tftp._tcp."])       [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"tftp://%@:%d/",   ipAddr, port]]];
-    else if ([SrvType isEqualToString:@"_ssh._tcp."])        [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"ssh://%@:%d/",    ipAddr, port]]];
-    else if ([SrvType isEqualToString:@"_telnet._tcp."])     [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"telnet://%@:%d/", ipAddr, port]]];
-    else if ([SrvType isEqualToString:@"_http._tcp."])       [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"http://%@:%d",    ipAddr, port]]];
-    else if ([SrvType isEqualToString:@"_printer._tcp."])    [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"lpr://%@:%d/",    ipAddr, port]]];
-    else if ([SrvType isEqualToString:@"_ipp._tcp."])        [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"ipp://%@:%d/",    ipAddr, port]]];
-    else if ([SrvType isEqualToString:@"_afpovertcp._tcp."]) [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"afp://%@:%d/",    ipAddr, port]]];
-    else if ([SrvType isEqualToString:@"_smb._tcp."])        [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"smb://%@:%d/",    ipAddr, port]]];
-
-    return;
-}
-
-- (IBAction)handleTableClick:(id)sender
-{
-    //populate the text fields
-}
-
-- (IBAction)removeSelected:(id)sender
-{
-    // remove the selected row and force a refresh
-
-    int selectedRow = [serviceDisplayTable selectedRow];
-
-    if (selectedRow) {
-
-        [srvtypeKeys removeObjectAtIndex:selectedRow];
-        [srvnameKeys removeObjectAtIndex:selectedRow];
-
-        [[NSUserDefaults standardUserDefaults] setObject:srvtypeKeys forKey:@"SrvTypeKeys"];
-        [[NSUserDefaults standardUserDefaults] setObject:srvnameKeys forKey:@"SrvNameKeys"];
-
-        [typeField reloadData];
-        [serviceDisplayTable reloadData];
-    }
-}
-
-- (IBAction)addNewService:(id)sender
-{
-    // add new entries from the edit fields to the arrays for the defaults
-
-    if ([[serviceTypeField stringValue] length] && [[serviceNameField stringValue] length]) {
-        [srvtypeKeys addObject:[serviceTypeField stringValue]];
-        [srvnameKeys addObject:[serviceNameField stringValue]];
-
-        [[NSUserDefaults standardUserDefaults] setObject:srvtypeKeys forKey:@"SrvTypeKeys"];
-        [[NSUserDefaults standardUserDefaults] setObject:srvnameKeys forKey:@"SrvNameKeys"];
-
-        [typeField reloadData];
-        [serviceDisplayTable reloadData];
-    }
-
-}
-
-
-
-@end
\ No newline at end of file
diff --git a/mDNSMacOSX/Applications/DNSServiceBrowser/DNS Service Browser.pbproj/project.pbxproj b/mDNSMacOSX/Applications/DNSServiceBrowser/DNS Service Browser.pbproj/project.pbxproj
deleted file mode 100644 (file)
index 1cb8edd..0000000
+++ /dev/null
@@ -1,377 +0,0 @@
-// !$*UTF8*$!
-{
-       archiveVersion = 1;
-       classes = {
-       };
-       objectVersion = 38;
-       objects = {
-               080E96DCFE201CFB7F000001 = {
-                       fileRef = 29B97318FDCFA39411CA2CEA;
-                       isa = PBXBuildFile;
-                       settings = {
-                       };
-               };
-               080E96DDFE201D6D7F000001 = {
-                       children = (
-                               6515F1C002245DF2000001D2,
-                               6515F1C102245DF2000001D2,
-                       );
-                       isa = PBXGroup;
-                       name = Classes;
-                       refType = 4;
-               };
-               089C165CFE840E0CC02AAC07 = {
-                       children = (
-                               089C165DFE840E0CC02AAC07,
-                       );
-                       isa = PBXVariantGroup;
-                       name = InfoPlist.strings;
-                       refType = 4;
-               };
-               089C165DFE840E0CC02AAC07 = {
-                       fileEncoding = 10;
-                       isa = PBXFileReference;
-                       name = English;
-                       path = English.lproj/InfoPlist.strings;
-                       refType = 4;
-               };
-               089C165EFE840E0CC02AAC07 = {
-                       fileRef = 089C165CFE840E0CC02AAC07;
-                       isa = PBXBuildFile;
-                       settings = {
-                       };
-               };
-//080
-//081
-//082
-//083
-//084
-//100
-//101
-//102
-//103
-//104
-               1058C7A0FEA54F0111CA2CBB = {
-                       children = (
-                               1058C7A1FEA54F0111CA2CBB,
-                       );
-                       isa = PBXGroup;
-                       name = "Linked Frameworks";
-                       refType = 4;
-               };
-               1058C7A1FEA54F0111CA2CBB = {
-                       isa = PBXFrameworkReference;
-                       name = Cocoa.framework;
-                       path = /System/Library/Frameworks/Cocoa.framework;
-                       refType = 0;
-               };
-               1058C7A2FEA54F0111CA2CBB = {
-                       children = (
-                               29B97325FDCFA39411CA2CEA,
-                               29B97324FDCFA39411CA2CEA,
-                       );
-                       isa = PBXGroup;
-                       name = "Other Frameworks";
-                       refType = 4;
-               };
-               1058C7A3FEA54F0111CA2CBB = {
-                       fileRef = 1058C7A1FEA54F0111CA2CBB;
-                       isa = PBXBuildFile;
-                       settings = {
-                       };
-               };
-//100
-//101
-//102
-//103
-//104
-//170
-//171
-//172
-//173
-//174
-               17587328FF379C6511CA2CBB = {
-                       isa = PBXApplicationReference;
-                       path = "DNS Service Browser.app";
-                       refType = 3;
-               };
-//170
-//171
-//172
-//173
-//174
-//190
-//191
-//192
-//193
-//194
-               19C28FACFE9D520D11CA2CBB = {
-                       children = (
-                               17587328FF379C6511CA2CBB,
-                       );
-                       isa = PBXGroup;
-                       name = Products;
-                       refType = 4;
-               };
-//190
-//191
-//192
-//193
-//194
-//290
-//291
-//292
-//293
-//294
-               29B97313FDCFA39411CA2CEA = {
-                       buildStyles = (
-                               4A9504CCFFE6A4B311CA0CBA,
-                               4A9504CDFFE6A4B311CA0CBA,
-                       );
-                       isa = PBXProject;
-                       mainGroup = 29B97314FDCFA39411CA2CEA;
-                       projectDirPath = "";
-                       targets = (
-                               29B97326FDCFA39411CA2CEA,
-                       );
-               };
-               29B97314FDCFA39411CA2CEA = {
-                       children = (
-                               080E96DDFE201D6D7F000001,
-                               29B97315FDCFA39411CA2CEA,
-                               29B97317FDCFA39411CA2CEA,
-                               29B97323FDCFA39411CA2CEA,
-                               19C28FACFE9D520D11CA2CBB,
-                       );
-                       isa = PBXGroup;
-                       name = "DNS Service Browser";
-                       path = "";
-                       refType = 4;
-               };
-               29B97315FDCFA39411CA2CEA = {
-                       children = (
-                               29B97316FDCFA39411CA2CEA,
-                       );
-                       isa = PBXGroup;
-                       name = "Other Sources";
-                       path = "";
-                       refType = 4;
-               };
-               29B97316FDCFA39411CA2CEA = {
-                       isa = PBXFileReference;
-                       path = main.m;
-                       refType = 4;
-               };
-               29B97317FDCFA39411CA2CEA = {
-                       children = (
-                               29B97318FDCFA39411CA2CEA,
-                               089C165CFE840E0CC02AAC07,
-                               6515F1C5022460A1000001D2,
-                       );
-                       isa = PBXGroup;
-                       name = Resources;
-                       path = "";
-                       refType = 4;
-               };
-               29B97318FDCFA39411CA2CEA = {
-                       children = (
-                               29B97319FDCFA39411CA2CEA,
-                       );
-                       isa = PBXVariantGroup;
-                       name = MainMenu.nib;
-                       path = "";
-                       refType = 4;
-               };
-               29B97319FDCFA39411CA2CEA = {
-                       isa = PBXFileReference;
-                       name = English;
-                       path = English.lproj/MainMenu.nib;
-                       refType = 4;
-               };
-               29B97323FDCFA39411CA2CEA = {
-                       children = (
-                               1058C7A0FEA54F0111CA2CBB,
-                               1058C7A2FEA54F0111CA2CBB,
-                       );
-                       isa = PBXGroup;
-                       name = Frameworks;
-                       path = "";
-                       refType = 4;
-               };
-               29B97324FDCFA39411CA2CEA = {
-                       isa = PBXFrameworkReference;
-                       name = AppKit.framework;
-                       path = /System/Library/Frameworks/AppKit.framework;
-                       refType = 0;
-               };
-               29B97325FDCFA39411CA2CEA = {
-                       isa = PBXFrameworkReference;
-                       name = Foundation.framework;
-                       path = /System/Library/Frameworks/Foundation.framework;
-                       refType = 0;
-               };
-               29B97326FDCFA39411CA2CEA = {
-                       buildPhases = (
-                               29B97327FDCFA39411CA2CEA,
-                               29B97328FDCFA39411CA2CEA,
-                               29B9732BFDCFA39411CA2CEA,
-                               29B9732DFDCFA39411CA2CEA,
-                       );
-                       buildSettings = {
-                               FRAMEWORK_SEARCH_PATHS = "";
-                               HEADER_SEARCH_PATHS = "";
-                               INSTALL_PATH = "$(HOME)/Applications";
-                               LIBRARY_SEARCH_PATHS = "";
-                               OTHER_CFLAGS = "";
-                               OTHER_LDFLAGS = "";
-                               PRODUCT_NAME = "DNS Service Browser";
-                               SECTORDER_FLAGS = "";
-                               WARNING_CFLAGS = "-Wmost -Wno-four-char-constants -Wno-unknown-pragmas";
-                               WRAPPER_EXTENSION = app;
-                       };
-                       dependencies = (
-                       );
-                       isa = PBXApplicationTarget;
-                       name = "DNS Service Browser";
-                       productInstallPath = "$(HOME)/Applications";
-                       productName = "DNS Service Browser";
-                       productReference = 17587328FF379C6511CA2CBB;
-                       productSettingsXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
-<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
-<plist version=\"1.0\">
-<dict>
-       <key>CFBundleDevelopmentRegion</key>
-       <string>English</string>
-       <key>CFBundleExecutable</key>
-       <string>DNS Service Browser</string>
-       <key>CFBundleIconFile</key>
-       <string></string>
-       <key>CFBundleInfoDictionaryVersion</key>
-       <string>6.0</string>
-       <key>CFBundlePackageType</key>
-       <string>APPL</string>
-       <key>CFBundleSignature</key>
-       <string>????</string>
-       <key>CFBundleVersion</key>
-       <string>0.1</string>
-       <key>NSMainNibFile</key>
-       <string>MainMenu</string>
-       <key>NSPrincipalClass</key>
-       <string>NSApplication</string>
-</dict>
-</plist>
-";
-                       shouldUseHeadermap = 1;
-               };
-               29B97327FDCFA39411CA2CEA = {
-                       buildActionMask = 2147483647;
-                       files = (
-                               6515F1C202245DF2000001D2,
-                       );
-                       isa = PBXHeadersBuildPhase;
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               29B97328FDCFA39411CA2CEA = {
-                       buildActionMask = 2147483647;
-                       files = (
-                               080E96DCFE201CFB7F000001,
-                               089C165EFE840E0CC02AAC07,
-                       );
-                       isa = PBXResourcesBuildPhase;
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               29B9732BFDCFA39411CA2CEA = {
-                       buildActionMask = 2147483647;
-                       files = (
-                               29B9732CFDCFA39411CA2CEA,
-                               6515F1C302245DF3000001D2,
-                       );
-                       isa = PBXSourcesBuildPhase;
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               29B9732CFDCFA39411CA2CEA = {
-                       fileRef = 29B97316FDCFA39411CA2CEA;
-                       isa = PBXBuildFile;
-                       settings = {
-                               ATTRIBUTES = (
-                               );
-                       };
-               };
-               29B9732DFDCFA39411CA2CEA = {
-                       buildActionMask = 2147483647;
-                       files = (
-                               1058C7A3FEA54F0111CA2CBB,
-                       );
-                       isa = PBXFrameworksBuildPhase;
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-//290
-//291
-//292
-//293
-//294
-//4A0
-//4A1
-//4A2
-//4A3
-//4A4
-               4A9504CCFFE6A4B311CA0CBA = {
-                       buildRules = (
-                       );
-                       buildSettings = {
-                               COPY_PHASE_STRIP = NO;
-                               OPTIMIZATION_CFLAGS = "-O0";
-                       };
-                       isa = PBXBuildStyle;
-                       name = Development;
-               };
-               4A9504CDFFE6A4B311CA0CBA = {
-                       buildRules = (
-                       );
-                       buildSettings = {
-                               COPY_PHASE_STRIP = YES;
-                       };
-                       isa = PBXBuildStyle;
-                       name = Deployment;
-               };
-//4A0
-//4A1
-//4A2
-//4A3
-//4A4
-//650
-//651
-//652
-//653
-//654
-               6515F1C002245DF2000001D2 = {
-                       isa = PBXFileReference;
-                       path = BrowserController.h;
-                       refType = 4;
-               };
-               6515F1C102245DF2000001D2 = {
-                       isa = PBXFileReference;
-                       path = BrowserController.m;
-                       refType = 4;
-               };
-               6515F1C202245DF2000001D2 = {
-                       fileRef = 6515F1C002245DF2000001D2;
-                       isa = PBXBuildFile;
-                       settings = {
-                       };
-               };
-               6515F1C302245DF3000001D2 = {
-                       fileRef = 6515F1C102245DF2000001D2;
-                       isa = PBXBuildFile;
-                       settings = {
-                       };
-               };
-               6515F1C5022460A1000001D2 = {
-                       isa = PBXFileReference;
-                       name = DNSServiceDiscovery.h;
-                       path = /usr/include/DNSServiceDiscovery/DNSServiceDiscovery.h;
-                       refType = 0;
-               };
-       };
-       rootObject = 29B97313FDCFA39411CA2CEA;
-}
diff --git a/mDNSMacOSX/Applications/DNSServiceBrowser/English.lproj/InfoPlist.strings b/mDNSMacOSX/Applications/DNSServiceBrowser/English.lproj/InfoPlist.strings
deleted file mode 100644 (file)
index 08c0f0c..0000000
Binary files a/mDNSMacOSX/Applications/DNSServiceBrowser/English.lproj/InfoPlist.strings and /dev/null differ
diff --git a/mDNSMacOSX/Applications/DNSServiceBrowser/English.lproj/MainMenu.nib/classes.nib b/mDNSMacOSX/Applications/DNSServiceBrowser/English.lproj/MainMenu.nib/classes.nib
deleted file mode 100644 (file)
index 2668d5d..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-{
-    IBClasses = (
-        {
-            ACTIONS = {
-                addNewService = id; 
-                connect = id; 
-                editDomains = id; 
-                handleDomainClick = id; 
-                handleNameClick = id; 
-                handleTableClick = id; 
-                handleTypeClick = id; 
-                loadDomains = id; 
-                removeSelected = id; 
-            }; 
-            CLASS = BrowserController; 
-            LANGUAGE = ObjC; 
-            OUTLETS = {
-                domainEditField = id; 
-                domainField = id; 
-                domainWindow = id; 
-                ipAddressField = id; 
-                nameColumn = id; 
-                nameField = id; 
-                portField = id; 
-                serviceDisplayTable = id; 
-                serviceNameField = id; 
-                serviceTypeField = id; 
-                textField = id; 
-                typeColumn = id; 
-                typeField = id; 
-            }; 
-            SUPERCLASS = NSObject; 
-        }, 
-        {CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; }
-    ); 
-    IBVersion = 1; 
-}
\ No newline at end of file
diff --git a/mDNSMacOSX/Applications/DNSServiceBrowser/English.lproj/MainMenu.nib/info.nib b/mDNSMacOSX/Applications/DNSServiceBrowser/English.lproj/MainMenu.nib/info.nib
deleted file mode 100644 (file)
index e31cf4c..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-       <key>IBDocumentLocation</key>
-       <string>14 102 356 240 0 0 1152 746 </string>
-       <key>IBEditorPositions</key>
-       <dict>
-               <key>29</key>
-               <string>22 474 271 44 0 0 1152 746 </string>
-       </dict>
-       <key>IBFramework Version</key>
-       <string>273.0</string>
-       <key>IBOpenObjects</key>
-       <array>
-               <integer>220</integer>
-               <integer>201</integer>
-       </array>
-       <key>IBSystem Version</key>
-       <string>6C35</string>
-</dict>
-</plist>
diff --git a/mDNSMacOSX/Applications/DNSServiceBrowser/English.lproj/MainMenu.nib/objects.nib b/mDNSMacOSX/Applications/DNSServiceBrowser/English.lproj/MainMenu.nib/objects.nib
deleted file mode 100644 (file)
index b330188..0000000
Binary files a/mDNSMacOSX/Applications/DNSServiceBrowser/English.lproj/MainMenu.nib/objects.nib and /dev/null differ
diff --git a/mDNSMacOSX/Applications/DNSServiceBrowser/main.m b/mDNSMacOSX/Applications/DNSServiceBrowser/main.m
deleted file mode 100644 (file)
index c340509..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- * 
- * @APPLE_LICENSE_HEADER_END@
-
-    Change History (most recent first):
-
-$Log: main.m,v $
-Revision 1.4  2003/08/12 19:55:07  cheshire
-Update to APSL 2.0
-
- */
-
-#import <Cocoa/Cocoa.h>
-
-int main(int argc, const char *argv[])
-{
-    return NSApplicationMain(argc, argv);
-}
diff --git a/mDNSMacOSX/Applications/DNSServiceRegistration/DNS Service Registration.pbproj/project.pbxproj b/mDNSMacOSX/Applications/DNSServiceRegistration/DNS Service Registration.pbproj/project.pbxproj
deleted file mode 100644 (file)
index 9487a76..0000000
+++ /dev/null
@@ -1,377 +0,0 @@
-// !$*UTF8*$!
-{
-       archiveVersion = 1;
-       classes = {
-       };
-       objectVersion = 38;
-       objects = {
-               080E96DCFE201CFB7F000001 = {
-                       fileRef = 29B97318FDCFA39411CA2CEA;
-                       isa = PBXBuildFile;
-                       settings = {
-                       };
-               };
-               080E96DDFE201D6D7F000001 = {
-                       children = (
-                               654EC28D0226D54A006533C2,
-                               654EC28C0226D54A006533C2,
-                       );
-                       isa = PBXGroup;
-                       name = Classes;
-                       refType = 4;
-               };
-               089C165CFE840E0CC02AAC07 = {
-                       children = (
-                               089C165DFE840E0CC02AAC07,
-                       );
-                       isa = PBXVariantGroup;
-                       name = InfoPlist.strings;
-                       refType = 4;
-               };
-               089C165DFE840E0CC02AAC07 = {
-                       fileEncoding = 10;
-                       isa = PBXFileReference;
-                       name = English;
-                       path = English.lproj/InfoPlist.strings;
-                       refType = 4;
-               };
-               089C165EFE840E0CC02AAC07 = {
-                       fileRef = 089C165CFE840E0CC02AAC07;
-                       isa = PBXBuildFile;
-                       settings = {
-                       };
-               };
-//080
-//081
-//082
-//083
-//084
-//100
-//101
-//102
-//103
-//104
-               1058C7A0FEA54F0111CA2CBB = {
-                       children = (
-                               1058C7A1FEA54F0111CA2CBB,
-                       );
-                       isa = PBXGroup;
-                       name = "Linked Frameworks";
-                       refType = 4;
-               };
-               1058C7A1FEA54F0111CA2CBB = {
-                       isa = PBXFrameworkReference;
-                       name = Cocoa.framework;
-                       path = /System/Library/Frameworks/Cocoa.framework;
-                       refType = 0;
-               };
-               1058C7A2FEA54F0111CA2CBB = {
-                       children = (
-                               29B97325FDCFA39411CA2CEA,
-                               29B97324FDCFA39411CA2CEA,
-                               65DD378E028194AE000001D1,
-                       );
-                       isa = PBXGroup;
-                       name = "Other Frameworks";
-                       refType = 4;
-               };
-               1058C7A3FEA54F0111CA2CBB = {
-                       fileRef = 1058C7A1FEA54F0111CA2CBB;
-                       isa = PBXBuildFile;
-                       settings = {
-                       };
-               };
-//100
-//101
-//102
-//103
-//104
-//170
-//171
-//172
-//173
-//174
-               17587328FF379C6511CA2CBB = {
-                       isa = PBXApplicationReference;
-                       path = "DNS Service Registration.app";
-                       refType = 3;
-               };
-//170
-//171
-//172
-//173
-//174
-//190
-//191
-//192
-//193
-//194
-               19C28FACFE9D520D11CA2CBB = {
-                       children = (
-                               17587328FF379C6511CA2CBB,
-                       );
-                       isa = PBXGroup;
-                       name = Products;
-                       refType = 4;
-               };
-//190
-//191
-//192
-//193
-//194
-//290
-//291
-//292
-//293
-//294
-               29B97313FDCFA39411CA2CEA = {
-                       buildStyles = (
-                               4A9504CCFFE6A4B311CA0CBA,
-                               4A9504CDFFE6A4B311CA0CBA,
-                       );
-                       isa = PBXProject;
-                       mainGroup = 29B97314FDCFA39411CA2CEA;
-                       projectDirPath = "";
-                       targets = (
-                               29B97326FDCFA39411CA2CEA,
-                       );
-               };
-               29B97314FDCFA39411CA2CEA = {
-                       children = (
-                               080E96DDFE201D6D7F000001,
-                               29B97315FDCFA39411CA2CEA,
-                               29B97317FDCFA39411CA2CEA,
-                               29B97323FDCFA39411CA2CEA,
-                               19C28FACFE9D520D11CA2CBB,
-                       );
-                       isa = PBXGroup;
-                       name = "DNS Service Registration";
-                       path = "";
-                       refType = 4;
-               };
-               29B97315FDCFA39411CA2CEA = {
-                       children = (
-                               29B97316FDCFA39411CA2CEA,
-                       );
-                       isa = PBXGroup;
-                       name = "Other Sources";
-                       path = "";
-                       refType = 4;
-               };
-               29B97316FDCFA39411CA2CEA = {
-                       isa = PBXFileReference;
-                       path = main.m;
-                       refType = 4;
-               };
-               29B97317FDCFA39411CA2CEA = {
-                       children = (
-                               29B97318FDCFA39411CA2CEA,
-                               089C165CFE840E0CC02AAC07,
-                       );
-                       isa = PBXGroup;
-                       name = Resources;
-                       path = "";
-                       refType = 4;
-               };
-               29B97318FDCFA39411CA2CEA = {
-                       children = (
-                               29B97319FDCFA39411CA2CEA,
-                       );
-                       isa = PBXVariantGroup;
-                       name = MainMenu.nib;
-                       path = "";
-                       refType = 4;
-               };
-               29B97319FDCFA39411CA2CEA = {
-                       isa = PBXFileReference;
-                       name = English;
-                       path = English.lproj/MainMenu.nib;
-                       refType = 4;
-               };
-               29B97323FDCFA39411CA2CEA = {
-                       children = (
-                               1058C7A0FEA54F0111CA2CBB,
-                               1058C7A2FEA54F0111CA2CBB,
-                       );
-                       isa = PBXGroup;
-                       name = Frameworks;
-                       path = "";
-                       refType = 4;
-               };
-               29B97324FDCFA39411CA2CEA = {
-                       isa = PBXFrameworkReference;
-                       name = AppKit.framework;
-                       path = /System/Library/Frameworks/AppKit.framework;
-                       refType = 0;
-               };
-               29B97325FDCFA39411CA2CEA = {
-                       isa = PBXFrameworkReference;
-                       name = Foundation.framework;
-                       path = /System/Library/Frameworks/Foundation.framework;
-                       refType = 0;
-               };
-               29B97326FDCFA39411CA2CEA = {
-                       buildPhases = (
-                               29B97327FDCFA39411CA2CEA,
-                               29B97328FDCFA39411CA2CEA,
-                               29B9732BFDCFA39411CA2CEA,
-                               29B9732DFDCFA39411CA2CEA,
-                       );
-                       buildSettings = {
-                               FRAMEWORK_SEARCH_PATHS = "";
-                               HEADER_SEARCH_PATHS = "";
-                               INSTALL_PATH = "$(HOME)/Applications";
-                               LIBRARY_SEARCH_PATHS = "";
-                               OTHER_CFLAGS = "";
-                               OTHER_LDFLAGS = "";
-                               PRODUCT_NAME = "DNS Service Registration";
-                               SECTORDER_FLAGS = "";
-                               WARNING_CFLAGS = "-Wmost -Wno-four-char-constants -Wno-unknown-pragmas";
-                               WRAPPER_EXTENSION = app;
-                       };
-                       dependencies = (
-                       );
-                       isa = PBXApplicationTarget;
-                       name = "DNS Service Registration";
-                       productInstallPath = "$(HOME)/Applications";
-                       productName = "DNS Service Registration";
-                       productReference = 17587328FF379C6511CA2CBB;
-                       productSettingsXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
-<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
-<plist version=\"1.0\">
-<dict>
-       <key>CFBundleDevelopmentRegion</key>
-       <string>English</string>
-       <key>CFBundleExecutable</key>
-       <string>DNS Service Registration</string>
-       <key>CFBundleIconFile</key>
-       <string></string>
-       <key>CFBundleInfoDictionaryVersion</key>
-       <string>6.0</string>
-       <key>CFBundlePackageType</key>
-       <string>APPL</string>
-       <key>CFBundleSignature</key>
-       <string>????</string>
-       <key>CFBundleVersion</key>
-       <string>0.1</string>
-       <key>NSMainNibFile</key>
-       <string>MainMenu</string>
-       <key>NSPrincipalClass</key>
-       <string>NSApplication</string>
-</dict>
-</plist>
-";
-                       shouldUseHeadermap = 1;
-               };
-               29B97327FDCFA39411CA2CEA = {
-                       buildActionMask = 2147483647;
-                       files = (
-                               654EC28E0226D54A006533C2,
-                       );
-                       isa = PBXHeadersBuildPhase;
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               29B97328FDCFA39411CA2CEA = {
-                       buildActionMask = 2147483647;
-                       files = (
-                               080E96DCFE201CFB7F000001,
-                               089C165EFE840E0CC02AAC07,
-                       );
-                       isa = PBXResourcesBuildPhase;
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               29B9732BFDCFA39411CA2CEA = {
-                       buildActionMask = 2147483647;
-                       files = (
-                               29B9732CFDCFA39411CA2CEA,
-                               654EC28F0226D54A006533C2,
-                       );
-                       isa = PBXSourcesBuildPhase;
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               29B9732CFDCFA39411CA2CEA = {
-                       fileRef = 29B97316FDCFA39411CA2CEA;
-                       isa = PBXBuildFile;
-                       settings = {
-                               ATTRIBUTES = (
-                               );
-                       };
-               };
-               29B9732DFDCFA39411CA2CEA = {
-                       buildActionMask = 2147483647;
-                       files = (
-                               1058C7A3FEA54F0111CA2CBB,
-                       );
-                       isa = PBXFrameworksBuildPhase;
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-//290
-//291
-//292
-//293
-//294
-//4A0
-//4A1
-//4A2
-//4A3
-//4A4
-               4A9504CCFFE6A4B311CA0CBA = {
-                       buildRules = (
-                       );
-                       buildSettings = {
-                               COPY_PHASE_STRIP = NO;
-                               OPTIMIZATION_CFLAGS = "-O0";
-                       };
-                       isa = PBXBuildStyle;
-                       name = Development;
-               };
-               4A9504CDFFE6A4B311CA0CBA = {
-                       buildRules = (
-                       );
-                       buildSettings = {
-                               COPY_PHASE_STRIP = YES;
-                       };
-                       isa = PBXBuildStyle;
-                       name = Deployment;
-               };
-//4A0
-//4A1
-//4A2
-//4A3
-//4A4
-//650
-//651
-//652
-//653
-//654
-               654EC28C0226D54A006533C2 = {
-                       isa = PBXFileReference;
-                       path = RegistrationController.m;
-                       refType = 4;
-               };
-               654EC28D0226D54A006533C2 = {
-                       isa = PBXFileReference;
-                       path = RegistrationController.h;
-                       refType = 4;
-               };
-               654EC28E0226D54A006533C2 = {
-                       fileRef = 654EC28D0226D54A006533C2;
-                       isa = PBXBuildFile;
-                       settings = {
-                       };
-               };
-               654EC28F0226D54A006533C2 = {
-                       fileRef = 654EC28C0226D54A006533C2;
-                       isa = PBXBuildFile;
-                       settings = {
-                       };
-               };
-               65DD378E028194AE000001D1 = {
-                       isa = PBXFrameworkReference;
-                       name = CoreFoundation.framework;
-                       path = /System/Library/Frameworks/CoreFoundation.framework;
-                       refType = 0;
-               };
-       };
-       rootObject = 29B97313FDCFA39411CA2CEA;
-}
diff --git a/mDNSMacOSX/Applications/DNSServiceRegistration/English.lproj/InfoPlist.strings b/mDNSMacOSX/Applications/DNSServiceRegistration/English.lproj/InfoPlist.strings
deleted file mode 100644 (file)
index 2aadfdc..0000000
Binary files a/mDNSMacOSX/Applications/DNSServiceRegistration/English.lproj/InfoPlist.strings and /dev/null differ
diff --git a/mDNSMacOSX/Applications/DNSServiceRegistration/English.lproj/MainMenu.nib/classes.nib b/mDNSMacOSX/Applications/DNSServiceRegistration/English.lproj/MainMenu.nib/classes.nib
deleted file mode 100644 (file)
index 46f466c..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-{
-    IBClasses = (
-        {CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, 
-        {
-            ACTIONS = {
-                addNewService = id; 
-                registerService = id; 
-                removeSelected = id; 
-                unregisterService = id; 
-            }; 
-            CLASS = RegistrationController; 
-            LANGUAGE = ObjC; 
-            OUTLETS = {
-                domainColumn = NSTableColumn; 
-                nameColumn = NSTableColumn; 
-                portColumn = NSTableColumn; 
-                serviceDisplayTable = NSTableView; 
-                serviceDomainField = NSTextField; 
-                serviceNameField = NSTextField; 
-                servicePortField = NSTextField; 
-                serviceTextField = NSTextField; 
-                serviceTypeField = NSTextField; 
-                textColumn = NSTableColumn; 
-                typeColumn = NSTableColumn; 
-            }; 
-            SUPERCLASS = NSObject; 
-        }
-    ); 
-    IBVersion = 1; 
-}
\ No newline at end of file
diff --git a/mDNSMacOSX/Applications/DNSServiceRegistration/English.lproj/MainMenu.nib/info.nib b/mDNSMacOSX/Applications/DNSServiceRegistration/English.lproj/MainMenu.nib/info.nib
deleted file mode 100644 (file)
index 9d2eb74..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-       <key>IBDocumentLocation</key>
-       <string>32 111 356 240 0 0 1152 746 </string>
-       <key>IBEditorPositions</key>
-       <dict>
-               <key>29</key>
-               <string>103 609 252 44 0 0 1152 746 </string>
-       </dict>
-       <key>IBFramework Version</key>
-       <string>273.0</string>
-       <key>IBOpenObjects</key>
-       <array>
-               <integer>243</integer>
-               <integer>21</integer>
-       </array>
-       <key>IBSystem Version</key>
-       <string>6C30</string>
-</dict>
-</plist>
diff --git a/mDNSMacOSX/Applications/DNSServiceRegistration/English.lproj/MainMenu.nib/objects.nib b/mDNSMacOSX/Applications/DNSServiceRegistration/English.lproj/MainMenu.nib/objects.nib
deleted file mode 100644 (file)
index 705e77d..0000000
Binary files a/mDNSMacOSX/Applications/DNSServiceRegistration/English.lproj/MainMenu.nib/objects.nib and /dev/null differ
diff --git a/mDNSMacOSX/Applications/DNSServiceRegistration/RegistrationController.h b/mDNSMacOSX/Applications/DNSServiceRegistration/RegistrationController.h
deleted file mode 100644 (file)
index ca53bf2..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- * 
- * @APPLE_LICENSE_HEADER_END@
-
-    Change History (most recent first):
-
-$Log: RegistrationController.h,v $
-Revision 1.5  2003/08/12 19:55:07  cheshire
-Update to APSL 2.0
-
- */
-
-/* RegistrationController */
-
-#import <Cocoa/Cocoa.h>
-
-@interface RegistrationController : NSObject
-{
-    IBOutlet NSTableColumn     *typeColumn;
-    IBOutlet NSTableColumn     *nameColumn;
-    IBOutlet NSTableColumn     *portColumn;
-    IBOutlet NSTableColumn     *domainColumn;
-    IBOutlet NSTableColumn     *textColumn;
-
-    IBOutlet NSTableView       *serviceDisplayTable;
-
-    IBOutlet NSTextField       *serviceTypeField;
-    IBOutlet NSTextField       *serviceNameField;
-    IBOutlet NSTextField       *servicePortField;
-    IBOutlet NSTextField       *serviceDomainField;
-    IBOutlet NSTextField       *serviceTextField;
-    
-    NSMutableArray             *srvtypeKeys;
-    NSMutableArray             *srvnameKeys;
-    NSMutableArray             *srvportKeys;
-    NSMutableArray             *srvdomainKeys;
-    NSMutableArray             *srvtextKeys;
-
-    NSMutableDictionary                *registeredDict;
-}
-
-- (IBAction)registerService:(id)sender;
-- (IBAction)unregisterService:(id)sender;
-
-- (IBAction)addNewService:(id)sender;
-- (IBAction)removeSelected:(id)sender;
-
-@end
diff --git a/mDNSMacOSX/Applications/DNSServiceRegistration/RegistrationController.m b/mDNSMacOSX/Applications/DNSServiceRegistration/RegistrationController.m
deleted file mode 100644 (file)
index 6255179..0000000
+++ /dev/null
@@ -1,247 +0,0 @@
-/*
- * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- * 
- * @APPLE_LICENSE_HEADER_END@
-
-    Change History (most recent first):
-
-$Log: RegistrationController.m,v $
-Revision 1.13  2003/08/12 19:55:07  cheshire
-Update to APSL 2.0
-
- */
-
-#import "RegistrationController.h"
-
-#include <DNSServiceDiscovery/DNSServiceDiscovery.h>
-
-void reg_reply (
-                int            errorCode,
-                void           *context
-                )
-{
-    // registration reply
-    printf("Got a reply from the server with error %d\n", errorCode);
-    return;
-}
-
-void
-MyHandleMachMessage ( CFMachPortRef port, void * msg, CFIndex size, void * info )
-{
-    DNSServiceDiscovery_handleReply(msg);
-}
-
-@implementation RegistrationController
-
-- (void)registerDefaults
-{
-    NSMutableDictionary *regDict = [NSMutableDictionary dictionary];
-
-    NSArray *typeArray   = [NSArray arrayWithObjects:@"_ftp._tcp.",    @"_ssh._tcp.",  @"_tftp._tcp.",        @"_http._tcp.",      @"_printer._tcp.",  @"_afpovertcp._tcp.",         nil];
-    NSArray *nameArray   = [NSArray arrayWithObjects:@"My ftp Server", @"My Computer", @"Testing Boot Image", @"A Web Server",     @"SteveÕs Printer", @"Company AppleShare Server", nil];
-    NSArray *portArray   = [NSArray arrayWithObjects:@"21",            @"22",          @"69",                 @"80",               @"515",             @"548",                       nil];
-    NSArray *domainArray = [NSArray arrayWithObjects:@"",              @"",            @"",                   @"",                 @"",                @"",                          nil];
-    NSArray *textArray   = [NSArray arrayWithObjects:@"",              @"",            @"image=mybootimage",  @"path=/index.html", @"rn=lpt1",         @"Vol=Public",                nil];
-
-    [regDict setObject:typeArray forKey:@"SrvTypeKeys"];
-    [regDict setObject:nameArray forKey:@"SrvNameKeys"];
-    [regDict setObject:portArray forKey:@"SrvPortKeys"];
-    [regDict setObject:domainArray forKey:@"SrvDomainKeys"];
-    [regDict setObject:textArray forKey:@"SrvTextKeys"];
-
-    [[NSUserDefaults standardUserDefaults] registerDefaults:regDict];
-}
-
-- (id)init
-{
-    srvtypeKeys = [[NSMutableArray array] retain];     //Define arrays for Type, Domain, and Name
-    srvnameKeys = [[NSMutableArray array] retain];
-    srvportKeys = [[NSMutableArray array] retain];
-    srvdomainKeys = [[NSMutableArray array] retain];
-    srvtextKeys = [[NSMutableArray array] retain];
-
-    registeredDict = [[NSMutableDictionary alloc] init];
-    
-    [self registerDefaults];
-    return [super init];
-}
-
-- (void)awakeFromNib                           //BrowserController startup procedure
-{
-    [srvtypeKeys addObjectsFromArray:[[NSUserDefaults standardUserDefaults] arrayForKey:@"SrvTypeKeys"]];
-    [srvnameKeys addObjectsFromArray:[[NSUserDefaults standardUserDefaults] arrayForKey:@"SrvNameKeys"]];
-    [srvportKeys addObjectsFromArray:[[NSUserDefaults standardUserDefaults] arrayForKey:@"SrvPortKeys"]];
-    [srvdomainKeys addObjectsFromArray:[[NSUserDefaults standardUserDefaults] arrayForKey:@"SrvDomainKeys"]];
-    [srvtextKeys addObjectsFromArray:[[NSUserDefaults standardUserDefaults] arrayForKey:@"SrvTextKeys"]];
-
-    [serviceDisplayTable reloadData];                          //Reload (redraw) data in fields
-
-}
-
-
-
- - (IBAction)registerService:(id)sender
-{
-    int selectedRow = [serviceDisplayTable selectedRow];
-    CFRunLoopSourceRef rls;
-    uint16_t   registerPort;
-    CFMachPortRef           cfMachPort;
-    CFMachPortContext       context;
-    Boolean                 shouldFreeInfo;
-    dns_service_discovery_ref  dns_client;
-    mach_port_t port;
-
-    if (selectedRow < 0) {
-        return;
-    }
-
-    context.version                 = 1;
-    context.info                    = 0;
-    context.retain                  = NULL;
-    context.release                 = NULL;
-    context.copyDescription        = NULL;
-
-    registerPort = [[srvportKeys objectAtIndex:selectedRow] intValue];
-    
-    dns_client = DNSServiceRegistrationCreate
-        (
-            [[srvnameKeys objectAtIndex:selectedRow] UTF8String],
-            [[srvtypeKeys objectAtIndex:selectedRow] UTF8String],
-            [[srvdomainKeys objectAtIndex:selectedRow] UTF8String],
-            registerPort,
-            [[srvtextKeys objectAtIndex:selectedRow] UTF8String],
-            reg_reply,
-            nil
-            );
-            
-    port = DNSServiceDiscoveryMachPort(dns_client);
-
-    if (port) {
-
-        //printf("port is %d\n", port);
-
-        cfMachPort = CFMachPortCreateWithPort ( kCFAllocatorDefault, port, ( CFMachPortCallBack ) MyHandleMachMessage,&context,&shouldFreeInfo );
-
-        rls = CFMachPortCreateRunLoopSource(NULL, cfMachPort, 0);
-        CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
-        CFRelease(rls);
-        [registeredDict setObject:[NSNumber numberWithUnsignedInt:(unsigned int)dns_client] forKey:[srvtypeKeys objectAtIndex:selectedRow]];
-    } else {
-        printf("Could not obtain client port\n");
-    }
-
-}
-
-- (IBAction)unregisterService:(id)sender
-{
-    int selectedRow = [serviceDisplayTable selectedRow];
-    NSString *key = [srvtypeKeys objectAtIndex:selectedRow];
-
-    NSNumber *refPtr = [registeredDict objectForKey:key];
-    dns_service_discovery_ref ref = (dns_service_discovery_ref)[refPtr unsignedIntValue];
-
-    if (ref) {
-        DNSServiceDiscoveryDeallocate(ref);
-        [registeredDict removeObjectForKey:key];
-    }
-}
-
--(void)tableView:(NSTableView *)theTableView setObjectValue:(id)object forTableColumn:(NSTableColumn *)tableColumn row:(int)row
-{
-    if (row<0) return;
-}
-
-- (int)numberOfRowsInTableView:(NSTableView *)theTableView     //Begin mandatory TableView methods
-{
-    return [srvtypeKeys count];
-}
-
-- (id)tableView:(NSTableView *)theTableView objectValueForTableColumn:(NSTableColumn *)theColumn row:(int)rowIndex
-{
-    if (theColumn == typeColumn) {
-        return [srvtypeKeys objectAtIndex:rowIndex];
-    }
-    if (theColumn == nameColumn) {
-        return [srvnameKeys objectAtIndex:rowIndex];
-    }
-    if (theColumn == portColumn) {
-        return [srvportKeys objectAtIndex:rowIndex];
-    }
-    if (theColumn == domainColumn) {
-        return [srvdomainKeys objectAtIndex:rowIndex];
-    }
-    if (theColumn == textColumn) {
-        return [srvtextKeys objectAtIndex:rowIndex];
-    }
-    
-    return(0);
-}                                              //End of mandatory TableView methods
-
-- (IBAction)removeSelected:(id)sender
-{
-    // remove the selected row and force a refresh
-
-    int selectedRow = [serviceDisplayTable selectedRow];
-
-    if (selectedRow) {
-
-        [srvtypeKeys removeObjectAtIndex:selectedRow];
-        [srvnameKeys removeObjectAtIndex:selectedRow];
-        [srvportKeys removeObjectAtIndex:selectedRow];
-        [srvdomainKeys removeObjectAtIndex:selectedRow];
-        [srvtextKeys removeObjectAtIndex:selectedRow];
-
-        [[NSUserDefaults standardUserDefaults] setObject:srvtypeKeys forKey:@"SrvTypeKeys"];
-        [[NSUserDefaults standardUserDefaults] setObject:srvnameKeys forKey:@"SrvNameKeys"];
-        [[NSUserDefaults standardUserDefaults] setObject:srvportKeys forKey:@"SrvPortKeys"];
-        [[NSUserDefaults standardUserDefaults] setObject:srvdomainKeys forKey:@"SrvDomainKeys"];
-        [[NSUserDefaults standardUserDefaults] setObject:srvtextKeys forKey:@"SrvTextKeys"];
-        
-        [serviceDisplayTable reloadData];
-    }
-}
-
-- (IBAction)addNewService:(id)sender
-{
-    // add new entries from the edit fields to the arrays for the defaults
-
-    if ([[serviceTypeField stringValue] length] && [[serviceNameField stringValue] length] && [[serviceDomainField stringValue] length]&& [[servicePortField stringValue] length]) {
-        [srvtypeKeys addObject:[serviceTypeField stringValue]];
-        [srvnameKeys addObject:[serviceNameField stringValue]];
-        [srvportKeys addObject:[servicePortField stringValue]];
-        [srvdomainKeys addObject:[serviceDomainField stringValue]];
-        [srvtextKeys addObject:[serviceTextField stringValue]];
-
-        [[NSUserDefaults standardUserDefaults] setObject:srvtypeKeys forKey:@"SrvTypeKeys"];
-        [[NSUserDefaults standardUserDefaults] setObject:srvnameKeys forKey:@"SrvNameKeys"];
-        [[NSUserDefaults standardUserDefaults] setObject:srvportKeys forKey:@"SrvPortKeys"];
-        [[NSUserDefaults standardUserDefaults] setObject:srvdomainKeys forKey:@"SrvDomainKeys"];
-        [[NSUserDefaults standardUserDefaults] setObject:srvtextKeys forKey:@"SrvTextKeys"];
-
-        [serviceDisplayTable reloadData];
-    } else {
-        NSBeep();
-    }
-
-}
-
-
-
-@end
diff --git a/mDNSMacOSX/Applications/DNSServiceRegistration/main.m b/mDNSMacOSX/Applications/DNSServiceRegistration/main.m
deleted file mode 100644 (file)
index c340509..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- * 
- * @APPLE_LICENSE_HEADER_END@
-
-    Change History (most recent first):
-
-$Log: main.m,v $
-Revision 1.4  2003/08/12 19:55:07  cheshire
-Update to APSL 2.0
-
- */
-
-#import <Cocoa/Cocoa.h>
-
-int main(int argc, const char *argv[])
-{
-    return NSApplicationMain(argc, argv);
-}
diff --git a/mDNSMacOSX/Applications/HAAutomounter/HAAutomounter.h b/mDNSMacOSX/Applications/HAAutomounter/HAAutomounter.h
deleted file mode 100644 (file)
index 7bb3e90..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- * 
- * @APPLE_LICENSE_HEADER_END@
-
-    Change History (most recent first):
-
-$Log: HAAutomounter.h,v $
-Revision 1.4  2003/08/12 19:55:08  cheshire
-Update to APSL 2.0
-
- */
-
-#import <Foundation/Foundation.h>
-
-
-@interface HAAutomounter : NSObject {
-
-    NSNetServiceBrowser *browser;
-    NSNetService       *resolver;
-}
-
-@end
diff --git a/mDNSMacOSX/Applications/HAAutomounter/HAAutomounter.m b/mDNSMacOSX/Applications/HAAutomounter/HAAutomounter.m
deleted file mode 100644 (file)
index 4aae5ed..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- * 
- * @APPLE_LICENSE_HEADER_END@
-
-    Change History (most recent first):
-
-$Log: HAAutomounter.m,v $
-Revision 1.4  2003/08/12 19:55:08  cheshire
-Update to APSL 2.0
-
- */
-
-#import "HAAutomounter.h"
-
-#import <AppKit/AppKit.h>
-
-#include <sys/types.h>
-#include "arpa/inet.h"
-#include <netinet/in.h>
-
-@implementation HAAutomounter
-
-- (id)init
-{
-    self = [super init];
-
-    browser = [[NSNetServiceBrowser alloc] init];
-
-    [browser setDelegate:self];
-
-    [browser searchForServicesOfType:@"_mountme._tcp." inDomain:@""];
-    
-    [browser scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode: NSDefaultRunLoopMode];
-
-    return self;
-}
-
-- (void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser didFindService:(NSNetService *)aNetService moreComing:(BOOL)moreComing
-{
-    if (resolver) {
-        [resolver release];
-    }
-
-    resolver = [[NSNetService alloc] initWithDomain:[aNetService domain] type:[aNetService type] name:[aNetService name]];
-    [resolver setDelegate:self];
-    [resolver scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode: NSDefaultRunLoopMode];
-
-    [resolver resolve];
-}
-
-
-- (void)netServiceDidResolveAddress:(NSNetService *)sender;
-{
-    if ([[sender addresses] count]) {
-    
-        // URL mount the volume
-        NSData *addr = [[sender addresses] objectAtIndex:0];
-        struct sockaddr_in *address = CFDataGetBytePtr((CFDataRef)addr);
-        NSString *ipAddr = [NSString stringWithCString:inet_ntoa(((struct in_addr)((struct sockaddr_in *)address)->sin_addr))];
-        int port = ((struct sockaddr_in *)address)->sin_port;
-        NSArray *txtArray = [[sender protocolSpecificInformation] componentsSeparatedByString:@","];
-
-        if ([txtArray count] == 3) {
-            NSString *user = [txtArray objectAtIndex:0];
-            NSString *password = [txtArray objectAtIndex:1];
-            NSString *share = [txtArray objectAtIndex:2];
-    
-            [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"afp://%@:%@@%@:%d/%@", user, password, ipAddr, port, share]]];
-        } else {
-            NSLog(@"incompatible format for txt record, s/b user,password,share");
-        }
-
-    } else {
-        NSLog(@"No address %@", sender);
-    }
-}
-
-- (void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser didRemoveService:(NSNetService *)aNetService moreComing:(BOOL)moreComing
-{
-    // unmount the volume
-}
-
-
-@end
diff --git a/mDNSMacOSX/Applications/HAAutomounter/HAAutomounter.pbproj/project.pbxproj b/mDNSMacOSX/Applications/HAAutomounter/HAAutomounter.pbproj/project.pbxproj
deleted file mode 100644 (file)
index 7d654f8..0000000
+++ /dev/null
@@ -1,296 +0,0 @@
-// !$*UTF8*$!
-{
-       archiveVersion = 1;
-       classes = {
-       };
-       objectVersion = 38;
-       objects = {
-               014CEA4F0018CE4811CA2923 = {
-                       buildRules = (
-                       );
-                       buildSettings = {
-                               COPY_PHASE_STRIP = NO;
-                               OPTIMIZATION_CFLAGS = "-O0";
-                       };
-                       isa = PBXBuildStyle;
-                       name = Development;
-               };
-               014CEA500018CE4811CA2923 = {
-                       buildRules = (
-                       );
-                       buildSettings = {
-                               COPY_PHASE_STRIP = YES;
-                       };
-                       isa = PBXBuildStyle;
-                       name = Deployment;
-               };
-//010
-//011
-//012
-//013
-//014
-//030
-//031
-//032
-//033
-//034
-               034768E6FF38A76511DB9C8B = {
-                       isa = PBXExecutableFileReference;
-                       path = HAAutomounter;
-                       refType = 3;
-               };
-//030
-//031
-//032
-//033
-//034
-//080
-//081
-//082
-//083
-//084
-               08FB7793FE84155DC02AAC07 = {
-                       buildStyles = (
-                               014CEA4F0018CE4811CA2923,
-                               014CEA500018CE4811CA2923,
-                       );
-                       isa = PBXProject;
-                       mainGroup = 08FB7794FE84155DC02AAC07;
-                       projectDirPath = "";
-                       targets = (
-                               08FB779FFE84155DC02AAC07,
-                       );
-               };
-               08FB7794FE84155DC02AAC07 = {
-                       children = (
-                               08FB7795FE84155DC02AAC07,
-                               08FB779DFE84155DC02AAC07,
-                               1AB674ADFE9D54B511CA2CBB,
-                       );
-                       isa = PBXGroup;
-                       name = HAAutomounter;
-                       refType = 4;
-               };
-               08FB7795FE84155DC02AAC07 = {
-                       children = (
-                               65CA1A4902808474000001D1,
-                               65CA1A4802808474000001D1,
-                               08FB7796FE84155DC02AAC07,
-                       );
-                       isa = PBXGroup;
-                       name = Source;
-                       refType = 4;
-               };
-               08FB7796FE84155DC02AAC07 = {
-                       isa = PBXFileReference;
-                       path = main.m;
-                       refType = 4;
-               };
-               08FB779DFE84155DC02AAC07 = {
-                       children = (
-                               08FB779EFE84155DC02AAC07,
-                               65CA1A4F0280888E000001D1,
-                               65CA1DCD028088B2000001D1,
-                               65CA1E9D02809D68000001D1,
-                               65CA1EB302809DA3000001D1,
-                               6547B9AF0282024900CE36C6,
-                       );
-                       isa = PBXGroup;
-                       name = "External Frameworks and Libraries";
-                       refType = 4;
-               };
-               08FB779EFE84155DC02AAC07 = {
-                       isa = PBXFrameworkReference;
-                       name = Foundation.framework;
-                       path = /System/Library/Frameworks/Foundation.framework;
-                       refType = 0;
-               };
-               08FB779FFE84155DC02AAC07 = {
-                       buildPhases = (
-                               08FB77A0FE84155DC02AAC07,
-                               08FB77A1FE84155DC02AAC07,
-                               08FB77A3FE84155DC02AAC07,
-                               08FB77A5FE84155DC02AAC07,
-                       );
-                       buildSettings = {
-                               FRAMEWORK_SEARCH_PATHS = "\"$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks\"";
-                               HEADER_SEARCH_PATHS = "";
-                               INSTALL_PATH = "$(HOME)/bin";
-                               LIBRARY_SEARCH_PATHS = "";
-                               OTHER_CFLAGS = "";
-                               OTHER_LDFLAGS = "";
-                               OTHER_REZFLAGS = "";
-                               PRODUCT_NAME = HAAutomounter;
-                               REZ_EXECUTABLE = YES;
-                               SECTORDER_FLAGS = "";
-                               WARNING_CFLAGS = "-Wmost -Wno-four-char-constants -Wno-unknown-pragmas";
-                       };
-                       dependencies = (
-                       );
-                       isa = PBXToolTarget;
-                       name = HAAutomounter;
-                       productInstallPath = "$(HOME)/bin";
-                       productName = HAAutomounter;
-                       productReference = 034768E6FF38A76511DB9C8B;
-                       shouldUseHeadermap = 1;
-               };
-               08FB77A0FE84155DC02AAC07 = {
-                       buildActionMask = 2147483647;
-                       files = (
-                               65CA1A4A02808474000001D1,
-                       );
-                       isa = PBXHeadersBuildPhase;
-               };
-               08FB77A1FE84155DC02AAC07 = {
-                       buildActionMask = 2147483647;
-                       files = (
-                               08FB77A2FE84155DC02AAC07,
-                               65CA1A4B02808474000001D1,
-                       );
-                       isa = PBXSourcesBuildPhase;
-               };
-               08FB77A2FE84155DC02AAC07 = {
-                       fileRef = 08FB7796FE84155DC02AAC07;
-                       isa = PBXBuildFile;
-                       settings = {
-                               ATTRIBUTES = (
-                               );
-                       };
-               };
-               08FB77A3FE84155DC02AAC07 = {
-                       buildActionMask = 2147483647;
-                       files = (
-                               08FB77A4FE84155DC02AAC07,
-                               65CA1DCC02808890000001D1,
-                               65CA1E9C028088B3000001D1,
-                               65CA1EB202809D68000001D1,
-                               65CA1EBC02809DA3000001D1,
-                               6547BBFD0282024900CE36C6,
-                       );
-                       isa = PBXFrameworksBuildPhase;
-               };
-               08FB77A4FE84155DC02AAC07 = {
-                       fileRef = 08FB779EFE84155DC02AAC07;
-                       isa = PBXBuildFile;
-                       settings = {
-                       };
-               };
-               08FB77A5FE84155DC02AAC07 = {
-                       buildActionMask = 2147483647;
-                       files = (
-                       );
-                       isa = PBXRezBuildPhase;
-               };
-//080
-//081
-//082
-//083
-//084
-//1A0
-//1A1
-//1A2
-//1A3
-//1A4
-               1AB674ADFE9D54B511CA2CBB = {
-                       children = (
-                               034768E6FF38A76511DB9C8B,
-                       );
-                       isa = PBXGroup;
-                       name = Products;
-                       refType = 4;
-               };
-//1A0
-//1A1
-//1A2
-//1A3
-//1A4
-//650
-//651
-//652
-//653
-//654
-               6547B9AF0282024900CE36C6 = {
-                       isa = PBXFrameworkReference;
-                       name = AppKit.framework;
-                       path = /System/Library/Frameworks/AppKit.framework;
-                       refType = 0;
-               };
-               6547BBFD0282024900CE36C6 = {
-                       fileRef = 6547B9AF0282024900CE36C6;
-                       isa = PBXBuildFile;
-                       settings = {
-                       };
-               };
-               65CA1A4802808474000001D1 = {
-                       isa = PBXFileReference;
-                       path = HAAutomounter.h;
-                       refType = 4;
-               };
-               65CA1A4902808474000001D1 = {
-                       isa = PBXFileReference;
-                       path = HAAutomounter.m;
-                       refType = 4;
-               };
-               65CA1A4A02808474000001D1 = {
-                       fileRef = 65CA1A4802808474000001D1;
-                       isa = PBXBuildFile;
-                       settings = {
-                       };
-               };
-               65CA1A4B02808474000001D1 = {
-                       fileRef = 65CA1A4902808474000001D1;
-                       isa = PBXBuildFile;
-                       settings = {
-                       };
-               };
-               65CA1A4F0280888E000001D1 = {
-                       isa = PBXFrameworkReference;
-                       name = CoreFoundation.framework;
-                       path = /System/Library/Frameworks/CoreFoundation.framework;
-                       refType = 0;
-               };
-               65CA1DCC02808890000001D1 = {
-                       fileRef = 65CA1A4F0280888E000001D1;
-                       isa = PBXBuildFile;
-                       settings = {
-                       };
-               };
-               65CA1DCD028088B2000001D1 = {
-                       isa = PBXFrameworkReference;
-                       name = CoreServices.framework;
-                       path = /System/Library/Frameworks/CoreServices.framework;
-                       refType = 0;
-               };
-               65CA1E9C028088B3000001D1 = {
-                       fileRef = 65CA1DCD028088B2000001D1;
-                       isa = PBXBuildFile;
-                       settings = {
-                       };
-               };
-               65CA1E9D02809D68000001D1 = {
-                       isa = PBXFrameworkReference;
-                       name = AppleShareClientCore.framework;
-                       path = /System/Library/Frameworks/AppleShareClientCore.framework;
-                       refType = 0;
-               };
-               65CA1EB202809D68000001D1 = {
-                       fileRef = 65CA1E9D02809D68000001D1;
-                       isa = PBXBuildFile;
-                       settings = {
-                       };
-               };
-               65CA1EB302809DA3000001D1 = {
-                       isa = PBXFrameworkReference;
-                       name = URLMount.framework;
-                       path = /System/Library/PrivateFrameworks/URLMount.framework;
-                       refType = 0;
-               };
-               65CA1EBC02809DA3000001D1 = {
-                       fileRef = 65CA1EB302809DA3000001D1;
-                       isa = PBXBuildFile;
-                       settings = {
-                       };
-               };
-       };
-       rootObject = 08FB7793FE84155DC02AAC07;
-}
diff --git a/mDNSMacOSX/Applications/HAAutomounter/main.m b/mDNSMacOSX/Applications/HAAutomounter/main.m
deleted file mode 100644 (file)
index 6ad4471..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- * 
- * @APPLE_LICENSE_HEADER_END@
-
-    Change History (most recent first):
-
-$Log: main.m,v $
-Revision 1.4  2003/08/12 19:55:08  cheshire
-Update to APSL 2.0
-
- */
-
-#import <Foundation/Foundation.h>
-
-#import "HAAutomounter.h"
-
-int main (int argc, const char * argv[]) {
-    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
-
-    [[HAAutomounter alloc] init];
-
-    [[NSRunLoop currentRunLoop] run];
-
-    [pool release];
-    return 0;
-}
index e4c230d3e666c4e851665d519e7428efcee254a9..388cdf27f5c3410f65a149549531e86fb2396a2c 100644 (file)
@@ -1,8 +1,10 @@
 /*
- * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
+ * Copright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
     Change History (most recent first):
 
 $Log: CFSocket.c,v $
-Revision 1.115.2.5  2005/01/28 05:02:06  cheshire
-<rdar://problem/3770559> SUPan: Replace IP TTL 255 check with local-subnet check
+Revision 1.157  2004/06/08 18:54:48  ksekar
+<rdar://problem/3681378>: mDNSResponder leaks after exploring in Printer Setup Utility
+
+Revision 1.156  2004/06/05 00:04:26  cheshire
+<rdar://problem/3668639>: wide-area domains should be returned in reg. domain enumeration
+
+Revision 1.155  2004/06/04 08:58:30  ksekar
+<rdar://problem/3668624>: Keychain integration for secure dynamic update
+
+Revision 1.154  2004/05/31 22:22:28  ksekar
+<rdar://problem/3668639>: wide-area domains should be returned in
+reg. domain enumeration
+
+Revision 1.153  2004/05/26 17:06:33  cheshire
+<rdar://problem/3668515>: Don't rely on CFSocketInvalidate() to remove RunLoopSource
+
+Revision 1.152  2004/05/18 23:51:26  cheshire
+Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
 
-Revision 1.115.2.4  2004/04/23 00:34:06  cheshire
-<rdar://problem/3628978>: mDNSResponder messages on wake
+Revision 1.151  2004/05/17 21:46:34  cheshire
+<rdar://problem/3616426>: When interface is turned off, browse "remove" events are delivered with interface index zero
 Take care to correctly update InterfaceIDs when a dormant interface comes back to life
 
-Revision 1.115.2.3  2004/04/08 23:18:11  cheshire
-<rdar://problem/3609972> When interface turned off, browse "remove" events delivered with interface index zero
-Refinement from Bob Bradley: Should use "mDNS *const m" instead of referencing mDNSStorage directly
+Revision 1.150  2004/05/13 04:54:20  ksekar
+Unified list copy/free code.  Added symetric list for
+
+Revision 1.149  2004/05/13 03:55:14  ksekar
+Fixed list traversal bug in FoundDefSearchDomain.
+
+Revision 1.148  2004/05/12 22:03:08  ksekar
+Made GetSearchDomainList a true platform-layer call (declaration moved
+from mDNSMacOSX.h to mDNSClientAPI.h), impelemted to return "local"
+only on non-OSX platforms.  Changed call to return a copy of the list
+to avoid shared memory issues.  Added a routine to free the list.
+
+Revision 1.147  2004/05/12 02:03:25  ksekar
+Non-local domains will only be browsed by default, and show up in
+_browse domain enumeration, if they contain an _browse._dns-sd ptr record.
+
+Revision 1.146  2004/04/27 02:49:15  cheshire
+<rdar://problem/3634655>: mDNSResponder leaks sockets on bind() error
+
+Revision 1.145  2004/04/21 03:08:03  cheshire
+Rename 'alias' to more descriptive name 'primary'
 
-Revision 1.115.2.2  2004/04/08 00:42:37  cheshire
+Revision 1.144  2004/04/21 03:04:35  cheshire
+Minor cleanup for clarity
+
+Revision 1.143  2004/04/21 03:03:30  cheshire
+Preparation work: AddInterfaceToList() should return pointer to structure it creates
+
+Revision 1.142  2004/04/21 02:49:11  cheshire
+To reduce future confusion, renamed 'TxAndRx' to 'McastTxRx'
+
+Revision 1.141  2004/04/21 02:20:47  cheshire
+Rename interface field 'CurrentlyActive' to more descriptive 'Exists'
+
+Revision 1.140  2004/04/14 23:09:29  ksekar
+Support for TSIG signed dynamic updates.
+
+Revision 1.139  2004/04/09 17:40:26  cheshire
+Remove unnecessary "Multicast" field -- it duplicates the semantics of the existing McastTxRx field
+
+Revision 1.138  2004/04/09 16:37:16  cheshire
+Suggestion from Bob Bradley:
+Move NumCacheRecordsForInterfaceID() to DNSCommon.c so it's available to all platform layers
+
+Revision 1.137  2004/04/08 00:59:55  cheshire
 <rdar://problem/3609972> When interface turned off, browse "remove" events delivered with interface index zero
-Unify use of the InterfaceID field, and make code that walks the list respect the CurrentlyActive flag
+Unify use of the InterfaceID field, and make code that walks the list respect the 'Exists' flag
 
-Revision 1.115.2.1  2004/04/07 01:08:15  cheshire
+Revision 1.136  2004/04/07 01:08:57  cheshire
 <rdar://problem/3609972> When interface turned off, browse "remove" events delivered with interface index zero
 
+Revision 1.135  2004/03/19 01:01:03  ksekar
+Fixed config file parsing to chop newline
+
+Revision 1.134  2004/03/13 01:57:34  ksekar
+<rdar://problem/3192546>: DynDNS: Dynamic update of service records
+
+Revision 1.133  2004/02/02 22:46:56  cheshire
+Move "CFRelease(dict);" inside the "if (dict)" check
+
+Revision 1.132  2004/01/28 02:30:08  ksekar
+Added default Search Domains to unicast browsing, controlled via
+Networking sharing prefs pane.  Stopped sending unicast messages on
+every interface.  Fixed unicast resolving via mach-port API.
+
+Revision 1.131  2004/01/27 22:57:48  cheshire
+<rdar://problem/3534352>: Need separate socket for issuing unicast queries
+
+Revision 1.130  2004/01/27 22:28:40  cheshire
+<rdar://problem/3541288>: Time to prune obsolete code for listening on port 53
+Additional lingering port 53 code deleted
+
+Revision 1.129  2004/01/27 20:15:23  cheshire
+<rdar://problem/3541288>: Time to prune obsolete code for listening on port 53
+
+Revision 1.128  2004/01/24 23:58:17  cheshire
+Change to use mDNSVal16() instead of shifting and ORing
+
+Revision 1.127  2004/01/24 04:59:16  cheshire
+Fixes so that Posix/Linux, OS9, Windows, and VxWorks targets build again
+
+Revision 1.126  2004/01/23 23:23:15  ksekar
+Added TCP support for truncated unicast messages.
+
+Revision 1.125  2004/01/22 03:43:09  cheshire
+Export constants like mDNSInterface_LocalOnly so that the client layers can use them
+
+Revision 1.124  2004/01/21 21:53:19  cheshire
+<rdar://problem/3448144>: Don't try to receive unicast responses if we're not the first to bind to the UDP port
+
+Revision 1.123  2004/01/20 03:18:25  cheshire
+Removed "LogMsg("Hey There!");" that evidently got checked in my mistake
+
+Revision 1.122  2003/12/17 20:43:59  cheshire
+<rdar://problem/3496728>: Syslog messages saying "sendto failed"
+
+Revision 1.121  2003/12/13 03:05:28  ksekar
+<rdar://problem/3192548>: DynDNS: Unicast query of service records
+
+Revision 1.120  2003/12/08 21:00:46  rpantos
+Changes to support mDNSResponder on Linux.
+
+Revision 1.119  2003/12/03 02:35:15  cheshire
+Also report value of m->timenow when logging sendto() failure
+
+Revision 1.118  2003/11/14 20:59:09  cheshire
+Clients can't use AssignDomainName macro because mDNSPlatformMemCopy is defined in mDNSPlatformFunctions.h.
+Best solution is just to combine mDNSClientAPI.h and mDNSPlatformFunctions.h into a single file.
+
+Revision 1.117  2003/11/08 22:18:29  cheshire
+<rdar://problem/3477870>: Don't need to show process ID in *every* mDNSResponder syslog message
+
+Revision 1.116  2003/09/23 16:39:49  cheshire
+When LogAllOperations is set, also report registration and deregistration of interfaces
+
 Revision 1.115  2003/09/10 00:45:55  cheshire
 <rdar://problem/3412328> Don't log "sendto failed" errors during the first two minutes of startup
 
 Revision 1.114  2003/08/27 02:55:13  cheshire
-<rdar://problem/3387910>:      Bug: Don't report mDNSPlatformSendUDP sendto errno 64 (Host is down)
+<rdar://problem/3387910>: Bug: Don't report mDNSPlatformSendUDP sendto errno 64 (Host is down)
 
 Revision 1.113  2003/08/19 22:20:00  cheshire
 <rdar://problem/3376721> Don't use IPv6 on interfaces that have a routable IPv4 address configured
@@ -102,7 +224,7 @@ Revision 1.99  2003/08/05 20:13:52  cheshire
 Ignore interfaces with the IN6_IFF_NOTREADY flag set
 
 Revision 1.98  2003/07/20 03:38:51  ksekar
-Bug #: 3320722
+<rdar://problem/3320722>
 Completed support for Unix-domain socket based API.
 
 Revision 1.97  2003/07/19 03:15:16  cheshire
@@ -195,7 +317,7 @@ it should say "%lu", etc.) and improve error logging (use strerror()
 to include textual error message as well as numeric error in log messages).
 
 Revision 1.73  2003/05/21 17:56:29  ksekar
-Bug #: <rdar://problem/3191277>:       mDNSResponder doesn't watch for IPv6 address changes
+<rdar://problem/3191277>: mDNSResponder doesn't watch for IPv6 address changes
 
 Revision 1.72  2003/05/14 18:48:41  cheshire
 <rdar://problem/3159272> mDNSResponder should be smarter about reconfigurations
@@ -230,12 +352,12 @@ Revision 1.65  2003/04/26 02:34:01  cheshire
 Add missing mDNSexport
 
 Revision 1.64  2003/04/15 16:48:06  jgraessl
-Bug #: 3228833
+<rdar://problem/3228833>
 Modified code in CFSocket notifier function to read all packets on the socket
 instead of reading only one packet every time the notifier was called.
 
 Revision 1.63  2003/04/15 16:33:50  jgraessl
-Bug #: 3221880
+<rdar://problem/3221880>
 Switched to our own copy of if_indextoname to improve performance.
 
 Revision 1.62  2003/03/28 01:55:44  cheshire
@@ -253,25 +375,25 @@ Revision 1.60  2003/03/15 04:40:38  cheshire
 Change type called "mDNSOpaqueID" to the more descriptive name "mDNSInterfaceID"
 
 Revision 1.59  2003/03/11 01:23:26  cheshire
-Bug #: 3194246 mDNSResponder socket problems
+<rdar://problem/3194246> mDNSResponder socket problems
 
 Revision 1.58  2003/03/06 01:43:04  cheshire
-Bug #: 3189097 Additional debugging code in mDNSResponder
+<rdar://problem/3189097> Additional debugging code in mDNSResponder
 Improve "LIST_ALL_INTERFACES" output
 
 Revision 1.57  2003/03/05 22:36:27  cheshire
-Bug #: 3186338 Loopback doesn't work with mDNSResponder-27
+<rdar://problem/3186338> Loopback doesn't work with mDNSResponder-27
 Temporary workaround: Skip loopback interface *only* if we found at least one v4 interface to use
 
 Revision 1.56  2003/03/05 01:50:38  cheshire
-Bug #: 3189097 Additional debugging code in mDNSResponder
+<rdar://problem/3189097> Additional debugging code in mDNSResponder
 
 Revision 1.55  2003/02/21 01:54:09  cheshire
-Bug #: 3099194 mDNSResponder needs performance improvements
+<rdar://problem/3099194> mDNSResponder needs performance improvements
 Switched to using new "mDNS_Execute" model (see "Implementer Notes.txt")
 
 Revision 1.54  2003/02/20 06:48:35  cheshire
-Bug #: 3169535 Xserve RAID needs to do interface-specific registrations
+<rdar://problem/3169535> Xserve RAID needs to do interface-specific registrations
 Reviewed by: Josh Graessley, Bob Bradley
 
 Revision 1.53  2003/01/29 02:21:23  cheshire
@@ -285,16 +407,16 @@ Fixed backwards comparison in SearchForInterfaceByName
 
 Revision 1.50  2003/01/13 23:49:44  jgraessl
 Merged changes for the following fixes in to top of tree:
-3086540  computer name changes not handled properly
-3124348  service name changes are not properly handled
-3124352  announcements sent in pairs, failing chattiness test
+<rdar://problem/3086540>  computer name changes not handled properly
+<rdar://problem/3124348>  service name changes are not properly handled
+<rdar://problem/3124352>  announcements sent in pairs, failing chattiness test
 
 Revision 1.49  2002/12/23 22:13:30  jgraessl
 Reviewed by: Stuart Cheshire
 Initial IPv6 support for mDNSResponder.
 
 Revision 1.48  2002/11/22 01:37:52  cheshire
-Bug #: 3108426 mDNSResponder is monitoring ServiceEntities instead of InterfaceEntities
+<rdar://problem/3108426> mDNSResponder is monitoring ServiceEntities instead of InterfaceEntities
 
 Revision 1.47  2002/09/21 20:44:51  zarzycki
 Added APSL info
@@ -321,14 +443,6 @@ Minor code tidying
 // Supporting routines to run mDNS on a CFRunLoop platform
 // ***************************************************************************
 
-// Open Transport 2.7.x on Mac OS 9 used to send Multicast DNS queries to UDP port 53,
-// before the Multicast DNS port was changed to 5353. For this reason, the mDNSResponder
-// in earlier versions of Mac OS X 10.2 Jaguar used to set mDNS_AllowPort53 to 1 to allow
-// it to also listen and answer queries on UDP port 53. Now that Transport 2.8 (included in
-// the Classic subsystem of Mac OS X 10.2 Jaguar) has been corrected to issue Multicast DNS
-// queries on UDP port 5353, this backwards-compatibility legacy support is no longer needed.
-#define mDNS_AllowPort53 0
-
 // For debugging, set LIST_ALL_INTERFACES to 1 to display all found interfaces,
 // including ones that mDNSResponder chooses not to use.
 #define LIST_ALL_INTERFACES 0
@@ -336,15 +450,14 @@ Minor code tidying
 // For enabling AAAA records over IPv4. Setting this to 0 sends only
 // A records over IPv4 and AAAA over IPv6. Setting this to 1 sends both
 // AAAA and A records over both IPv4 and IPv6.
-#define AAAA_OVER_V4   1
+#define AAAA_OVER_V4 1
 
 #include "mDNSClientAPI.h"          // Defines the interface provided to the client layer above
-#include "mDNSPlatformFunctions.h"     // Defines the interface to the supporting layer below
-#include "mDNSMacOSX.h"                                // Defines the specific types needed to run mDNS on this platform
+#include "mDNSMacOSX.h"             // Defines the specific types needed to run mDNS on this platform
 
 #include <stdio.h>
-#include <unistd.h>                                    // For select() and close()
-#include <stdarg.h>                                    // For va_list support
+#include <unistd.h>                 // For select() and close()
+#include <stdarg.h>                 // For va_list support
 #include <net/if.h>
 #include <net/if_dl.h>
 #include <sys/uio.h>
@@ -353,15 +466,19 @@ Minor code tidying
 #include <sys/sysctl.h>
 #include <fcntl.h>
 #include <sys/ioctl.h>
+#include <time.h>                   // platform support for UTC time
+#include <arpa/inet.h>              // for inet_aton
 
-#include <netinet/in.h>                                // For IP_RECVTTL
+#include <netinet/in.h>             // For IP_RECVTTL
 #ifndef IP_RECVTTL
-#define IP_RECVTTL 24  /* bool; receive reception TTL w/dgram */
+#define IP_RECVTTL 24               // bool; receive reception TTL w/dgram
 #endif
 
-#include <netinet/in_systm.h>          // For n_long, required by <netinet/ip.h> below
-#include <netinet/ip.h>                                // For IPTOS_LOWDELAY etc.
-#include <netinet6/in6_var.h>          // For IN6_IFF_NOTREADY etc.
+#include <netinet/in_systm.h>       // For n_long, required by <netinet/ip.h> below
+#include <netinet/ip.h>             // For IPTOS_LOWDELAY etc.
+#include <netinet6/in6_var.h>       // For IN6_IFF_NOTREADY etc.
+
+#include <Security/Security.h>
 
 // Code contributed by Dave Heller:
 // Define RUN_ON_PUMA_WITHOUT_IFADDRS to compile code that will
@@ -377,10 +494,40 @@ Minor code tidying
 #include <IOKit/IOMessage.h>
 #include <mach/mach_time.h>
 
+typedef struct AuthRecordListElem
+       {
+    struct AuthRecordListElem *next;
+    AuthRecord ar;
+       } AuthRecordListElem;
+
+typedef struct SearchListElem
+       {
+    struct SearchListElem *next;
+    domainname domain;
+    int flag;  
+    DNSQuestion browseQ;
+    DNSQuestion registerQ;
+    AuthRecordListElem *AuthRecs;
+       } SearchListElem;
+
+
 // ***************************************************************************
 // Globals
 
 static mDNSu32 clockdivisor = 0;
+static mDNSBool DNSConfigInitialized = mDNSfalse;
+#define MAX_SEARCH_DOMAINS 32
+
+// for domain enumeration and default browsing
+static SearchListElem *SearchList = NULL;    // where we search for _browse domains
+static DNSQuestion DefBrowseDomainQ;         // our local enumeration query for _browse domains
+static DNameListElem *DefBrowseList = NULL;  // cache of answers to above query (where we search for empty string browses)
+
+#define CONFIG_FILE "/etc/mDNSResponder.conf"
+#define LH_KEYCHAIN_DESC "Lighthouse Shared Secret"
+#define LH_KEYCHAIN_SERVICE "Lighthouse"
+#define SYS_KEYCHAIN_PATH "/Library/Keychains/System.keychain"
+#define LH_SUFFIX "members.mac.com."
 
 // ***************************************************************************
 // Macros
@@ -395,56 +542,6 @@ static mDNSu32 clockdivisor = 0;
 // ***************************************************************************
 // Functions
 
-// Note, this uses mDNS_vsnprintf instead of standard "vsnprintf", because mDNS_vsnprintf knows
-// how to print special data types like IP addresses and length-prefixed domain names
-#if MDNS_DEBUGMSGS
-mDNSexport void debugf_(const char *format, ...)
-       {
-       unsigned char buffer[512];
-       va_list ptr;
-       va_start(ptr,format);
-       buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0;
-       va_end(ptr);
-       fprintf(stderr,"%s\n", buffer);
-       fflush(stderr);
-       }
-#endif
-
-#if MDNS_DEBUGMSGS > 1
-mDNSexport void verbosedebugf_(const char *format, ...)
-       {
-       unsigned char buffer[512];
-       va_list ptr;
-       va_start(ptr,format);
-       buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0;
-       va_end(ptr);
-       fprintf(stderr,"%s\n", buffer);
-       fflush(stderr);
-       }
-#endif
-
-mDNSexport void LogMsg(const char *format, ...)
-       {
-       unsigned char buffer[512];
-       va_list ptr;
-       va_start(ptr,format);
-       buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0;
-       va_end(ptr);
-       
-       extern int debug_mode;
-       if (debug_mode)         // In debug_mode we write to stderr
-               {
-               fprintf(stderr,"%s\n", buffer);
-               fflush(stderr);
-               }
-       else                            // else, in production mode, we write to syslog
-               {
-               openlog("mDNSResponder", LOG_CONS | LOG_PERROR | LOG_PID, LOG_DAEMON);
-               syslog(LOG_ERR, "%s", buffer);
-               closelog();
-               }
-       }
-
 mDNSlocal struct ifaddrs* myGetIfAddrs(int refresh)
        {
        static struct ifaddrs *ifa = NULL;
@@ -473,53 +570,59 @@ mDNSlocal int myIfIndexToName(u_short index, char* name)
 mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(const mDNS *const m, mDNSu32 index)
        {
        NetworkInterfaceInfoOSX *i;
-       if (index == (uint32_t)~0) return((mDNSInterfaceID)~0);
+       if (index == (uint32_t)~0) return(mDNSInterface_LocalOnly);
        if (index)
                for (i = m->p->InterfaceList; i; i = i->next)
-                       if (i->ifinfo.InterfaceID && i->scope_id == index)      // Don't get tricked by inactive interfaces
-                               return(i->ifinfo.InterfaceID);
+                       // Don't get tricked by inactive interfaces with no InterfaceID set
+                       if (i->ifinfo.InterfaceID && i->scope_id == index) return(i->ifinfo.InterfaceID);
        return(mDNSNULL);
        }
        
 mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(const mDNS *const m, mDNSInterfaceID id)
        {
        NetworkInterfaceInfoOSX *i;
-       if (id == (mDNSInterfaceID)~0) return((mDNSu32)~0);
+       if (id == mDNSInterface_LocalOnly) return((mDNSu32)~0);
        if (id)
                for (i = m->p->InterfaceList; i; i = i->next)
-                       // Don't use i->ifinfo.InterfaceID here because we want to find inactive interfaces where that's not set
-                       if ((mDNSInterfaceID)i == id)
-                               return i->scope_id;
+                       // Don't use i->ifinfo.InterfaceID here, because we DO want to find inactive interfaces, which have no InterfaceID set
+                       if ((mDNSInterfaceID)i == id) return(i->scope_id);
        return 0;
        }
 
+// NOTE: If InterfaceID is NULL, it means, "send this packet through our anonymous unicast socket"
+// NOTE: If InterfaceID is non-NULL it means, "send this packet through our port 5353 socket on the specified interface"
 mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end,
-       mDNSInterfaceID InterfaceID, mDNSIPPort srcPort, const mDNSAddr *dst, mDNSIPPort dstPort)
+       mDNSInterfaceID InterfaceID, const mDNSAddr *dst, mDNSIPPort dstPort)
        {
        #pragma unused(m)
+       
+       // Note: For this platform we've adopted the convention that InterfaceIDs are secretly pointers
+       // to the NetworkInterfaceInfoOSX structure that holds the active sockets. The mDNSCore code
+       // doesn't know that and doesn't need to know that -- it just treats InterfaceIDs as opaque identifiers.
        NetworkInterfaceInfoOSX *info = (NetworkInterfaceInfoOSX *)InterfaceID;
+       char *ifa_name = info ? info->ifa_name : "unicast";
        struct sockaddr_storage to;
-       int s, err;
-
-       if (!InterfaceID) { LogMsg("mDNSPlatformSendUDP ERROR! Cannot send from zero InterfaceID"); return mStatus_BadParamErr; }
+       int s = -1, err;
 
        if (dst->type == mDNSAddrType_IPv4)
                {
-               struct sockaddr_in*     sin_to = (struct sockaddr_in*)&to;
-               sin_to->sin_len                 = sizeof(*sin_to);
-               sin_to->sin_family      = AF_INET;
-               sin_to->sin_port        = dstPort.NotAnInteger;
-               sin_to->sin_addr.s_addr = dst->ip.v4.NotAnInteger;
+               struct sockaddr_in *sin_to = (struct sockaddr_in*)&to;
+               sin_to->sin_len            = sizeof(*sin_to);
+               sin_to->sin_family         = AF_INET;
+               sin_to->sin_port           = dstPort.NotAnInteger;
+               sin_to->sin_addr.s_addr    = dst->ip.v4.NotAnInteger;
+               s = info ? info->ss.sktv4 : m->p->unicastsockets.sktv4;
                }
        else if (dst->type == mDNSAddrType_IPv6)
                {
-               struct sockaddr_in6* sin6_to = (struct sockaddr_in6*)&to;
-               sin6_to->sin6_len               = sizeof(*sin6_to);
-               sin6_to->sin6_family    = AF_INET6;
-               sin6_to->sin6_port              = dstPort.NotAnInteger;
-               sin6_to->sin6_flowinfo  = 0;
-               sin6_to->sin6_addr              = *(struct in6_addr*)&dst->ip.v6;
-               sin6_to->sin6_scope_id  = info->scope_id;
+               struct sockaddr_in6 *sin6_to = (struct sockaddr_in6*)&to;
+               sin6_to->sin6_len            = sizeof(*sin6_to);
+               sin6_to->sin6_family         = AF_INET6;
+               sin6_to->sin6_port           = dstPort.NotAnInteger;
+               sin6_to->sin6_flowinfo       = 0;
+               sin6_to->sin6_addr           = *(struct in6_addr*)&dst->ip.v6;
+               sin6_to->sin6_scope_id       = info ? info->scope_id : 0;
+               s = info ? info->ss.sktv6 : m->p->unicastsockets.sktv6;
                }
        else
                {
@@ -527,24 +630,12 @@ mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const DNSMessage *co
                return mStatus_BadParamErr;
                }
 
-       if (srcPort.NotAnInteger == MulticastDNSPort.NotAnInteger)
-               {
-               if      (dst->type == mDNSAddrType_IPv4) s = info->sktv4;
-               else if (dst->type == mDNSAddrType_IPv6) s = info->sktv6;
-               else                                     s = -1;
-               }
-#if mDNS_AllowPort53
-       else if (srcPort.NotAnInteger == UnicastDNSPort.NotAnInteger && dst->type == mDNSAddrType_IPv4)
-               s = info->skt53;
-#endif
-       else { LogMsg("Source port %d not allowed", (mDNSu16)srcPort.b[0]<<8 | srcPort.b[1]); return(-1); }
-       
        if (s >= 0)
                verbosedebugf("mDNSPlatformSendUDP: sending on InterfaceID %X %s/%d to %#a:%d skt %d",
-                       InterfaceID, info->ifa_name, dst->type, dst, (mDNSu16)dstPort.b[0]<<8 | dstPort.b[1], s);
+                       InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s);
        else
                verbosedebugf("mDNSPlatformSendUDP: NOT sending on InterfaceID %X %s/%d (socket of this type not available)",
-                       InterfaceID, info->ifa_name, dst->type, dst, (mDNSu16)dstPort.b[0]<<8 | dstPort.b[1]);
+                       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
@@ -553,14 +644,14 @@ mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const DNSMessage *co
        err = sendto(s, msg, (UInt8*)end - (UInt8*)msg, 0, (struct sockaddr *)&to, to.ss_len);
        if (err < 0)
                {
-               // Don't report EHOSTDOWN (i.e. ARP failure) to unicast destinations
+        // Don't report EHOSTDOWN (i.e. ARP failure) to unicast destinations
                if (errno == EHOSTDOWN && !mDNSAddressIsAllDNSLinkGroup(dst)) return(err);
-               // Don't report EHOSTUNREACH in the first two minutes after boot
+               // Don't report EHOSTUNREACH in the first three minutes after boot
                // This is because mDNSResponder intentionally starts up early in the boot process (See <rdar://problem/3409090>)
                // but this means that sometimes it starts before configd has finished setting up the multicast routing entries.
-               if (errno == EHOSTUNREACH && (mDNSu32)(m->timenow) < (mDNSu32)(mDNSPlatformOneSecond * 120)) return(err);
-               LogMsg("mDNSPlatformSendUDP sendto failed to send packet on InterfaceID %p %s/%ld to %#a:%d skt %d error %d errno %d (%s)",
-                       InterfaceID, info->ifa_name, dst->type, dst, (mDNSu16)dstPort.b[0]<<8 | dstPort.b[1], s, err, errno, strerror(errno));
+               if (errno == EHOSTUNREACH && (mDNSu32)(m->timenow) < (mDNSu32)(mDNSPlatformOneSecond * 180)) return(err);
+               LogMsg("mDNSPlatformSendUDP sendto failed to send packet on InterfaceID %p %s/%ld to %#a:%d skt %d error %d errno %d (%s) %lu",
+                       InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, errno, strerror(errno), (mDNSu32)(m->timenow));
                return(err);
                }
        
@@ -577,7 +668,7 @@ mDNSlocal ssize_t myrecvfrom(const int s, void *const buffer, const size_t max,
        struct cmsghdr *cmPtr;
        char            ancillary[1024];
 
-       *ttl = 255;                     // If kernel fails to provide TTL data (e.g. Jaguar doesn't) then assume the TTL was 255 as it should be
+       *ttl = 255;  // If kernel fails to provide TTL data (e.g. Jaguar doesn't) then assume the TTL was 255 as it should be
 
        // Set up the message
        msg.msg_name       = (caddr_t)from;
@@ -648,13 +739,16 @@ mDNSlocal ssize_t myrecvfrom(const int s, void *const buffer, const size_t max,
        return(n);
        }
 
+// On entry, context points to our CFSocketSet
+// If ss->info is NULL, we received this packet on our anonymous unicast socket
+// If ss->info is non-NULL, we received this packet on port 5353 on the indicated interface
 mDNSlocal void myCFSocketCallBack(CFSocketRef cfs, CFSocketCallBackType CallBackType, CFDataRef address, const void *data, void *context)
        {
        mDNSAddr senderAddr, destAddr;
        mDNSIPPort senderPort, destPort = MulticastDNSPort;
-       NetworkInterfaceInfoOSX *info = (NetworkInterfaceInfoOSX *)context;
-       mDNS *const m = info->m;
-       mDNSInterfaceID InterfaceID = info->ifinfo.InterfaceID;
+       const CFSocketSet *ss = (const CFSocketSet *)context;
+       mDNS *const m = ss->m;
+       const mDNSInterfaceID InterfaceID = ss->info ? ss->info->ifinfo.InterfaceID : mDNSNULL;
        DNSMessage packet;
        struct sockaddr_storage from;
        size_t fromlen = sizeof(from);
@@ -662,26 +756,20 @@ mDNSlocal void myCFSocketCallBack(CFSocketRef cfs, CFSocketCallBackType CallBack
        int err, s1 = -1, skt = CFSocketGetNative(cfs);
        int count = 0;
        
-       (void)address;  // Parameter not used
-       (void)data;             // Parameter not used
+       (void)address; // Parameter not used
+       (void)data;    // Parameter not used
        
-       if (CallBackType != kCFSocketReadCallBack) LogMsg("myCFSocketCallBack: Why is CallBackType %d not kCFSocketReadCallBack?", CallBackType);
+       if (CallBackType != kCFSocketReadCallBack)
+               LogMsg("myCFSocketCallBack: Why is CallBackType %d not kCFSocketReadCallBack?", CallBackType);
 
-#if mDNS_AllowPort53
-       if      (cfs == info->cfs53) { s1 = info->skt53; destPort = UnicastDNSPort; }
-       else
-#endif
-       if      (cfs == info->cfsv4) s1 = info->sktv4;
-       else if (cfs == info->cfsv6) s1 = info->sktv6;
+       if      (cfs == ss->cfsv4) s1 = ss->sktv4;
+       else if (cfs == ss->cfsv6) s1 = ss->sktv6;
 
        if (s1 < 0 || s1 != skt)
                {
                LogMsg("myCFSocketCallBack: s1 %d native socket %d, cfs %p", s1, skt, cfs);
-#if mDNS_AllowPort53
-               LogMsg("myCFSocketCallBack: cfs53 %p, skt53 %d", info->cfs53, info->skt53);
-#endif
-               LogMsg("myCFSocketCallBack: cfsv4 %p, sktv4 %d", info->cfsv4, info->sktv4);
-               LogMsg("myCFSocketCallBack: cfsv6 %p, sktv6 %d", info->cfsv6, info->sktv6);
+               LogMsg("myCFSocketCallBack: cfsv4 %p, sktv4 %d", ss->cfsv4, ss->sktv4);
+               LogMsg("myCFSocketCallBack: cfsv6 %p, sktv6 %d", ss->cfsv6, ss->sktv6);
                }
 
        mDNSu8 ttl;
@@ -708,33 +796,22 @@ mDNSlocal void myCFSocketCallBack(CFSocketRef cfs, CFSocketCallBackType CallBack
                        return;
                        }
 
-               if (mDNSAddrIsDNSMulticast(&destAddr))
-                       {
-                       // Even though we indicated a specific interface in the IP_ADD_MEMBERSHIP call, a weirdness of the
-                       // sockets API means that even though this socket has only officially joined the multicast group
-                       // on one specific interface, the kernel will still deliver multicast packets to it no matter which
-                       // interface they arrive on. According to the official Unix Powers That Be, this is Not A Bug.
-                       // To work around this weirdness, we use the IP_RECVIF option to find the name of the interface
-                       // on which the packet arrived, and ignore the packet if it really arrived on some other interface.
-                       if (strcmp(info->ifa_name, packetifname))
-                               {
-                               verbosedebugf("myCFSocketCallBack got a packet from %#a to %#a on interface %#a/%s (Ignored -- really arrived on interface %s)",
-                                       &senderAddr, &destAddr, &info->ifinfo.ip, info->ifa_name, packetifname);
-                               return;
-                               }
-                       else
-                               verbosedebugf("myCFSocketCallBack got a packet from %#a to %#a on interface %#a/%s",
-                                       &senderAddr, &destAddr, &info->ifinfo.ip, info->ifa_name);
-                       }
+               // Even though we indicated a specific interface in the IP_ADD_MEMBERSHIP call, a weirdness of the
+               // sockets API means that even though this socket has only officially joined the multicast group
+               // on one specific interface, the kernel will still deliver multicast packets to it no matter which
+               // interface they arrive on. According to the official Unix Powers That Be, this is Not A Bug.
+               // To work around this weirdness, we use the IP_RECVIF option to find the name of the interface
+               // on which the packet arrived, and ignore the packet if it really arrived on some other interface.
+               if (!ss->info)
+                       verbosedebugf("myCFSocketCallBack got a packet from %#a to %#a on unicast socket", &senderAddr, &destAddr);
+               else if (!strcmp(ss->info->ifa_name, packetifname))
+                       verbosedebugf("myCFSocketCallBack got a packet from %#a to %#a on interface %#a/%s",
+                               &senderAddr, &destAddr, &ss->info->ifinfo.ip, ss->info->ifa_name);
                else
                        {
-                       verbosedebugf("myCFSocketCallBack got a unicast from %#a to %#a on interface %#a/%s packetifname %s)",
-                               &senderAddr, &destAddr, &info->ifinfo.ip, info->ifa_name, packetifname);
-                       // Note: For unicast packets, try to find the matching mDNSCore interface object 
-                       // (though we may not be able to, for unicast packets received over something like a PPP link)
-                       NetworkInterfaceInfo *intf = m->HostInterfaces;
-                       while (intf && strcmp(intf->ifname, packetifname)) intf = intf->next;
-                       if (intf) InterfaceID = intf->InterfaceID;
+                       verbosedebugf("myCFSocketCallBack got a packet from %#a to %#a on interface %#a/%s (Ignored -- really arrived on interface %s)",
+                               &senderAddr, &destAddr, &ss->info->ifinfo.ip, ss->info->ifa_name, packetifname);
+                       return;
                        }
                
                if (err < (int)sizeof(DNSMessageHeader)) { debugf("myCFSocketCallBack packet length (%d) too short", err); return; }
@@ -772,7 +849,177 @@ mDNSlocal void myCFSocketCallBack(CFSocketRef cfs, CFSocketCallBackType CallBack
                        LogMsg("myCFSocketCallBack 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);
                sleep(1);               // After logging this error, rate limit so we don't flood syslog
+               } 
+       }
+
+// TCP socket support for unicast DNS and Dynamic DNS Update
+
+typedef struct
+       {
+    TCPConnectionCallback callback;
+    void *context;
+    int connected;
+       } tcpInfo_t;
+
+mDNSlocal void tcpCFSocketCallback(CFSocketRef cfs, CFSocketCallBackType CallbackType, CFDataRef address,
+                                                                  const void *data, void *context)
+       {
+       #pragma unused(CallbackType, address, data)
+       mDNSBool connect = mDNSfalse;  
+       
+       tcpInfo_t *info = context;
+       if (!info->connected)
+               {
+               connect = mDNStrue;
+               info->connected = mDNStrue;  // prevent connected flag from being set in future callbacks
                }
+       info->callback(CFSocketGetNative(cfs), info->context, connect);
+       // NOTE: the callback may call CloseConnection here, which frees the context structure!  
+       }
+
+mDNSexport mStatus mDNSPlatformTCPConnect(const mDNSAddr *dst, mDNSOpaque16 dstport, mDNSInterfaceID InterfaceID,
+                                                                                 TCPConnectionCallback callback, void *context, int *descriptor)
+       {
+       int sd, on = 1;  // "on" for setsockopt
+       struct sockaddr_in saddr;
+       CFSocketContext cfContext = { 0, NULL, 0, 0, 0 };  
+       tcpInfo_t *info;
+       CFSocketRef sr;
+       CFRunLoopSourceRef rls;
+       CFOptionFlags srFlags;
+       
+       (void)InterfaceID;      //!!!KRS use this if non-zero!!!
+
+       *descriptor = 0;
+       if (dst->type != mDNSAddrType_IPv4)
+               {
+               LogMsg("ERROR: mDNSPlatformTCPConnect - attempt to connect to an IPv6 address: opperation not supported");
+               return mStatus_UnknownErr;
+               }
+
+       sd = socket(AF_INET, SOCK_STREAM, 0);
+       if (sd < 0)
+               {
+               LogMsg("ERROR: socket; %s", strerror(errno));
+               return mStatus_UnknownErr;
+               }
+       // set non-blocking
+       if (fcntl(sd, F_SETFL, O_NONBLOCK) < 0)
+               {
+               LogMsg("ERROR: setsockopt O_NONBLOCK - %s", strerror(errno));
+               return mStatus_UnknownErr;
+               }
+       
+       // receive interface identifiers
+       if (setsockopt(sd, IPPROTO_IP, IP_RECVIF, &on, sizeof(on)) < 0)
+               {
+               LogMsg("setsockopt IP_RECVIF - %s", strerror(errno));
+               return mStatus_UnknownErr;
+               }
+       // set up CF wrapper, add to Run Loop
+       info = mallocL("mDNSPlatformTCPConnect", sizeof(tcpInfo_t));
+       info->callback = callback;
+       info->context = context;
+       cfContext.info = info;
+       sr = CFSocketCreateWithNative(kCFAllocatorDefault, sd, kCFSocketReadCallBack | kCFSocketConnectCallBack,
+                                                                 tcpCFSocketCallback, &cfContext);
+       if (!sr)
+               {
+               LogMsg("ERROR: mDNSPlatformTCPConnect - CFSocketRefCreateWithNative failed");
+               freeL("mDNSPlatformTCPConnect", info);
+               return mStatus_UnknownErr;
+               }
+
+       // prevent closing of native socket
+       srFlags = CFSocketGetSocketFlags(sr);
+       CFSocketSetSocketFlags(sr, srFlags & (~kCFSocketCloseOnInvalidate));
+       
+       rls = CFSocketCreateRunLoopSource(kCFAllocatorDefault, sr, 0);
+       if (!rls) 
+               {
+               LogMsg("ERROR: mDNSPlatformTCPConnect - CFSocketCreateRunLoopSource failed");
+               freeL("mDNSPlatformTCPConnect", info);
+               return mStatus_UnknownErr;
+               }
+       
+       CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
+       CFRelease(rls);
+       
+       // initiate connection wth peer
+       bzero(&saddr, sizeof(saddr));
+       saddr.sin_family = AF_INET;
+       saddr.sin_port = dstport.NotAnInteger;
+       memcpy(&saddr.sin_addr, &dst->ip.v4.NotAnInteger, sizeof(saddr.sin_addr));
+       if (connect(sd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0)
+               {
+               if (errno == EINPROGRESS)
+                       {
+                       info->connected = 0;
+                       *descriptor= sd;
+                       return mStatus_ConnectionPending;
+                       }
+               LogMsg("ERROR: mDNSPlatformTCPConnect - connect failed: %s", strerror(errno));
+               freeL("mDNSPlatformTCPConnect", info);
+               CFSocketInvalidate(sr);
+               return mStatus_ConnectionFailed;
+               }
+       info->connected = 1;
+       *descriptor = sd;
+       return mStatus_ConnectionEstablished;
+       }
+
+mDNSexport void mDNSPlatformTCPCloseConnection(int sd)
+       {
+       CFSocketContext cfContext;
+       tcpInfo_t *info;
+       CFSocketRef sr;
+
+    // get the CFSocket for the descriptor, if it exists
+       sr = CFSocketCreateWithNative(kCFAllocatorDefault, sd, NULL, NULL, NULL);
+       if (!sr)
+               {
+               LogMsg("ERROR: mDNSPlatformTCPCloseConnection - attempt to close a socket that was not properly created");
+               return;
+               }
+       CFSocketGetContext(sr, &cfContext);
+       if (!cfContext.info)
+               {
+               LogMsg("ERROR: mDNSPlatformTCPCloseConnection - could not retreive tcpInfo from socket context");
+               CFRelease(sr);
+               return;
+               }
+       CFRelease(sr);  // this only releases the copy we allocated with CreateWithNative above
+       
+       info = cfContext.info;
+       CFSocketInvalidate(sr);
+       CFRelease(sr);  
+       close(sd);
+       freeL("mDNSPlatformTCPCloseConnection", info);  
+       }
+
+mDNSexport int mDNSPlatformReadTCP(int sd, void *buf, int buflen)
+       {
+       int nread = recv(sd, buf, buflen, 0);
+       if (nread < 0)
+               {
+               if (errno == EAGAIN) return 0;  // no data available (call would block)
+               LogMsg("ERROR: mDNSPlatformReadTCP - recv: %s", strerror(errno));
+               return -1;
+               }
+       return nread;
+       }
+
+mDNSexport int mDNSPlatformWriteTCP(int sd, const char *msg, int len)
+       {
+       int nsent = send(sd, msg, len, 0);
+
+       if (nsent < 0)
+               {
+               if (errno == EAGAIN) return 0;  // blocked
+               LogMsg("ERROR: mDNSPlatformWriteTCP - sendL %s", strerror(errno));
+               return -1;
+               }
+       return nsent;
        }
 
 // This gets the text of the field currently labelled "Computer Name" in the Sharing Prefs Control Panel
@@ -798,60 +1045,70 @@ mDNSlocal void GetUserSpecifiedRFC1034ComputerName(domainlabel *const namelabel)
                }
        }
 
-mDNSlocal mStatus SetupSocket(NetworkInterfaceInfoOSX *i, mDNSIPPort port, int *s, CFSocketRef *c)
+// 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(CFSocketSet *cp, mDNSIPPort port, const mDNSAddr *ifaddr, u_short sa_family)
        {
+       int         *s        = (sa_family == AF_INET) ? &cp->sktv4 : &cp->sktv6;
+       CFSocketRef *c        = (sa_family == AF_INET) ? &cp->cfsv4 : &cp->cfsv6;
+       CFRunLoopSourceRef *r = (sa_family == AF_INET) ? &cp->rlsv4 : &cp->rlsv6;
        const int on = 1;
        const int twofivefive = 255;
+       mStatus err = mStatus_NoError;
+       char *errstr = mDNSNULL;
 
        if (*s >= 0) { LogMsg("SetupSocket ERROR: socket %d is already set", *s); return(-1); }
        if (*c) { LogMsg("SetupSocket ERROR: CFSocketRef %p is already set", *c); return(-1); }
 
        // Open the socket...
-       int skt = socket(i->sa_family, SOCK_DGRAM, IPPROTO_UDP);
+       int skt = socket(sa_family, SOCK_DGRAM, IPPROTO_UDP);
        if (skt < 0) { LogMsg("socket error %d errno %d (%s)", skt, errno, strerror(errno)); return(skt); }
 
-       // ... with a shared UDP port
-       mStatus err = setsockopt(skt, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on));
-       if (err < 0) { LogMsg("setsockopt - SO_REUSEPORT error %ld errno %d (%s)", err, errno, strerror(errno)); return(err); }
+       // ... with a shared UDP port, if it's for multicast receiving
+       if (port.NotAnInteger) err = setsockopt(skt, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on));
+       if (err < 0) { errstr = "setsockopt - SO_REUSEPORT"; goto fail; }
 
-       if (i->sa_family == AF_INET)
+       if (sa_family == AF_INET)
                {
                // We want to receive destination addresses
                err = setsockopt(skt, IPPROTO_IP, IP_RECVDSTADDR, &on, sizeof(on));
-               if (err < 0) { LogMsg("setsockopt - IP_RECVDSTADDR error %ld errno %d (%s)", err, errno, strerror(errno)); return(err); }
+               if (err < 0) { errstr = "setsockopt - IP_RECVDSTADDR"; goto fail; }
                
                // We want to receive interface identifiers
                err = setsockopt(skt, IPPROTO_IP, IP_RECVIF, &on, sizeof(on));
-               if (err < 0) { LogMsg("setsockopt - IP_RECVIF error %ld errno %d (%s)", err, errno, strerror(errno)); return(err); }
+               if (err < 0) { errstr = "setsockopt - IP_RECVIF"; goto fail; }
                
                // We want to receive packet TTL value so we can check it
                err = setsockopt(skt, IPPROTO_IP, IP_RECVTTL, &on, sizeof(on));
                // We ignore errors here -- we already know Jaguar doesn't support this, but we can get by without it
                
-               // Add multicast group membership on this interface
-               struct in_addr addr = { i->ifinfo.ip.ip.v4.NotAnInteger };
-               struct ip_mreq imr;
-               imr.imr_multiaddr.s_addr = AllDNSLinkGroup.NotAnInteger;
-               imr.imr_interface        = addr;
-               err = setsockopt(skt, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(imr));
-               if (err < 0) { LogMsg("setsockopt - IP_ADD_MEMBERSHIP error %ld errno %d (%s)", err, errno, strerror(errno)); return(err); }
-               
-               // Specify outgoing interface too
-               err = setsockopt(skt, IPPROTO_IP, IP_MULTICAST_IF, &addr, sizeof(addr));
-               if (err < 0) { LogMsg("setsockopt - IP_MULTICAST_IF error %ld errno %d (%s)", err, errno, strerror(errno)); return(err); }
+               // Add multicast group membership on this interface, if it's for multicast receiving
+               if (port.NotAnInteger)
+                       {
+                       struct in_addr addr = { ifaddr->ip.v4.NotAnInteger };
+                       struct ip_mreq imr;
+                       imr.imr_multiaddr.s_addr = AllDNSLinkGroup.NotAnInteger;
+                       imr.imr_interface        = addr;
+                       err = setsockopt(skt, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(imr));
+                       if (err < 0) { errstr = "setsockopt - IP_ADD_MEMBERSHIP"; goto fail; }
+                       
+                       // Specify outgoing interface too
+                       err = setsockopt(skt, IPPROTO_IP, IP_MULTICAST_IF, &addr, sizeof(addr));
+                       if (err < 0) { errstr = "setsockopt - IP_MULTICAST_IF"; goto fail; }
+                       }
                
                // Send unicast packets with TTL 255
                err = setsockopt(skt, IPPROTO_IP, IP_TTL, &twofivefive, sizeof(twofivefive));
-               if (err < 0) { LogMsg("setsockopt - IP_TTL error %ld errno %d (%s)", err, errno, strerror(errno)); return(err); }
+               if (err < 0) { errstr = "setsockopt - IP_TTL"; goto fail; }
                
                // And multicast packets with TTL 255 too
                err = setsockopt(skt, IPPROTO_IP, IP_MULTICAST_TTL, &twofivefive, sizeof(twofivefive));
-               if (err < 0) { LogMsg("setsockopt - IP_MULTICAST_TTL error %ld errno %d (%s)", err, errno, strerror(errno)); return(err); }
+               if (err < 0) { errstr = "setsockopt - IP_MULTICAST_TTL"; goto fail; }
 
                // Mark packets as high-throughput/low-delay (i.e. lowest reliability) to get maximum 802.11 multicast rate
                const int ip_tosbits = IPTOS_LOWDELAY | IPTOS_THROUGHPUT;
                err = setsockopt(skt, IPPROTO_IP, IP_TOS, &ip_tosbits, sizeof(ip_tosbits));
-               if (err < 0) { LogMsg("setsockopt - IP_TOS error %ld errno %d (%s)", err, errno, strerror(errno)); return(err); }
+               if (err < 0) { errstr = "setsockopt - IP_TOS"; goto fail; }
 
                // And start listening for packets
                struct sockaddr_in listening_sockaddr;
@@ -859,83 +1116,84 @@ mDNSlocal mStatus SetupSocket(NetworkInterfaceInfoOSX *i, mDNSIPPort port, int *
                listening_sockaddr.sin_port        = port.NotAnInteger;
                listening_sockaddr.sin_addr.s_addr = 0; // Want to receive multicasts AND unicasts on this socket
                err = bind(skt, (struct sockaddr *) &listening_sockaddr, sizeof(listening_sockaddr));
-               if (err)
-                       {
-                       // If we fail to bind to port 53 (because we're not root), that's okay, just tidy up and silently continue
-                       if (port.NotAnInteger == UnicastDNSPort.NotAnInteger) { close(skt); err = 0; }
-                       else LogMsg("bind error %ld errno %d (%s)", err, errno, strerror(errno));
-                       return(err);
-                       }
+               if (err) { errstr = "bind"; goto fail; }
                }
-       else if (i->sa_family == AF_INET6)
+       else if (sa_family == AF_INET6)
                {
                // We want to receive destination addresses and receive interface identifiers
                err = setsockopt(skt, IPPROTO_IPV6, IPV6_PKTINFO, &on, sizeof(on));
-               if (err < 0) { LogMsg("setsockopt - IPV6_PKTINFO error %ld errno %d (%s)", err, errno, strerror(errno)); return(err); }
+               if (err < 0) { errstr = "setsockopt - IPV6_PKTINFO"; goto fail; }
                
                // We want to receive packet hop count value so we can check it
                err = setsockopt(skt, IPPROTO_IPV6, IPV6_HOPLIMIT, &on, sizeof(on));
-               if (err < 0) { LogMsg("setsockopt - IPV6_HOPLIMIT error %ld errno %d (%s)", err, errno, strerror(errno)); return(err); }
+               if (err < 0) { errstr = "setsockopt - IPV6_HOPLIMIT"; goto fail; }
                
                // We want to receive only IPv6 packets, without this option, we may
                // get IPv4 addresses as mapped addresses.
                err = setsockopt(skt, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
-               if (err < 0) { LogMsg("setsockopt - IPV6_V6ONLY error %ld errno %d (%s)", err, errno, strerror(errno)); return(err); }
+               if (err < 0) { errstr = "setsockopt - IPV6_V6ONLY"; goto fail; }
                
-               // Add multicast group membership on this interface
-               int     interface_id = if_nametoindex(i->ifa_name);
-               struct ipv6_mreq i6mr;
-               i6mr.ipv6mr_interface = interface_id;
-               i6mr.ipv6mr_multiaddr = *(struct in6_addr*)&AllDNSLinkGroupv6;
-               err = setsockopt(skt, IPPROTO_IPV6, IPV6_JOIN_GROUP, &i6mr, sizeof(i6mr));
-               if (err < 0) { LogMsg("setsockopt - IPV6_JOIN_GROUP error %ld errno %d (%s)", err, errno, strerror(errno)); return(err); }
-               
-               // Specify outgoing interface too
-               err = setsockopt(skt, IPPROTO_IPV6, IPV6_MULTICAST_IF, &interface_id, sizeof(interface_id));
-               if (err < 0) { LogMsg("setsockopt - IPV6_MULTICAST_IF error %ld errno %d (%s)", err, errno, strerror(errno)); return(err); }
+               if (port.NotAnInteger)
+                       {
+                       // Add multicast group membership on this interface, if it's for multicast receiving
+                       int interface_id = if_nametoindex(cp->info->ifa_name);
+                       struct ipv6_mreq i6mr;
+                       i6mr.ipv6mr_interface = interface_id;
+                       i6mr.ipv6mr_multiaddr = *(struct in6_addr*)&AllDNSLinkGroupv6;
+                       err = setsockopt(skt, IPPROTO_IPV6, IPV6_JOIN_GROUP, &i6mr, sizeof(i6mr));
+                       if (err < 0) { errstr = "setsockopt - IPV6_JOIN_GROUP"; goto fail; }
+                       
+                       // Specify outgoing interface too
+                       err = setsockopt(skt, IPPROTO_IPV6, IPV6_MULTICAST_IF, &interface_id, sizeof(interface_id));
+                       if (err < 0) { errstr = "setsockopt - IPV6_MULTICAST_IF"; goto fail; }
+                       }
                
                // Send unicast packets with TTL 255
                err = setsockopt(skt, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &twofivefive, sizeof(twofivefive));
-               if (err < 0) { LogMsg("setsockopt - IPV6_UNICAST_HOPS error %ld errno %d (%s)", err, errno, strerror(errno)); return(err); }
+               if (err < 0) { errstr = "setsockopt - IPV6_UNICAST_HOPS"; goto fail; }
                
                // And multicast packets with TTL 255 too
                err = setsockopt(skt, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &twofivefive, sizeof(twofivefive));
-               if (err < 0) { LogMsg("setsockopt - IPV6_MULTICAST_HOPS error %ld errno %d (%s)", err, errno, strerror(errno)); return(err); }
+               if (err < 0) { errstr = "setsockopt - IPV6_MULTICAST_HOPS"; goto fail; }
                
                // Note: IPV6_TCLASS appears not to be implemented on OS X right now (or indeed on ANY version of Unix?)
                #ifdef IPV6_TCLASS
                // Mark packets as high-throughput/low-delay (i.e. lowest reliability) to get maximum 802.11 multicast rate
                int tclass = IPTOS_LOWDELAY | IPTOS_THROUGHPUT; // This may not be right (since tclass is not implemented on OS X, I can't test it)
                err = setsockopt(skt, IPPROTO_IPV6, IPV6_TCLASS, &tclass, sizeof(tclass));
-               if (err < 0) { LogMsg("setsockopt - IPV6_TCLASS error %ld errno %d (%s)", err, errno, strerror(errno)); return(err); }
+               if (err < 0) { errstr = "setsockopt - IPV6_TCLASS"; goto fail; }
                #endif
                
                // Want to receive our own packets
                err = setsockopt(skt, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &on, sizeof(on));
-               if (err < 0) { LogMsg("setsockopt - IPV6_MULTICAST_LOOP error %ld errno %d (%s)", err, errno, strerror(errno)); return(err); }
+               if (err < 0) { errstr = "setsockopt - IPV6_MULTICAST_LOOP"; goto fail; }
                
                // And start listening for packets
                struct sockaddr_in6 listening_sockaddr6;
                bzero(&listening_sockaddr6, sizeof(listening_sockaddr6));
-               listening_sockaddr6.sin6_len             = sizeof(listening_sockaddr6);
+               listening_sockaddr6.sin6_len         = sizeof(listening_sockaddr6);
                listening_sockaddr6.sin6_family      = AF_INET6;
                listening_sockaddr6.sin6_port        = port.NotAnInteger;
-               listening_sockaddr6.sin6_flowinfo        = 0;
+               listening_sockaddr6.sin6_flowinfo    = 0;
 //             listening_sockaddr6.sin6_addr = IN6ADDR_ANY_INIT; // Want to receive multicasts AND unicasts on this socket
-               listening_sockaddr6.sin6_scope_id        = 0;
+               listening_sockaddr6.sin6_scope_id    = 0;
                err = bind(skt, (struct sockaddr *) &listening_sockaddr6, sizeof(listening_sockaddr6));
-               if (err) { LogMsg("bind error %ld errno %d (%s)", err, errno, strerror(errno)); return(err); }
+               if (err) { errstr = "bind"; goto fail; }
                }
        
        fcntl(skt, F_SETFL, fcntl(skt, F_GETFL, 0) | O_NONBLOCK); // set non-blocking
        *s = skt;
-       CFSocketContext myCFSocketContext = { 0, i->ifinfo.InterfaceID, NULL, NULL, NULL };
+       CFSocketContext myCFSocketContext = { 0, cp, NULL, NULL, NULL };
        *c = CFSocketCreateWithNative(kCFAllocatorDefault, *s, kCFSocketReadCallBack, myCFSocketCallBack, &myCFSocketContext);
-       CFRunLoopSourceRef rls = CFSocketCreateRunLoopSource(kCFAllocatorDefault, *c, 0);
-       CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
-       CFRelease(rls);
+       *r = CFSocketCreateRunLoopSource(kCFAllocatorDefault, *c, 0);
+       CFRunLoopAddSource(CFRunLoopGetCurrent(), *r, kCFRunLoopDefaultMode);
        
        return(err);
+
+fail:
+       LogMsg("%s error %ld errno %d (%s)", errstr, err, errno, strerror(errno));
+       close(skt);
+       return(err);
        }
 
 mDNSlocal mStatus SetupAddr(mDNSAddr *ip, const struct sockaddr *const sa)
@@ -962,7 +1220,7 @@ mDNSlocal mStatus SetupAddr(mDNSAddr *ip, const struct sockaddr *const sa)
                }
        }
 
-mDNSlocal mStatus AddInterfaceToList(mDNS *const m, struct ifaddrs *ifa)
+mDNSlocal NetworkInterfaceInfoOSX *AddInterfaceToList(mDNS *const m, struct ifaddrs *ifa)
        {
        mDNSu32 scope_id = if_nametoindex(ifa->ifa_name);
        mDNSAddr ip;
@@ -972,49 +1230,44 @@ mDNSlocal mStatus AddInterfaceToList(mDNS *const m, struct ifaddrs *ifa)
                if (scope_id == (*p)->scope_id && mDNSSameAddress(&ip, &(*p)->ifinfo.ip))
                        {
                        debugf("AddInterfaceToList: Found existing interface %u with address %#a", scope_id, &ip);
-                       (*p)->CurrentlyActive = mDNStrue;
-                       return(0);
+                       (*p)->Exists = mDNStrue;
+                       return(*p);
                        }
 
        debugf("AddInterfaceToList: Making   new   interface %u with address %#a", scope_id, &ip);
        NetworkInterfaceInfoOSX *i = (NetworkInterfaceInfoOSX *)mallocL("NetworkInterfaceInfoOSX", sizeof(*i));
-       if (!i) return(-1);
+       if (!i) return(mDNSNULL);
        i->ifa_name        = (char *)mallocL("NetworkInterfaceInfoOSX name", strlen(ifa->ifa_name) + 1);
-       if (!i->ifa_name) { freeL("NetworkInterfaceInfoOSX", i); return(-1); }
+       if (!i->ifa_name) { freeL("NetworkInterfaceInfoOSX", i); return(mDNSNULL); }
        strcpy(i->ifa_name, ifa->ifa_name);
 
+       bzero(&i->ifinfo.uDNS_info, sizeof(uDNS_NetworkInterfaceInfo));
        i->ifinfo.InterfaceID = mDNSNULL;
        i->ifinfo.ip          = ip;
-       SetupAddr(&i->ifinfo.mask, ifa->ifa_netmask);
-       strncpy(i->ifinfo.ifname, ifa->ifa_name, sizeof(i->ifinfo.ifname));
-       i->ifinfo.ifname[sizeof(i->ifinfo.ifname)-1] = 0;
        i->ifinfo.Advertise   = m->AdvertiseLocalAddresses;
-       i->ifinfo.TxAndRx     = mDNSfalse;              // For now; will be set up later at the end of UpdateInterfaceList
-
+       i->ifinfo.McastTxRx   = mDNSfalse; // For now; will be set up later at the end of UpdateInterfaceList
+       
        i->next            = mDNSNULL;
-       i->m               = m;
+       i->Exists          = mDNStrue;
        i->scope_id        = scope_id;
-       i->CurrentlyActive = mDNStrue;
        i->sa_family       = ifa->ifa_addr->sa_family;
-       #if mDNS_AllowPort53
-       i->skt53 = -1;
-       i->cfs53 = NULL;
-       #endif
-       i->sktv4 = -1;
-       i->cfsv4 = NULL;
-       i->sktv6 = -1;
-       i->cfsv6 = NULL;
-       
-       if (!i->ifa_name) return(-1);
+       i->Multicast       = (ifa->ifa_flags & IFF_MULTICAST) && !(ifa->ifa_flags & IFF_POINTOPOINT);
+
+       i->ss.m     = m;
+       i->ss.info  = i;
+       i->ss.sktv4 = i->ss.sktv6 = -1;
+       i->ss.cfsv4 = i->ss.cfsv6 = NULL;
+       i->ss.rlsv4 = i->ss.rlsv6 = NULL;
+
        *p = i;
-       return(0);
+       return(i);
        }
 
 mDNSlocal NetworkInterfaceInfoOSX *FindRoutableIPv4(mDNS *const m, mDNSu32 scope_id)
        {
        NetworkInterfaceInfoOSX *i;
        for (i = m->p->InterfaceList; i; i = i->next)
-               if (i->CurrentlyActive && i->scope_id == scope_id && i->ifinfo.ip.type == mDNSAddrType_IPv4)
+               if (i->Exists && i->scope_id == scope_id && i->ifinfo.ip.type == mDNSAddrType_IPv4)
                        if (!(i->ifinfo.ip.ip.v4.b[0] == 169 && i->ifinfo.ip.ip.v4.b[1] == 254))
                                return(i);
        return(mDNSNULL);
@@ -1049,6 +1302,7 @@ mDNSlocal mStatus UpdateInterfaceList(mDNS *const m)
                debugf("Updating m->hostlabel to %#s", hostlabel.c);
                m->p->userhostlabel = m->hostlabel = hostlabel;
                mDNS_GenerateFQDN(m);
+               if (mDNS_DNSRegistered(m)) mDNS_GenerateGlobalFQDN(m);
                }
 
        while (ifa)
@@ -1066,6 +1320,9 @@ mDNSlocal mStatus UpdateInterfaceList(mDNS *const m)
                if (!(ifa->ifa_flags & IFF_UP))
                        debugf("UpdateInterfaceList: %4s(%d) Flags %04X Family %2d Interface not IFF_UP",
                                ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
+               if (!(ifa->ifa_flags & IFF_MULTICAST))
+                       debugf("UpdateInterfaceList: %4s(%d) Flags %04X Family %2d Interface not IFF_MULTICAST",
+                               ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
                if (ifa->ifa_flags & IFF_POINTOPOINT)
                        debugf("UpdateInterfaceList: %4s(%d) Flags %04X Family %2d Interface IFF_POINTOPOINT",
                                ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
@@ -1073,43 +1330,42 @@ mDNSlocal mStatus UpdateInterfaceList(mDNS *const m)
                        debugf("UpdateInterfaceList: %4s(%d) Flags %04X Family %2d Interface IFF_LOOPBACK",
                                ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
 #endif
-               if ((ifa->ifa_addr->sa_family == AF_INET || ifa->ifa_addr->sa_family == AF_INET6) &&
-                       (ifa->ifa_flags & IFF_MULTICAST) &&
-                   (ifa->ifa_flags & IFF_UP) && !(ifa->ifa_flags & IFF_POINTOPOINT))
-                       {
-                       int     ifru_flags6 = 0;
-                       if (ifa->ifa_addr->sa_family == AF_INET6 && InfoSocket >= 0)
-                               {
-                               struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
-                               struct in6_ifreq ifr6;
-                               bzero((char *)&ifr6, sizeof(ifr6));
-                               strncpy(ifr6.ifr_name, ifa->ifa_name, sizeof(ifr6.ifr_name));
-                               ifr6.ifr_addr = *sin6;
-                               if (ioctl(InfoSocket, SIOCGIFAFLAG_IN6, &ifr6) != -1)
-                                       ifru_flags6 = ifr6.ifr_ifru.ifru_flags6;
-                               verbosedebugf("%s %.16a %04X %04X", ifa->ifa_name, &sin6->sin6_addr, ifa->ifa_flags, ifru_flags6);
-                               }
-                       if (!(ifru_flags6 & (IN6_IFF_NOTREADY | IN6_IFF_DETACHED | IN6_IFF_DEPRECATED | IN6_IFF_TEMPORARY)))
+               if (ifa->ifa_flags & IFF_UP)
+                       if (ifa->ifa_addr->sa_family == AF_INET || ifa->ifa_addr->sa_family == AF_INET6)
                                {
-                               if (ifa->ifa_flags & IFF_LOOPBACK)
-                                       theLoopback = ifa;
-                               else
+                               int ifru_flags6 = 0;
+                               if (ifa->ifa_addr->sa_family == AF_INET6 && InfoSocket >= 0)
+                                       {
+                                       struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
+                                       struct in6_ifreq ifr6;
+                                       bzero((char *)&ifr6, sizeof(ifr6));
+                                       strncpy(ifr6.ifr_name, ifa->ifa_name, sizeof(ifr6.ifr_name));
+                                       ifr6.ifr_addr = *sin6;
+                                       if (ioctl(InfoSocket, SIOCGIFAFLAG_IN6, &ifr6) != -1)
+                                               ifru_flags6 = ifr6.ifr_ifru.ifru_flags6;
+                                       verbosedebugf("%s %.16a %04X %04X", ifa->ifa_name, &sin6->sin6_addr, ifa->ifa_flags, ifru_flags6);
+                                       }
+                               if (!(ifru_flags6 & (IN6_IFF_NOTREADY | IN6_IFF_DETACHED | IN6_IFF_DEPRECATED | IN6_IFF_TEMPORARY)))
                                        {
-                                       AddInterfaceToList(m, ifa);
-                                       if (ifa->ifa_addr->sa_family == AF_INET)
-                                               foundav4 = mDNStrue;
+                                       if (ifa->ifa_flags & IFF_LOOPBACK)
+                                               theLoopback = ifa;
+                                       else
+                                               {
+                                               AddInterfaceToList(m, ifa);
+                                               if (ifa->ifa_addr->sa_family == AF_INET)
+                                                       foundav4 = mDNStrue;
+                                               }
                                        }
                                }
-                       }
                ifa = ifa->ifa_next;
                }
 
-//     Temporary workaround: Multicast loopback on IPv6 interfaces appears not to work.
-//     In the interim, we skip loopback interface only if we found at least one v4 interface to use
+    //  Temporary workaround: Multicast loopback on IPv6 interfaces appears not to work.
+    //  In the interim, we skip loopback interface only if we found at least one v4 interface to use
        if (!foundav4 && theLoopback)
                AddInterfaceToList(m, theLoopback);
 
-       // Now the list is complete, set the TxAndRx setting for each interface.
+       // Now the list is complete, set the McastTxRx setting for each interface.
        // We always send and receive using IPv4.
        // To reduce traffic, we send and receive using IPv6 only on interfaces that have no routable IPv4 address.
        // Having a routable IPv4 address assigned is a reasonable indicator of being on a large configured network,
@@ -1119,13 +1375,13 @@ mDNSlocal mStatus UpdateInterfaceList(mDNS *const m)
        // so we are willing to make that sacrifice.
        NetworkInterfaceInfoOSX *i;
        for (i = m->p->InterfaceList; i; i = i->next)
-               if (i->CurrentlyActive)
+               if (i->Exists)
                        {
-                       mDNSBool txrx = ((i->ifinfo.ip.type == mDNSAddrType_IPv4) || !FindRoutableIPv4(m, i->scope_id));
-                       if (i->ifinfo.TxAndRx != txrx)
+                       mDNSBool txrx = i->Multicast && ((i->ifinfo.ip.type == mDNSAddrType_IPv4) || !FindRoutableIPv4(m, i->scope_id));
+                       if (i->ifinfo.McastTxRx != txrx)
                                {
-                               i->ifinfo.TxAndRx = txrx;
-                               i->CurrentlyActive = 2; // State change; need to deregister and reregister this interface
+                               i->ifinfo.McastTxRx = txrx;
+                               i->Exists = 2; // State change; need to deregister and reregister this interface
                                }
                        }
 
@@ -1137,8 +1393,7 @@ mDNSlocal NetworkInterfaceInfoOSX *SearchForInterfaceByName(mDNS *const m, char
        {
        NetworkInterfaceInfoOSX *i;
        for (i = m->p->InterfaceList; i; i = i->next)
-               if (!strcmp(i->ifa_name, ifname) &&
-                       i->CurrentlyActive &&
+               if (i->Exists && !strcmp(i->ifa_name, ifname) &&
                        ((AAAA_OVER_V4                                              ) ||
                         (type == AF_INET  && i->ifinfo.ip.type == mDNSAddrType_IPv4) ||
                         (type == AF_INET6 && i->ifinfo.ip.type == mDNSAddrType_IPv6) )) return(i);
@@ -1149,46 +1404,45 @@ mDNSlocal void SetupActiveInterfaces(mDNS *const m)
        {
        NetworkInterfaceInfoOSX *i;
        for (i = m->p->InterfaceList; i; i = i->next)
-               if (i->CurrentlyActive)
+               if (i->Exists)
                        {
-                       mStatus err = 0;
                        NetworkInterfaceInfo *n = &i->ifinfo;
-                       NetworkInterfaceInfoOSX *alias = SearchForInterfaceByName(m, i->ifa_name, i->sa_family);
-                       if (!alias) alias = i;
-                       
-                       if (n->InterfaceID && n->InterfaceID != (mDNSInterfaceID)alias)
+                       NetworkInterfaceInfoOSX *primary = SearchForInterfaceByName(m, i->ifa_name, i->sa_family);
+                       if (!primary) LogMsg("SetupActiveInterfaces ERROR! SearchForInterfaceByName didn't find %s", i->ifa_name);
+       
+                       if (n->InterfaceID && n->InterfaceID != (mDNSInterfaceID)primary)       // Sanity check
                                {
-                               LogMsg("SetupActiveInterfaces ERROR! n->InterfaceID %p != alias %p", n->InterfaceID, alias);
+                               LogMsg("SetupActiveInterfaces ERROR! n->InterfaceID %p != primary %p", n->InterfaceID, primary);
                                n->InterfaceID = mDNSNULL;
                                }
-               
+       
                        if (!n->InterfaceID)
                                {
-                               n->InterfaceID = (mDNSInterfaceID)alias;
+                               // NOTE: If n->InterfaceID is set, that means we've called mDNS_RegisterInterface() for this interface,
+                               // so we need to make sure we call mDNS_DeregisterInterface() before disposing it.
+                               // If n->InterfaceID is NOT set, then we haven't registered it and we should not try to deregister it
+                               n->InterfaceID = (mDNSInterfaceID)primary;
                                mDNS_RegisterInterface(m, n);
-                               debugf("SetupActiveInterfaces: Registered  %s(%lu) InterfaceID %p %#a%s",
-                                       i->ifa_name, i->scope_id, alias, &n->ip, n->InterfaceActive ? " (Primary)" : "");
+                               LogOperation("SetupActiveInterfaces: Registered  %s(%lu) InterfaceID %p %#a%s",
+                                       i->ifa_name, i->scope_id, primary, &n->ip, n->InterfaceActive ? " (Primary)" : "");
                                }
-               
-                       if (!n->TxAndRx)
-                               debugf("SetupActiveInterfaces: No TX/Rx on %s(%lu) InterfaceID %p %#a", i->ifa_name, i->scope_id, alias, &n->ip);
+       
+                       if (!n->McastTxRx)
+                               debugf("SetupActiveInterfaces: No Tx/Rx on %s(%lu) InterfaceID %p %#a", i->ifa_name, i->scope_id, primary, &n->ip);
                        else
                                {
-                               if (i->sa_family == AF_INET && alias->sktv4 == -1)
+                               if (i->sa_family == AF_INET && primary->ss.sktv4 == -1)
                                        {
-                                       #if mDNS_AllowPort53
-                                       err = SetupSocket(i, UnicastDNSPort, &alias->skt53, &alias->cfs53);
-                                       #endif
-                                       if (!err) err = SetupSocket(i, MulticastDNSPort, &alias->sktv4, &alias->cfsv4);
-                                       if (err == 0) debugf("SetupActiveInterfaces: v4 socket%2d %s(%lu) InterfaceID %p %#a", alias->sktv4, i->ifa_name, i->scope_id, n->InterfaceID, &n->ip);
-                                       else LogMsg("SetupActiveInterfaces: v4 socket%2d %s(%lu) InterfaceID %p %#a FAILED",   alias->sktv4, i->ifa_name, i->scope_id, n->InterfaceID, &n->ip);
+                                       mStatus err = SetupSocket(&primary->ss, MulticastDNSPort, &i->ifinfo.ip, AF_INET);
+                                       if (err == 0) debugf("SetupActiveInterfaces: v4 socket%2d %s(%lu) InterfaceID %p %#a", primary->ss.sktv4, i->ifa_name, i->scope_id, n->InterfaceID, &n->ip);
+                                       else LogMsg("SetupActiveInterfaces: v4 socket%2d %s(%lu) InterfaceID %p %#a FAILED",   primary->ss.sktv4, i->ifa_name, i->scope_id, n->InterfaceID, &n->ip);
                                        }
                        
-                               if (i->sa_family == AF_INET6 && alias->sktv6 == -1)
+                               if (i->sa_family == AF_INET6 && primary->ss.sktv6 == -1)
                                        {
-                                       err = SetupSocket(i, MulticastDNSPort, &alias->sktv6, &alias->cfsv6);
-                                       if (err == 0) debugf("SetupActiveInterfaces: v6 socket%2d %s(%lu) InterfaceID %p %#a", alias->sktv6, i->ifa_name, i->scope_id, n->InterfaceID, &n->ip);
-                                       else LogMsg("SetupActiveInterfaces: v6 socket%2d %s(%lu) InterfaceID %p %#a FAILED",   alias->sktv6, i->ifa_name, i->scope_id, n->InterfaceID, &n->ip);
+                                       mStatus err = SetupSocket(&primary->ss, MulticastDNSPort, &i->ifinfo.ip, AF_INET6);
+                                       if (err == 0) debugf("SetupActiveInterfaces: v6 socket%2d %s(%lu) InterfaceID %p %#a", primary->ss.sktv6, i->ifa_name, i->scope_id, n->InterfaceID, &n->ip);
+                                       else LogMsg("SetupActiveInterfaces: v6 socket%2d %s(%lu) InterfaceID %p %#a FAILED",   primary->ss.sktv6, i->ifa_name, i->scope_id, n->InterfaceID, &n->ip);
                                        }
                                }
                        }
@@ -1198,24 +1452,26 @@ mDNSlocal void MarkAllInterfacesInactive(mDNS *const m)
        {
        NetworkInterfaceInfoOSX *i;
        for (i = m->p->InterfaceList; i; i = i->next)
-               i->CurrentlyActive = mDNSfalse;
+               i->Exists = mDNSfalse;
        }
 
-mDNSlocal mDNSu32 NumCacheRecordsForInterfaceID(mDNS *const m, mDNSInterfaceID id)
+mDNSlocal void CloseSocketSet(CFSocketSet *ss)
        {
-       mDNSu32 slot, used = 0;
-       CacheRecord *rr;
-       for (slot = 0; slot < CACHE_HASH_SLOTS; slot++)
-               for (rr = m->rrcache_hash[slot]; rr; rr=rr->next)
-                       if (rr->resrec.InterfaceID == id) used++;
-       return(used);
+       // Note: MUST NOT close the underlying native BSD sockets.
+       // CFSocketInvalidate() will do that for us, in its own good time, which may not necessarily be immediately,
+       // because it first has to unhook the sockets from its select() call, before it can safely close them.
+       if (ss->cfsv4) { CFRunLoopRemoveSource(CFRunLoopGetCurrent(), ss->rlsv4, kCFRunLoopDefaultMode); CFRelease(ss->rlsv4); CFSocketInvalidate(ss->cfsv4); CFRelease(ss->cfsv4); }
+       if (ss->cfsv6) { CFRunLoopRemoveSource(CFRunLoopGetCurrent(), ss->rlsv6, kCFRunLoopDefaultMode); CFRelease(ss->rlsv6); CFSocketInvalidate(ss->cfsv6); CFRelease(ss->cfsv6); }
+       ss->sktv4 = ss->sktv6 = -1;
+       ss->cfsv4 = ss->cfsv6 = NULL;
+       ss->rlsv4 = ss->rlsv6 = NULL;
        }
 
 mDNSlocal void ClearInactiveInterfaces(mDNS *const m)
        {
        // First pass:
        // If an interface is going away, then deregister this from the mDNSCore.
-       // We also have to deregister it if the alias interface that it's using for its InterfaceID is going away.
+       // We also have to deregister 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: When the last representative of an interface goes away
@@ -1224,15 +1480,18 @@ mDNSlocal void ClearInactiveInterfaces(mDNS *const m)
        for (i = m->p->InterfaceList; i; i = i->next)
                {
                // 1. If this interface is no longer active, or its InterfaceID is changing, deregister it
-               NetworkInterfaceInfoOSX *alias = (NetworkInterfaceInfoOSX *)(i->ifinfo.InterfaceID);
-               NetworkInterfaceInfoOSX *newalias = SearchForInterfaceByName(m, i->ifa_name, i->sa_family);
-               if (!newalias) newalias = i;
-               if (i->ifinfo.InterfaceID && (!i->CurrentlyActive || (alias && !alias->CurrentlyActive) || i->CurrentlyActive == 2 || newalias != alias))
-                       {
-                       debugf("ClearInactiveInterfaces: Deregistering %#a", &i->ifinfo.ip);
-                       mDNS_DeregisterInterface(m, &i->ifinfo);
-                       i->ifinfo.InterfaceID = mDNSNULL;
-                       }
+               NetworkInterfaceInfoOSX *primary = SearchForInterfaceByName(m, i->ifa_name, i->sa_family);
+               if (i->ifinfo.InterfaceID)
+                       if (i->Exists == 0 || i->Exists == 2 || i->ifinfo.InterfaceID != (mDNSInterfaceID)primary)
+                               {
+                               LogOperation("ClearInactiveInterfaces: Deregistering %s(%lu) InterfaceID %p %#a%s",
+                                       i->ifa_name, i->scope_id, i->ifinfo.InterfaceID, &i->ifinfo.ip, i->ifinfo.InterfaceActive ? " (Primary)" : "");
+                               mDNS_DeregisterInterface(m, &i->ifinfo);
+                               i->ifinfo.InterfaceID = mDNSNULL;
+                               // NOTE: If n->InterfaceID is set, that means we've called mDNS_RegisterInterface() for this interface,
+                               // so we need to make sure we call mDNS_DeregisterInterface() before disposing it.
+                               // If n->InterfaceID is NOT set, then it's not registered and we should not call mDNS_DeregisterInterface() on it.
+                               }
                }
 
        // Second pass:
@@ -1243,21 +1502,9 @@ mDNSlocal void ClearInactiveInterfaces(mDNS *const m)
                i = *p;
                // 2. Close all our CFSockets. We'll recreate them later as necessary.
                // (We may have previously had both v4 and v6, and we may not need both any more.)
-               // Note: MUST NOT close the underlying native BSD sockets.
-               // CFSocketInvalidate() will do that for us, in its own good time, which may not necessarily be immediately,
-               // because it first has to unhook the sockets from its select() call, before it can safely close them.
-               #if mDNS_AllowPort53
-               if (i->cfs53) { CFSocketInvalidate(i->cfs53); CFRelease(i->cfs53); }
-               i->skt53 = -1;
-               i->cfs53 = NULL;
-               #endif
-               if (i->cfsv4) { CFSocketInvalidate(i->cfsv4); CFRelease(i->cfsv4); }
-               if (i->cfsv6) { CFSocketInvalidate(i->cfsv6); CFRelease(i->cfsv6); }
-               i->sktv4 = i->sktv6 = -1;
-               i->cfsv4 = i->cfsv6 = NULL;
-
+               CloseSocketSet(&i->ss);
                // 3. If no longer active, delete interface from list and free memory
-               if (!i->CurrentlyActive && NumCacheRecordsForInterfaceID(m, (mDNSInterfaceID)i) == 0)
+               if (!i->Exists && NumCacheRecordsForInterfaceID(m, (mDNSInterfaceID)i) == 0)
                        {
                        debugf("ClearInactiveInterfaces: Deleting      %#a", &i->ifinfo.ip);
                        *p = i->next;
@@ -1269,10 +1516,273 @@ mDNSlocal void ClearInactiveInterfaces(mDNS *const m)
                }
        }
 
+
+mDNSlocal mStatus RegisterNameServers(mDNS *const m, CFDictionaryRef dict)
+       {
+       int i, count;
+       CFArrayRef values;
+       char            buf[256];
+       mDNSv4Addr      saddr;  
+       CFStringRef s;
+
+
+       mDNS_DeregisterDNSList(m); // deregister orig list
+       values = CFDictionaryGetValue(dict, kSCPropNetDNSServerAddresses);
+       if (!values) return mStatus_NoError;
+
+       count = CFArrayGetCount(values);
+       for (i = 0; i < count; i++)
+               {
+               s = CFArrayGetValueAtIndex(values, i);
+               if (!s) { LogMsg("ERROR: RegisterNameServers - CFArrayGetValueAtIndex"); break; }
+               if (!CFStringGetCString(s, buf, 256, kCFStringEncodingASCII))
+                       {
+                       LogMsg("ERROR: RegisterNameServers - CFStringGetCString");
+                       continue;
+                       }
+               if (!inet_aton(buf, (struct in_addr *)saddr.b))
+                       {
+                       LogMsg("ERROR: RegisterNameServers - invalid address string %s", buf);
+                       continue;
+                       }
+               mDNS_RegisterDNS(m, &saddr);
+               }
+       return mStatus_NoError;
+       }
+
+mDNSlocal void FreeARElemCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
+       {
+       (void)m;  // unused
+       AuthRecordListElem *elem = rr->RecordContext;
+       if (result == mStatus_MemFree) freeL("FreeARElemCallback", elem);
+       }
+
+mDNSlocal void FoundDomain(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)       
+       {
+       SearchListElem *slElem = question->QuestionContext;
+       AuthRecordListElem *arElem, *ptr, *prev;
+    AuthRecord *dereg;    
+       char *name;
+       mStatus err;
+       
+       if (AddRecord)
+               {
+               arElem = mallocL("FoundDomain - arElem", sizeof(AuthRecordListElem));
+               if (!arElem) { LogMsg("ERROR: malloc");  return; }
+               mDNS_SetupResourceRecord(&arElem->ar, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, 7200,  kDNSRecordTypeShared, FreeARElemCallback, arElem);
+               if (question == &slElem->browseQ) name = "_browse._dns-sd._udp.local.";
+               else                              name = "_register._dns-sd._udp.local.";
+               MakeDomainNameFromDNSNameString(&arElem->ar.resrec.name, name);
+               strcpy(arElem->ar.resrec.rdata->u.name.c, answer->rdata->u.name.c);
+               err = mDNS_Register(m, &arElem->ar);
+               if (err)
+                       {
+                       LogMsg("ERROR: FoundDomain - mDNS_Register returned %d", err);
+                       freeL("FoundDomain - arElem", arElem);                            
+                       return;
+                       }
+               arElem->next = slElem->AuthRecs;
+               slElem->AuthRecs = arElem;
+               }
+       else
+               {
+               ptr = slElem->AuthRecs;
+               prev = NULL;
+               while (ptr)
+                       {
+                       if (SameDomainName(&ptr->ar.resrec.name, &answer->name) && SameDomainName(&ptr->ar.resrec.rdata->u.name, &answer->rdata->u.name))
+                               {
+                               debugf("Deregistering PTR %s -> %s", ptr->ar.resrec.name.c, ptr->ar.resrec.rdata->u.name.c);
+                dereg = &ptr->ar;
+                               if (prev) prev->next = ptr->next;
+                               else slElem->AuthRecs = ptr->next;
+                ptr = ptr->next;
+                               err = mDNS_Deregister(m, dereg);                                
+                               if (err) LogMsg("ERROR: FoundDomain - mDNS_Deregister returned %d", err);
+                               }
+                       else
+                               {
+                               prev = ptr;
+                               ptr = ptr->next;
+                               }
+                       }
+               }
+       }
+
+mDNSlocal mStatus RegisterSearchDomains(mDNS *const m, CFDictionaryRef dict)
+       {
+       int i, count;
+       CFArrayRef values;
+       domainname domain;
+       char            buf[MAX_ESCAPED_DOMAIN_NAME];
+       CFStringRef s;
+       SearchListElem *new, *ptr, *prev, *freeSLPtr;
+       AuthRecordListElem *arList;
+       mStatus err;
+       
+       // step 1: mark each elem for removal (-1)
+       for (ptr = SearchList; ptr; ptr = ptr->next) ptr->flag = -1;
+       
+       values = CFDictionaryGetValue(dict, kSCPropNetDNSSearchDomains);
+       if (values)
+               {
+               count = CFArrayGetCount(values);
+               for (i = 0; i < count; i++)
+                       {
+                       s = CFArrayGetValueAtIndex(values, i);
+                       if (!s) { LogMsg("ERROR: RegisterNameServers - CFArrayGetValueAtIndex"); break; }
+                       if (!CFStringGetCString(s, buf, MAX_ESCAPED_DOMAIN_NAME, kCFStringEncodingASCII))
+                               {
+                               LogMsg("ERROR: RegisterNameServers - CFStringGetCString");
+                               continue;
+                               }                                       
+                       if (!MakeDomainNameFromDNSNameString(&domain, buf))
+                               {
+                               LogMsg("ERROR: RegisterNameServers - invalid search domain %s", buf);
+                               continue;
+                               }                               
+                       // if domain is in list, mark as pre-existent (0)
+                       for (ptr = SearchList; ptr; ptr = ptr->next)
+                               if (SameDomainName(&ptr->domain, &domain)) { ptr->flag = 0; break; }
+
+                       // if domain not in list, add to list, mark as add (1)
+                       if (!ptr)
+                               {
+                               new = mallocL("RegisterSearchDomains - SearchListElem", sizeof(SearchListElem));
+                               if (!new) { LogMsg("ERROR: RegisterSearchDomains - malloc"); return mStatus_UnknownErr; }
+                               bzero(new, sizeof(SearchListElem));
+                               strcpy(new->domain.c, domain.c);
+                               new->flag = 1;  // add
+                               new->next = SearchList;
+                               SearchList = new;
+                               }
+                       }
+               }
+       // delete elems marked for removal, do queries for elems marked add
+       prev = NULL;
+       ptr = SearchList;
+       while (ptr)
+               {
+               if (ptr->flag == -1)  // remove
+                       {                               
+                       mDNS_StopQuery(m, &ptr->browseQ);
+                       mDNS_StopQuery(m, &ptr->registerQ);                     
+                       // deregister records generated from answers to the query
+                       arList = ptr->AuthRecs;
+                       ptr->AuthRecs = NULL;
+                       while (arList)
+                               {
+                               AuthRecord *dereg = &arList->ar;
+                               arList = arList->next;
+                               debugf("Deregistering PTR %s -> %s", dereg->resrec.name.c, dereg->resrec.rdata->u.name.c);
+                               err = mDNS_Deregister(m, dereg);
+                               if (err) LogMsg("ERROR: RegisterSearchDomains mDNS_Deregister returned %d", err);
+                               }
+                       
+                       // remove elem from list, delete                                
+                       if (prev) prev->next = ptr->next;
+                       else SearchList = ptr->next;
+                       freeSLPtr = ptr;
+                       ptr = ptr->next;
+                       freeL("RegisterNameServers - freeSLPtr", freeSLPtr);
+                       continue;
+                       }
+               
+               if (ptr->flag == 1)  // add
+                       {
+                       err = mDNS_GetDomains(m, &ptr->browseQ, mDNS_DomainTypeBrowse, &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
+                       if (err) LogMsg("ERROR: RegisterNameServers - mDNS_DomainTypeBrowse, %d", err);
+
+                       err = mDNS_GetDomains(m, &ptr->registerQ, mDNS_DomainTypeRegistration, &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
+                       if (err) LogMsg("ERROR: RegisterNameServers - mDNS_DomainTypeRegistration, %d", err);
+                       ptr->flag = 0;
+                       }
+               
+               if (ptr->flag) { LogMsg("RegisterNameServers - unknown flag %d.  Skipping.", ptr->flag); }
+               
+               prev = ptr;
+               ptr = ptr->next;
+               }               
+       
+       return mStatus_NoError;
+       }
+
+// key must be kSCPropNetDNSServerAddresses or kSCPropNetDNSSearchDomains
+mDNSlocal mStatus RegisterDNSConfig(mDNS *const m, CFDictionaryRef dict, const CFStringRef key)
+       {       
+       if (key == kSCPropNetDNSSearchDomains) return RegisterSearchDomains(m, dict);
+       if (key == kSCPropNetDNSServerAddresses) return RegisterNameServers(m, dict);
+       LogMsg("ERROR: RegisterDNSConfig - bad key"); return mStatus_UnknownErr;
+       }
+
+
+mDNSlocal void DNSConfigChanged(SCDynamicStoreRef session, CFArrayRef changes, void *context)
+       {
+       mDNS *m = context;
+       CFDictionaryRef dict;
+       CFStringRef     key;
+
+       if (DNSConfigInitialized && (!changes || CFArrayGetCount(changes) == 0)) return;
+
+       //!!!KRS fixme - we need a list of registerd servers. this wholesale
+    // dereg doesn't work if there's an error and we bail out before registering the new list
+
+       key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetDNS);
+       if (!key) {  LogMsg("ERROR: DNSConfigChanged - SCDynamicStoreKeyCreateNetworkGlobalEntity");  return;  }
+       dict = SCDynamicStoreCopyValue(session, key);
+       CFRelease(key);
+       if (dict)
+               {
+               RegisterDNSConfig(m, dict, kSCPropNetDNSServerAddresses);
+               RegisterDNSConfig(m, dict, kSCPropNetDNSSearchDomains);         
+               CFRelease(dict);
+               }               
+       if (mDNS_DNSRegistered(m)) mDNS_GenerateGlobalFQDN(m);
+       // no-op if label & domain are unchanged
+       }
+
+mDNSlocal mStatus WatchForDNSChanges(mDNS *const m)    
+    {
+    CFStringRef                            key;
+    CFMutableArrayRef          keyList;
+    CFRunLoopSourceRef         rls;
+    SCDynamicStoreRef          session;
+       SCDynamicStoreContext context = { 0, m, NULL, NULL, NULL };
+       
+    session = SCDynamicStoreCreate(NULL, CFSTR("trackDNS"), DNSConfigChanged, &context);    
+    if (!session) {  LogMsg("ERROR: WatchForDNSChanges - SCDynamicStoreCreate");  return mStatus_UnknownErr;  }
+
+    keyList = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+    if (!keyList) {  LogMsg("ERROR: WatchForDNSChanges - CFArrayCreateMutable");  return mStatus_UnknownErr;  }
+    
+    // create a pattern that matches the global DNS dictionary key
+    key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetDNS);
+    if (!key) {  LogMsg("ERROR: WatchForDNSChanges - SCDynamicStoreKeyCreateNetworkGlobalEntity");  return mStatus_UnknownErr;  }
+    
+    CFArrayAppendValue(keyList, key);
+    CFRelease(key);
+    
+    // set the keys for our DynamicStore session
+    SCDynamicStoreSetNotificationKeys(session, keyList, NULL);
+    CFRelease(keyList);
+    
+    // create a CFRunLoopSource for our DynamicStore session
+    rls = SCDynamicStoreCreateRunLoopSource(NULL, session, 0);
+    if (!rls) {  LogMsg("ERROR: WatchForDNSChanges - SCDynamicStoreCreateRunLoopSource");  return mStatus_UnknownErr;  }
+    
+    // add the run loop source to our current run loop 
+    CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
+    CFRelease(rls);
+    
+       // get initial configuration
+    DNSConfigChanged(session, NULL, m);
+    return mStatus_NoError;
+    }
+
 mDNSlocal void NetworkChanged(SCDynamicStoreRef store, CFArrayRef changedKeys, void *context)
        {
-       (void)store;            // Parameter not used
-       (void)changedKeys;      // Parameter not used
+       (void)store;        // Parameter not used
+       (void)changedKeys;  // Parameter not used
        debugf("***   Network Configuration Change   ***");
 
        mDNS *const m = (mDNS *const)context;
@@ -1339,7 +1849,7 @@ exit:
 mDNSlocal void PowerChanged(void *refcon, io_service_t service, natural_t messageType, void *messageArgument)
        {
        mDNS *const m = (mDNS *const)refcon;
-       (void)service;          // Parameter not used
+       (void)service;    // Parameter not used
        switch(messageType)
                {
                case kIOMessageCanSystemPowerOff:     debugf("PowerChanged kIOMessageCanSystemPowerOff (no action)");                      break; // E0000240
@@ -1367,10 +1877,130 @@ mDNSlocal mStatus WatchForPowerChanges(mDNS *const m)
        return(-1);
        }
 
+mDNSexport mDNSBool haveSecInfo = mDNSfalse;  // this must go away once we have full keychain integration
+mDNSlocal void GetAuthInfoFromKeychainItem(mDNS *m, SecKeychainItemRef item)
+       {
+       OSStatus err;
+       mDNSu32 infoTag = kSecAccountItemAttr;
+       mDNSu32 infoFmt = 0; // string
+    SecKeychainAttributeInfo info;             
+       SecKeychainAttributeList *authAttrList = NULL; 
+       void *data;
+       mDNSu32 dataLen;
+       
+       mStatus regErr;         
+       char accountName[MAX_ESCAPED_DOMAIN_NAME];
+       domainname zone;
+       AuthRecord *rrReg, *rrBrowse;
+
+       info.count = 1;
+       info.tag = &infoTag;
+       info.format = &infoFmt;
+               
+       err = SecKeychainItemCopyAttributesAndData(item, &info, NULL, &authAttrList, &dataLen, &data);
+       if (err) { LogMsg("SecKeychainItemCopyAttributesAndData returned error %d", err); return; }
+       
+       // copy account name
+       if (!authAttrList->count || authAttrList->attr->tag != kSecAccountItemAttr)
+           { LogMsg("Received bad authAttrList"); return; }
+       
+       if (authAttrList->attr->length + strlen(LH_SUFFIX) > MAX_ESCAPED_DOMAIN_NAME)
+               { LogMsg("Account name too long (%d bytes)", authAttrList->attr->length); return; }
+       memcpy(accountName, authAttrList->attr->data, authAttrList->attr->length);
+       accountName[authAttrList->attr->length] = '\0';
+       
+       zone.c[0] = '\0';
+       if (!AppendLiteralLabelString(&zone, accountName) ||
+               !AppendDNSNameString(&zone, LH_SUFFIX))
+               { LogMsg("InitAuthInfo - bad account name"); return; }
+       
+       mDNS_UpdateDomainRequiresAuthentication(m, &zone, &zone, data, dataLen, mDNStrue);
+       if(m->uDNS_info.NameRegDomain) { debugf("Overwriting config file options with KeyChain values"); }
+       
+       if (!ConvertDomainNameToCString(&zone, m->uDNS_info.NameRegDomain) ||
+               !ConvertDomainNameToCString(&zone, m->uDNS_info.ServiceRegDomain))
+               { LogMsg("Couldn't set keychain username in uDNS global info"); }
+       
+       mDNS_GenerateGlobalFQDN(m);
+       // normally we'd query the zone for _register/_browse domains, but to reduce server load we manually generate the records
+
+       haveSecInfo = mDNStrue;
+       //!!!KRS need to do better bookkeeping once we support multiple users
+       rrReg = mallocL("AuthRecord", sizeof(AuthRecord));
+       rrBrowse = mallocL("AuthRecord", sizeof(AuthRecord));
+       if (!rrReg || !rrBrowse) { LogMsg("ERROR: Malloc"); return; }
+       
+       // set up _browse
+       mDNS_SetupResourceRecord(rrBrowse, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, 7200,  kDNSRecordTypeShared, mDNSNULL, mDNSNULL);
+       MakeDomainNameFromDNSNameString(&rrBrowse->resrec.name, "_browse._dns-sd._udp.local.");
+       strcpy(rrBrowse->resrec.rdata->u.name.c, zone.c);
+       
+       // set up _register
+       mDNS_SetupResourceRecord(rrReg, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, 7200,  kDNSRecordTypeShared, mDNSNULL, mDNSNULL);
+       MakeDomainNameFromDNSNameString(&rrReg->resrec.name, "_register._dns-sd._udp.local.");
+       strcpy(rrReg->resrec.rdata->u.name.c, zone.c);
+       
+       regErr = mDNS_Register(m, rrReg);
+       if (regErr) LogMsg("Registration of local-only reg domain %s failed", zone.c);
+       
+       regErr = mDNS_Register(m, rrBrowse);
+       if (regErr) LogMsg("Registration of local-only browse domain %s failed", zone.c);
+       SecKeychainItemFreeContent(authAttrList, data);
+       }
+
+mDNSlocal void InitAuthInfo(mDNS *m);
+
+mDNSlocal OSStatus KeychainCallback(SecKeychainEvent event, SecKeychainCallbackInfo *info, void *context)
+       {
+       (void)event;
+       (void)info;
+       // unused
+       
+       debugf("SecKeychainAddCallback received event %d", event);
+       InitAuthInfo((mDNS *)context);  // keychain events happen rarely - just rebuild the list
+       return 0;
+       }
+
+mDNSexport void InitAuthInfo(mDNS *m)
+       {
+       OSStatus err;
+       
+       SecKeychainSearchRef searchRef = NULL;
+       SecKeychainRef sysKeychain = NULL;
+       SecKeychainAttribute searchAttrs[] = { { kSecDescriptionItemAttr, strlen(LH_KEYCHAIN_DESC), LH_KEYCHAIN_DESC },
+                                                                         { kSecServiceItemAttr, strlen(LH_KEYCHAIN_SERVICE), LH_KEYCHAIN_SERVICE } };  
+       SecKeychainAttributeList searchList = { sizeof(searchAttrs) / sizeof(*searchAttrs), searchAttrs };
+       SecKeychainItemRef item;
+
+       // clear any previous entries
+       mDNS_ClearAuthenticationList(m);
+
+       err = SecKeychainOpen(SYS_KEYCHAIN_PATH, &sysKeychain);
+       if (err) { LogMsg("ERROR: InitAuthInfo - couldn't open system keychain - %d", err); goto release_refs; }
+       err = SecKeychainSetDomainDefault(kSecPreferencesDomainSystem, sysKeychain);
+       if (err) { LogMsg("ERROR: InitAuthInfo - couldn't set domain default for system keychain - %d", err); goto release_refs; }
+       
+       err = SecKeychainSearchCreateFromAttributes(sysKeychain, kSecGenericPasswordItemClass, &searchList, &searchRef);
+       if (err) { LogMsg("ERROR: InitAuthInfo - SecKeychainSearchCreateFromAttributes %d", err); goto release_refs; }
+
+       while (!SecKeychainSearchCopyNext(searchRef, &item))
+               {
+               GetAuthInfoFromKeychainItem(m, item);
+               CFRelease(item);
+               }
+       err = SecKeychainAddCallback(KeychainCallback, kSecAddEventMask | kSecDeleteEventMask | kSecUpdateEventMask | kSecPasswordChangedEventMask, m); 
+       if (err && err != errSecDuplicateCallback) { LogMsg("SecKeychainAddCallback returned error %d", err); }                                                         
+
+       release_refs:
+       
+       if (searchRef) CFRelease(searchRef);
+       if (sysKeychain) CFRelease(sysKeychain);
+       }
+
 CF_EXPORT CFDictionaryRef _CFCopySystemVersionDictionary(void);
 CF_EXPORT const CFStringRef _kCFSystemVersionProductNameKey;
 CF_EXPORT const CFStringRef _kCFSystemVersionProductVersionKey;
-CF_EXPORT const CFStringRef _kCFSystemVersionBuildVersionKey;          
+CF_EXPORT const CFStringRef _kCFSystemVersionBuildVersionKey;
 
 mDNSexport mDNSBool mDNSMacOSXSystemBuildNumber(char *HINFO_SWstring)
        {
@@ -1392,12 +2022,192 @@ mDNSexport mDNSBool mDNSMacOSXSystemBuildNumber(char *HINFO_SWstring)
        return(major);
        }
 
-mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m)
+// Test to see if we're the first client running on UDP port 5353, by trying to bind to 5353 without using SO_REUSEPORT.
+// If we fail, someone else got here first. That's not a big problem; we can share the port for multicast responses --
+// we just need to be aware that we shouldn't expect to successfully receive unicast UDP responses.
+mDNSlocal mDNSBool mDNSPlatformInit_ReceiveUnicast(void)
        {
+       int err;
+       int s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+       struct sockaddr_in s5353;
+       s5353.sin_family      = AF_INET;
+       s5353.sin_port        = MulticastDNSPort.NotAnInteger;
+       s5353.sin_addr.s_addr = 0;
+       err = bind(s, (struct sockaddr *)&s5353, sizeof(s5353));
+       close(s);
+       if (err) debugf("No unicast UDP responses");
+       else     debugf("Unicast UDP responses okay");
+       return(err == 0);
+       }
+
+
+//!!!KRS this should be less order-dependent as we support more configuration options
+mDNSlocal mDNSBool GetConfigOption(char *dst, const char *option, FILE *f)
+       {
+       char buf[1024];
+       int len;
+       
+       if (!fgets(buf, 1024, f)) { LogMsg("Option %s not set", option); return mDNSfalse; }
+       len = strlen(option);
+       if (!strncmp(buf, option, len))
+               {
+               strcpy(dst, buf + len + 1);
+               len = strlen(dst);
+               if ( len && dst[len-1] == '\n') dst[len-1] = '\0';  // chop newline
+               return mDNStrue;
+               }
+       LogMsg("Malformatted config file - %s not set", option);        
+       return mDNSfalse;
+       }
+       
+
+       
+mDNSlocal void ReadRegDomainFromConfig(mDNS *const m)
+       {
+       FILE *f;
+       uDNS_GlobalInfo *u = &m->uDNS_info;;
+       char key[MAX_ESCAPED_DOMAIN_NAME];
+       domainname key_d, name_d, service_d;
+       char secret[1024];
+       int slen;
        mStatus err;
 
-       m->hostlabel.c[0]        = 0;
+    // read registration domain (for dynamic updates) from config file
+    // !!!KRS these must go away once we can learn the reg domain from the network or prefs    
+       if (m->uDNS_info.NameRegDomain[0] || m->uDNS_info.ServiceRegDomain[0])
+               { debugf("Options from config already set via keychain. Ignoring config file."); return; }
+       
+       f = fopen(CONFIG_FILE, "r");
+       if (!f)
+               {
+               if (errno != ENOENT)  LogMsg("ERROR: Config file exists, but cannot be opened.");
+               return;
+               }
+
+       if (!GetConfigOption(u->NameRegDomain, "name-reg", f)) goto end;
+       if (!GetConfigOption(u->ServiceRegDomain, "service-reg", f)) goto end;
+       if (!GetConfigOption(key, "key-name", f)) goto end;
+       if (!GetConfigOption(secret, "secret-64", f)) { LogMsg("ERROR: config file contains key without secret"); goto end; }
+
+       // we don't actually need this in domain-name format - just convert it to error check
+       if (!MakeDomainNameFromDNSNameString(&service_d, u->ServiceRegDomain))
+               { LogMsg("ERROR: config file contains bad service reg domain %s", u->ServiceRegDomain); u->ServiceRegDomain[0] = '\0'; }        
+
+       if (!MakeDomainNameFromDNSNameString(&name_d, u->NameRegDomain))
+               { LogMsg("ERROR: config file contains bad name reg domain %s", u->NameRegDomain); u->NameRegDomain[0] = '\0'; } 
+
+       if (!MakeDomainNameFromDNSNameString(&key_d, key))
+               { LogMsg("ERROR: config file contains bad key %s", key); key[0] = '\0'; }
 
+       if (key[0])
+               {
+               slen = strlen(secret);
+               if (u->ServiceRegDomain[0]) 
+                       {
+                       err = mDNS_UpdateDomainRequiresAuthentication(m, &service_d, &key_d, secret, slen, mDNStrue);
+                       if (err) LogMsg("ERROR: mDNS_UpdateDomainRequiresAuthentication returned %d for domain ", err, u->ServiceRegDomain);
+                       }
+               if (u->NameRegDomain[0])
+                       {
+                       err = mDNS_UpdateDomainRequiresAuthentication(m, &name_d, &key_d, secret, slen, mDNStrue);
+                       if (err) LogMsg("ERROR: mDNS_UpdateDomainRequiresAuthentication returned %d for domain ", err, u->NameRegDomain);
+                       }
+               }
+       
+       end:
+       fclose(f);
+       }
+
+mDNSexport DNameListElem *mDNSPlatformGetSearchDomainList(void)
+       {
+       return mDNS_CopyDNameList(DefBrowseList);
+       }
+
+mDNSexport DNameListElem *mDNSPlatformGetRegDomainList(void)
+       {
+       static DNameListElem tmp;
+       static mDNSBool init = mDNSfalse;
+
+       if (!init)
+               {
+               MakeDomainNameFromDNSNameString(&tmp.name, "local.");
+               tmp.next = NULL;
+               init = mDNStrue;
+               }
+       return mDNS_CopyDNameList(&tmp);
+       }
+
+       
+mDNSlocal void FoundDefBrowseDomain(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
+       {
+       DNameListElem *ptr, *prev, *new;
+       (void)m; // unused;
+       (void)question;  // unused
+
+       if (AddRecord)
+               {
+               new = mallocL("FoundDefBrowseDomain", sizeof(DNameListElem));
+               if (!new) { LogMsg("ERROR: malloc"); return; }
+               strcpy(new->name.c, answer->rdata->u.name.c);
+               new->next = DefBrowseList;
+               DefBrowseList = new;
+               return;
+               }
+       else
+               {
+               ptr = DefBrowseList;
+               prev = NULL;
+               while (ptr)
+                       {
+                       if (SameDomainName(&ptr->name, &answer->rdata->u.name))
+                               {
+                               if (prev) prev->next = ptr->next;
+                               else DefBrowseList = ptr->next;
+                               freeL("FoundDefBrowseDomain", ptr);
+                               return;
+                               }
+                       prev = ptr;
+                       ptr = ptr->next;
+                       }
+               LogMsg("FoundDefBrowseDomain: Got remove event for domain %s not in list", answer->rdata->u.name.c);
+               }    
+       }
+
+// Construction of Default Browse domain list (i.e. when clients pass NULL) is as follows:
+// 1) query for _browse._dns-sd._udp.local on LocalOnly interface
+//    (.local manually generated via explicit callback)
+// 2) for each search domain (from prefs pane), query for _browse._dns-sd._udp.<searchdomain>.
+// 3) for each result from (2), register LocalOnly PTR record_browse._dns-sd._udp.local. -> <result>
+// 4) result above should generate a callback from question in (1).  result added to global list
+// 5) global list delivered to client via GetSearchDomainList()
+// 6) client calls to enumerate domains now go over LocalOnly interface
+//    (!!!KRS may add outgoing interface in addition)
+
+mDNSlocal mStatus InitDNSConfig(mDNS *const m)
+       {
+       mStatus err;
+       AuthRecord local;       
+       DNSConfigInitialized = mDNStrue;
+
+       // start query for domains to be used in default (empty string domain) browses
+       err = mDNS_GetDomains(m, &DefBrowseDomainQ, mDNS_DomainTypeBrowse, NULL, mDNSInterface_LocalOnly, FoundDefBrowseDomain, NULL);
+
+       // provide .local automatically
+       mDNS_SetupResourceRecord(&local, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, 7200,  kDNSRecordTypeShared, mDNSNULL, mDNSNULL);
+       MakeDomainNameFromDNSNameString(&local.resrec.name, "_browse._dns-sd._udp.local.");
+       MakeDomainNameFromDNSNameString(&local.resrec.rdata->u.name, "local.");
+       // other fields ignored
+       FoundDefBrowseDomain(m, &DefBrowseDomainQ, &local.resrec, 1);
+
+    return mStatus_NoError;
+       }
+       
+mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m)
+       {
+       mStatus err;
+
+       m->hostlabel.c[0]        = 0;
+       
        char *HINFO_HWstring = "Macintosh";
        char HINFO_HWstring_buffer[256];
        int    get_model[2] = { CTL_HW, HW_MODEL };
@@ -1406,7 +2216,8 @@ mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m)
                HINFO_HWstring = HINFO_HWstring_buffer;
 
        char HINFO_SWstring[256] = "";
-       if (mDNSMacOSXSystemBuildNumber(HINFO_SWstring) < 7) m->KnownBugs = mDNS_KnownBug_PhantomInterfaces;
+       if (mDNSMacOSXSystemBuildNumber(HINFO_SWstring) < 7) m->KnownBugs |= mDNS_KnownBug_PhantomInterfaces;
+       if (mDNSPlatformInit_ReceiveUnicast())               m->CanReceiveUnicast = mDNStrue;
 
        mDNSu32 hlen = mDNSPlatformStrLen(HINFO_HWstring);
        mDNSu32 slen = mDNSPlatformStrLen(HINFO_SWstring);
@@ -1418,6 +2229,15 @@ mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m)
                mDNSPlatformMemCopy(HINFO_SWstring, &m->HISoftware.c[1], slen);
                }
 
+       m->p->unicastsockets.m     = m;
+       m->p->unicastsockets.info  = NULL;
+       m->p->unicastsockets.sktv4 = m->p->unicastsockets.sktv6 = -1;
+       m->p->unicastsockets.cfsv4 = m->p->unicastsockets.cfsv6 = NULL;
+       m->p->unicastsockets.rlsv4 = m->p->unicastsockets.rlsv6 = NULL;
+       
+       err = SetupSocket(&m->p->unicastsockets, zeroIPPort, &zeroAddr, AF_INET);
+       err = SetupSocket(&m->p->unicastsockets, zeroIPPort, &zeroAddr, AF_INET6);
+
        m->p->InterfaceList      = mDNSNULL;
        m->p->userhostlabel.c[0] = 0;
        UpdateInterfaceList(m);
@@ -1427,12 +2247,24 @@ mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m)
        if (err) return(err);
        
        err = WatchForPowerChanges(m);
-       return(err);
+       if (err) return err;
+       
+       err = WatchForDNSChanges(m);
+
+       InitDNSConfig(m);
+
+       m->uDNS_info.ServiceRegDomain[0] = '\0';
+       m->uDNS_info.NameRegDomain[0] = '\0';
+       InitAuthInfo(m);
+       ReadRegDomainFromConfig(m);     
+       
+       return(err);
        }
 
 mDNSexport mStatus mDNSPlatformInit(mDNS *const m)
        {
        mStatus result = mDNSPlatformInit_setup(m);
+       
        // We don't do asynchronous initialization on OS X, so by the time we get here the setup will already
        // have succeeded or failed -- so if it succeeded, we should just call mDNSCoreInitComplete() immediately
        if (result == mStatus_NoError) mDNSCoreInitComplete(m, mStatus_NoError);
@@ -1464,6 +2296,7 @@ mDNSexport void mDNSPlatformClose(mDNS *const m)
        
        MarkAllInterfacesInactive(m);
        ClearInactiveInterfaces(m);
+       CloseSocketSet(&m->p->unicastsockets);
        }
 
 mDNSexport mDNSs32  mDNSPlatformOneSecond = 1000;
@@ -1502,6 +2335,11 @@ mDNSexport mDNSs32  mDNSPlatformTimeNow(void)
        return((mDNSs32)(mach_absolute_time() / clockdivisor));
        }
 
+mDNSexport mDNSs32 mDNSPlatformUTC(void)
+       {
+       return time(NULL);
+       }
+
 // 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; }
index e0cf87c1560b65a6c9b014c87e5a715f6b406bb8..3a7e266589af5f772c80d14cb95268baec015d5f 100644 (file)
@@ -3,6 +3,8 @@
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
index b6d3a9a8d5b85482229c049654d15963682b3c9a..bd5b11bf7b0818fbd9311320c6057c3992e0d94c 100644 (file)
@@ -3,6 +3,8 @@
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
index 942fb6b1802216ce7d783fb7dbc84257a8ccf931..6ae6004e76dfe581119b72753676fb5cdcb68801 100644 (file)
@@ -3,6 +3,8 @@
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
index eb400b1fd9a0c7fba74fddadaac23a1b3b48ab12..a4596af2a82e22031a3c29e440507eae62ec8158 100644 (file)
@@ -3,6 +3,8 @@
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
diff --git a/mDNSMacOSX/SampleUDSClient.c b/mDNSMacOSX/SampleUDSClient.c
deleted file mode 100755 (executable)
index 7838fc1..0000000
+++ /dev/null
@@ -1,411 +0,0 @@
-/*
- * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- * 
- * @APPLE_LICENSE_HEADER_END@
-
-    Change History (most recent first):
-
-$Log: SampleUDSClient.c,v $
-Revision 1.7  2003/08/18 18:50:15  cheshire
-Can now give "-lo" as first parameter, to test "local only" mode
-
-Revision 1.6  2003/08/12 19:56:25  cheshire
-Update to APSL 2.0
-
- */
-
-#include <dns_sd.h>
-#include <unistd.h>
-#include <DNSServiceDiscovery/DNSServiceDiscovery.h> // include Mach API to ensure no conflicts exist
-#include <CoreFoundation/CoreFoundation.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#define BIND_8_COMPAT 1
-#include <nameser.h>
-// T_SRV is not defined in older versions of nameser.h
-#ifndef T_SRV
-#define T_SRV 33
-#endif
-
-// constants
-#define MAX_DOMAIN_LABEL 63
-#define MAX_DOMAIN_NAME 255
-#define MAX_CSTRING 2044
-
-
-// data structure defs
-typedef union { unsigned char b[2]; unsigned short NotAnInteger; } Opaque16;
-
-typedef struct { u_char c[ 64]; } domainlabel;
-typedef struct { u_char c[256]; } domainname;
-
-
-typedef struct 
-    { 
-    uint16_t priority; 
-    uint16_t weight; 
-    uint16_t port; 
-    domainname target;
-    } srv_rdata;
-
-
-// private function prototypes
-static void sighdlr(int signo);
-static char *ConvertDomainNameToCString_withescape(const domainname *const name, char *ptr, char esc);
-static char *ConvertDomainLabelToCString_withescape(const domainlabel *const label, char *ptr, char esc);
-//static void MyCallbackWrapper(CFSocketRef sr, CFSocketCallBackType t, CFDataRef dr, const void *i, void *context);
-static void print_rdata(int type, int len, const u_char *rdata);
-static void query_cb(const DNSServiceRef DNSServiceRef, const DNSServiceFlags flags, const u_int32_t interfaceIndex, const DNSServiceErrorType errorCode, const char *name, const u_int16_t rrtype, const u_int16_t rrclass, const u_int16_t rdlen, const void *rdata, const u_int32_t ttl, void *context);
-static void resolve_cb(const DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *fullname, const char *hosttarget, uint16_t port, uint16_t txtLen, const char                          *txtRecord, void *context);
-static void my_enum_cb( DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *replyDomain, void *context);
-static void my_regecordcb(DNSServiceRef sdRef, DNSRecordRef RecordRef, DNSServiceFlags flags, DNSServiceErrorType errorCode, void *context);
-static void browse_cb(DNSServiceRef sdr, DNSServiceFlags flags, uint32_t ifi, DNSServiceErrorType err, const char *serviceName, const char *regtype, const char *domain, void *context);
-
-
-// globals
-static DNSServiceRef sdr = NULL;
-static uint32_t InterfaceIndex = 0;
-
-static void regservice_cb(DNSServiceRef sdRef, DNSServiceFlags flags, DNSServiceErrorType errorCode, const char *name, const char *regtype, const char *domain, void *context)
-       {
-       #pragma unused (sdRef, flags, errorCode, context)
-       printf("regservice_cb %s %s %s\n", name, regtype, domain);
-       }
-
-int main (int argc, char * argv[])  {
-    int err, t, i;
-    char *name, *type, *domain;
-    DNSServiceFlags flags;
-    DNSRecordRef recordrefs[10];
-    char host[256];
-    int ipaddr = 12345;        // random IP address
-    
-    char full[1024];
-    
-    // First parameter "-lo" means "local only"
-    if (!strcmp(argv[1], "-lo")) { InterfaceIndex = -1; argv++; argc--; }
-    
-    if (signal(SIGINT, sighdlr) == SIG_ERR)  fprintf(stderr, "ERROR - can't catch interupt!\n");
-    if (argc < 2) exit(1);
-
-    if (!strcmp(argv[1], "-regrecord"))
-        {
-        err = DNSServiceCreateConnection(&sdr);
-        if (err)
-            {
-            printf("DNSServiceCreateConnection returned %d\n", err);
-            exit(1);
-            }
-        printf("registering 10 address records...\n");
-        for (i = 0; i < 10; i++)
-            {
-            sprintf(host, "testhost-%d.local.", i);
-            ipaddr++;
-            err = DNSServiceRegisterRecord(sdr, &recordrefs[i], kDNSServiceFlagsUnique, InterfaceIndex, 
-                host, 1, 1, 4, &ipaddr, 60, my_regecordcb, NULL);
-            if (err) 
-                {
-                printf("DNSServiceRegisterRecord returned error %d\n", err);
-                exit(1);
-                }
-            }
-        printf("processing results...\n");
-        for (i = 0; i < 10; i++) DNSServiceProcessResult(sdr);
-        printf("deregistering half of the records\n");
-        for (i = 0; i < 10; i++)
-            {
-            if (i % 2) 
-                {
-                err = DNSServiceRemoveRecord(sdr, recordrefs[i], 0);
-                if (err) 
-                    {
-                    printf("DNSServiceRemoveRecord returned error %d\n" ,err);
-                    exit(1);
-                    }
-                }
-            }
-        printf("sleeping 10...\n");
-        sleep(10);
-        printf("deregistering all remaining records\n");;
-        DNSServiceRefDeallocate(sdr);
-        printf("done.  sleeping 10..\n");
-        sleep(10);
-        exit(1);
-        }
-                
-    if (!strcmp(argv[1], "-browse"))
-        {
-        if (argc < 3) exit(1);
-        err = DNSServiceBrowse(&sdr, 0, InterfaceIndex, argv[2], NULL /*"local."*/, browse_cb, NULL);
-        if (err) 
-            {
-            printf("DNSServiceBrowse returned error %d\n", err);
-            exit(1);
-            }
-        while(1) DNSServiceProcessResult(sdr);
-        }    
-                            
-    if (!strcmp(argv[1], "-enum"))
-        {
-        if (!strcmp(argv[2], "browse")) flags = kDNSServiceFlagsBrowseDomains;
-        else if (!strcmp(argv[2], "register")) flags = kDNSServiceFlagsRegistrationDomains;
-        else exit(1);
-        
-        err = DNSServiceEnumerateDomains(&sdr, flags, InterfaceIndex, my_enum_cb, NULL);
-        if (err) 
-            {
-            printf("EnumerateDomains returned error %d\n", err);
-            exit(1);
-            }
-        while(1) DNSServiceProcessResult(sdr);
-        }
-    if (!strcmp(argv[1], "-query"))
-        {
-        t = atol(argv[5]);
-        err = DNSServiceConstructFullName(full, argv[2], argv[3], argv[4]);
-        if (err) exit(1);
-        printf("resolving fullname %s type %d\n", full, t);
-        err = DNSServiceQueryRecord(&sdr, 0, 0, full, t, 1, query_cb, NULL);
-        while (1) DNSServiceProcessResult(sdr);
-        }
-
-    if (!strcmp(argv[1], "-regservice"))
-        {
-        char *regtype = "_http._tcp";
-               char txtstring[] = "\x0DMy Txt Record";
-        if (argc > 2) name = argv[2];
-        else name = NULL;
-        if (argc > 3) regtype = argv[3];
-               uint16_t PortAsNumber = 123;
-        if (argc > 4) PortAsNumber = atoi(argv[4]);
-               Opaque16 registerPort = { { PortAsNumber >> 8, PortAsNumber & 0xFF } };
-        err = DNSServiceRegister(&sdr, 0, InterfaceIndex, name, regtype, "local.", NULL, registerPort.NotAnInteger, sizeof(txtstring)-1, txtstring, regservice_cb, NULL);
-        if (err) 
-            {
-            printf("DNSServiceRegister returned error %d\n", err);
-            exit(1);
-            }
-        while (1) DNSServiceProcessResult(sdr);
-        }
-    if (!strcmp(argv[1], "-resolve"))
-        {
-        name = argv[2];
-        type = argv[3];
-        domain = argv[4];
-        err = DNSServiceResolve(&sdr, 0, InterfaceIndex, name, type, domain, resolve_cb, NULL);
-        if (err) 
-            {
-            printf("DNSServiceResolve returned error %d\n", err);
-            exit(1);
-            }
-        while(1) DNSServiceProcessResult(sdr);
-        }
-    exit(1);
-    }    
-
-
-
-// callbacks
-
-// wrapper to make callbacks fit CFRunLoop callback signature
-/*
-static void MyCallbackWrapper(CFSocketRef sr, CFSocketCallBackType t, CFDataRef dr, const void *i, void *context)  
-    {
-    (void)sr;
-    (void)t;
-    (void)dr;
-    (void)i;
-    
-    DNSServiceRef *sdr = context;
-    DNSServiceDiscoveryProcessResult(*sdr);
-    }
-*/
-
-static void browse_cb(DNSServiceRef sdr, DNSServiceFlags flags, uint32_t ifi, DNSServiceErrorType err, const char *serviceName, const char *regtype, const char *domain, void *context)
-    {
-    #pragma unused(sdr, ifi, context)
-    
-    if (err)
-        {
-        printf("Callback: error %d\n", err);
-        return;
-        }
-    printf("BrowseCB: %s %s %s %s (%s)\n", serviceName, regtype, domain, (flags & kDNSServiceFlagsMoreComing ? "(more coming)" : ""), flags & kDNSServiceFlagsAdd ? "(ADD)" : "(REMOVE)");
-
-    }
-
-static void my_enum_cb( DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *replyDomain, void *context)
-    {
-    #pragma unused(sdRef, context)
-    char *type;
-    if (flags == kDNSServiceFlagsAdd) type = "add";
-    else if (flags == kDNSServiceFlagsRemove) type = "remove";
-    else if (flags == (kDNSServiceFlagsAdd | kDNSServiceFlagsDefault)) type = "add default";
-    else type = "unknown";
-    
-    
-    if (errorCode) printf("EnumerateDomainsCB: error code %d\n", errorCode);
-    else printf("%s domain %s on interface %d\n", type, replyDomain, interfaceIndex);
-    }
-    
-static void query_cb(const DNSServiceRef DNSServiceRef, const DNSServiceFlags flags, const u_int32_t interfaceIndex, const DNSServiceErrorType errorCode, const char *name, const u_int16_t rrtype, const u_int16_t rrclass, const u_int16_t rdlen, const void *rdata, const u_int32_t ttl, void *context) 
-    {
-    (void)DNSServiceRef;
-    (void)flags;
-    (void)interfaceIndex;
-    (void)rrclass;
-    (void)ttl;
-    (void)context;
-    
-    if (errorCode)
-        {
-        printf("query callback: error==%d\n", errorCode);
-        return;
-        }
-    printf("query callback - name = %s, rdata=\n", name);
-    print_rdata(rrtype, rdlen, rdata);
-    }
-static void resolve_cb(const DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *fullname, const char *hosttarget, uint16_t port, uint16_t txtLen, const char *txtRecord, void *context)
-    {
-    int i;
-    
-    #pragma unused(sdRef, flags, interfaceIndex, errorCode, context, txtRecord)
-    printf("Resolved %s to %s:%d (%d bytes txt data)\n", fullname, hosttarget, port, txtLen);
-    printf("TXT Data:\n");
-    for (i = 0; i < txtLen; i++)
-        if (txtRecord[i] >= ' ') printf("%c", txtRecord[i]);
-    }
-
-
-
-static void my_regecordcb(DNSServiceRef sdRef, DNSRecordRef RecordRef, DNSServiceFlags flags, DNSServiceErrorType errorCode, void *context)
-    {
-    #pragma unused (sdRef, RecordRef, flags, context)
-    if (errorCode) printf("regrecord CB received error %d\n", errorCode);
-    else printf("regrecord callback - no errors\n");
-    }
-
-
-// resource record data interpretation routines
-static char *ConvertDomainLabelToCString_withescape(const domainlabel *const label, char *ptr, char esc)
-    {
-    const u_char *      src = label->c;                         // Domain label we're reading
-    const u_char        len = *src++;                           // Read length of this (non-null) label
-    const u_char *const end = src + len;                        // Work out where the label ends
-    if (len > MAX_DOMAIN_LABEL) return(NULL);           // If illegal label, abort
-    while (src < end)                                           // While we have characters in the label
-        {
-        u_char c = *src++;
-        if (esc)
-            {
-            if (c == '.')                                       // If character is a dot,
-                *ptr++ = esc;                                   // Output escape character
-            else if (c <= ' ')                                  // If non-printing ascii,
-                {                                                   // Output decimal escape sequence
-                *ptr++ = esc;
-                *ptr++ = (char)  ('0' + (c / 100)     );
-                *ptr++ = (char)  ('0' + (c /  10) % 10);
-                c      = (u_char)('0' + (c      ) % 10);
-                }
-            }
-        *ptr++ = (char)c;                                       // Copy the character
-        }
-    *ptr = 0;                                                   // Null-terminate the string
-    return(ptr);                                                // and return
-    }
-static char *ConvertDomainNameToCString_withescape(const domainname *const name, char *ptr, char esc)
-    {
-    const u_char *src         = name->c;                        // Domain name we're reading
-    const u_char *const max   = name->c + MAX_DOMAIN_NAME;      // Maximum that's valid
-
-    if (*src == 0) *ptr++ = '.';                                // Special case: For root, just write a dot
-
-    while (*src)                                                                                                        // While more characters in the domain name
-        {
-        if (src + 1 + *src >= max) return(NULL);
-        ptr = ConvertDomainLabelToCString_withescape((const domainlabel *)src, ptr, esc);
-        if (!ptr) return(NULL);
-        src += 1 + *src;
-        *ptr++ = '.';                                           // Write the dot after the label
-        }
-
-    *ptr++ = 0;                                                 // Null-terminate the string
-    return(ptr);                                                // and return
-    }
-
-// print arbitrary rdata in a readable manned 
-static void print_rdata(int type, int len, const u_char *rdata)
-    {
-    int i;
-    srv_rdata *srv;
-    char targetstr[MAX_CSTRING];
-    struct in_addr in;
-    
-    switch (type)
-        {
-        case T_TXT:
-            // print all the alphanumeric and punctuation characters
-            for (i = 0; i < len; i++)
-                if (rdata[i] >= 32 && rdata[i] <= 127) printf("%c", rdata[i]);
-            printf("\n");
-            return;
-        case T_SRV:
-            srv = (srv_rdata *)rdata;
-            ConvertDomainNameToCString_withescape(&srv->target, targetstr, 0);
-            printf("pri=%d, w=%d, port=%d, target=%s\n", srv->priority, srv->weight, srv->port, targetstr);
-            return;
-        case T_A:
-            assert(len == 4);
-            memcpy(&in, rdata, sizeof(in));
-            printf("%s\n", inet_ntoa(in));
-            return;
-        case T_PTR:
-            ConvertDomainNameToCString_withescape((domainname *)rdata, targetstr, 0);
-            printf("%s\n", targetstr);
-            return;
-        default:
-            printf("ERROR: I dont know how to print RData of type %d\n", type);
-            return;
-        }
-    }
-
-
-
-
-// signal handlers, setup/teardown, etc.
-static void sighdlr(int signo)
-    {
-    assert(signo == SIGINT);
-    fprintf(stderr, "Received sigint - deallocating serviceref and exiting\n");
-    if (sdr)
-        DNSServiceRefDeallocate(sdr);
-    exit(1);
-    }
-
-
index f905bd79e86d860737f2c03de3d87e1edeeef4d4..430d0e6e1186055449762506c31e21f1c9915564 100644 (file)
@@ -3,6 +3,8 @@
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
     Change History (most recent first):
 
 $Log: SamplemDNSClient.c,v $
+Revision 1.44  2004/05/28 02:20:06  cheshire
+If we allow dot or empty string for domain when resolving a service,
+it should be a synonym for "local"
+
+Revision 1.43  2004/02/03 22:07:50  cheshire
+<rdar://problem/3548184>: Widen columns to display non-local domains better
+
+Revision 1.42  2003/12/03 11:39:17  cheshire
+<rdar://problem/3468977> Browse output misaligned in mDNS command-line tool
+(Also fix it to add leading space when the hours part of the time is only one digit)
+
+Revision 1.41  2003/10/30 22:52:57  cheshire
+<rdar://problem/3468977> Browse output misaligned in mDNS command-line tool
+
+Revision 1.40  2003/09/26 01:07:06  cheshire
+Added test case to test fix for <rdar://problem/3427923>
+
 Revision 1.39  2003/08/18 19:05:45  cheshire
 <rdar://problem/3382423> UpdateRecord not working right
 Added "newrdlength" field to hold new length of updated rdata
@@ -127,7 +146,7 @@ static void printtimestamp(void)
        struct tm tm;
        gettimeofday(&tv, NULL);
        localtime_r((time_t*)&tv.tv_sec, &tm);
-       printf("%d:%02d:%02d.%03d  ", tm.tm_hour, tm.tm_min, tm.tm_sec, tv.tv_usec/1000);
+       printf("%2d:%02d:%02d.%03d  ", tm.tm_hour, tm.tm_min, tm.tm_sec, tv.tv_usec/1000);
        }
 
 #define DomainMsg(X) ((X) == DNSServiceDomainEnumerationReplyAddDomain        ? "Added"     :          \
@@ -159,9 +178,9 @@ static void browse_reply(DNSServiceBrowserReplyResultType resultType,
        {
        char *op = (resultType == DNSServiceBrowserReplyAddInstance) ? "Add" : "Rmv";
     (void)context; // Unused
-       if (num_printed++ == 0) printf("A/R Flags %-8s %-20s %s\n", "Domain", "Service Type", "Instance Name");
+       if (num_printed++ == 0) printf("Timestamp     A/R Flags %-24s %-24s %s\n", "Domain", "Service Type", "Instance Name");
        printtimestamp();
-       printf("%s%6X %-8s %-20s %s\n", op, flags, replyDomain, replyType, replyName);
+       printf("%s%6X %-24s %-24s %s\n", op, flags, replyDomain, replyType, replyName);
        }
 
 static void resolve_reply(struct sockaddr *interface, struct sockaddr *address, const char *txtRecord, DNSServiceDiscoveryReplyFlags flags, void *context)
@@ -307,7 +326,7 @@ int main(int argc, char **argv)
        setlinebuf(stdout);                             // Want to see lines as they appear, not block buffered
 
        if (argc < 2) goto Fail;                // Minimum command line is the command name and one argument
-    operation = getopt(argc, (char * const *)argv, "EFBLRAUNTM");
+    operation = getopt(argc, (char * const *)argv, "EFBLRAUNTMI");
        if (operation == -1) goto Fail;
 
     switch (operation)
@@ -321,7 +340,7 @@ int main(int argc, char **argv)
                     break;
 
         case 'B':      if (argc < optind+1) goto Fail;
-                    dom = (argc < optind+2) ? "" : argv[optind+1];
+                    dom = (argc < optind+2) ? "local" : argv[optind+1];
                     if (dom[0] == '.' && dom[1] == 0) dom[0] = 0;      // We allow '.' on the command line as a synonym for empty string
                     printf("Browsing for %s%s\n", argv[optind+0], dom);
                     client = DNSServiceBrowserCreate(argv[optind+0], dom, browse_reply, nil);
@@ -329,7 +348,7 @@ int main(int argc, char **argv)
 
         case 'L':      if (argc < optind+2) goto Fail;
                     dom = (argc < optind+3) ? "" : argv[optind+2];
-                    if (dom[0] == '.' && dom[1] == 0) dom[0] = 0;      // We allow '.' on the command line as a synonym for empty string
+                                       if (dom[0] == '.' && dom[1] == 0) dom = "local";   // We allow '.' on the command line as a synonym for "local"
                     printf("Lookup %s.%s%s\n", argv[optind+0], argv[optind+1], dom);
                     client = DNSServiceResolverResolve(argv[optind+0], argv[optind+1], dom, resolve_reply, nil);
                     break;
@@ -397,6 +416,16 @@ int main(int argc, char **argv)
                     break;
                     }
 
+        case 'I':      {
+                    pid_t pid = getpid();
+                    Opaque16 registerPort = { { pid >> 8, pid & 0xFF } };
+                    static const char TXT[] = "\x09" "Test Data";
+                    printf("Registering Service Test._testtxt._tcp.local.\n");
+                    client = DNSServiceRegistrationCreate("", "_testtxt._tcp.", "", registerPort.NotAnInteger, "", reg_reply, nil);
+                    if (client) DNSServiceRegistrationUpdateRecord(client, 0, 1+TXT[0], &TXT[0], 120);
+                    break;
+                    }
+
         default: goto Exit;
         }
 
@@ -424,5 +453,6 @@ Fail:
        fprintf(stderr, "%s -N                             (Test adding a large NULL record)\n", argv[0]);
        fprintf(stderr, "%s -T                            (Test creating a large TXT record)\n", argv[0]);
        fprintf(stderr, "%s -M      (Test creating a registration with multiple TXT records)\n", argv[0]);
+       fprintf(stderr, "%s -I   (Test registering and then immediately updating TXT record)\n", argv[0]);
        return 0;
        }
index 97105170d0b789ce5f3c00a40fa6e4b7573d772a..9cb6a47efeed9f6405c97412455e2eb486743024 100644 (file)
@@ -3,6 +3,8 @@
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
     Change History (most recent first):
 
 $Log: daemon.c,v $
-Revision 1.134.2.8  2005/01/28 04:03:24  cheshire
-<rdar://problem/3759302> SUPan: Current method of doing subtypes causes name collisions
-Summary: Pulled in ConstructServiceName, CountSubTypes and AllocateSubTypes from Tiger version.
+Revision 1.175  2004/06/10 20:23:21  cheshire
+Also list interfaces in SIGINFO output
+
+Revision 1.174  2004/06/08 18:54:48  ksekar
+<rdar://problem/3681378>: mDNSResponder leaks after exploring in Printer Setup Utility
+
+Revision 1.173  2004/06/08 17:35:12  cheshire
+<rdar://problem/3683988> Detect and report if mDNSResponder uses too much CPU
+
+Revision 1.172  2004/06/05 00:04:26  cheshire
+<rdar://problem/3668639>: wide-area domains should be returned in reg. domain enumeration
+
+Revision 1.171  2004/06/04 08:58:30  ksekar
+<rdar://problem/3668624>: Keychain integration for secure dynamic update
+
+Revision 1.170  2004/05/30 20:01:50  ksekar
+<rdar://problem/3668635>: wide-area default registrations should be in
+.local too - fixed service registration when clients pass an explicit
+domain (broken by previous checkin)
+
+Revision 1.169  2004/05/30 01:30:16  ksekar
+<rdar://problem/3668635>: wide-area default registrations should be in
+.local too
+
+Revision 1.168  2004/05/18 23:51:26  cheshire
+Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
+
+Revision 1.167  2004/05/14 16:39:47  ksekar
+Browse for iChat locally for now.
+
+Revision 1.166  2004/05/13 21:33:52  ksekar
+Clean up non-local registration control via config file.  Force iChat
+registrations to be local for now.
 
-Revision 1.134.2.7  2004/06/18 17:28:19  cheshire
-<rdar://problem/3588761> Current method of doing subtypes causes name collisions
+Revision 1.165  2004/05/13 04:54:20  ksekar
+Unified list copy/free code.  Added symetric list for
 
-Revision 1.134.2.6  2004/04/06 19:50:36  cheshire
+Revision 1.164  2004/05/12 22:03:08  ksekar
+Made GetSearchDomainList a true platform-layer call (declaration moved
+from mDNSMacOSX.h to mDNSClientAPI.h), impelemted to return "local"
+only on non-OSX platforms.  Changed call to return a copy of the list
+to avoid shared memory issues.  Added a routine to free the list.
+
+Revision 1.163  2004/05/12 02:03:25  ksekar
+Non-local domains will only be browsed by default, and show up in
+_browse domain enumeration, if they contain an _browse._dns-sd ptr record.
+
+Revision 1.162  2004/04/14 23:09:29  ksekar
+Support for TSIG signed dynamic updates.
+
+Revision 1.161  2004/04/07 01:20:04  cheshire
+Hash slot value should be unsigned
+
+Revision 1.160  2004/04/06 19:51:24  cheshire
 <rdar://problem/3605898> mDNSResponder will not launch if "nobody" user doesn't exist.
 After more discussion, we've decided to use userid -2 if "nobody" user doesn't exist.
 
-Revision 1.134.2.5  2004/04/03 01:29:07  cheshire
+Revision 1.159  2004/04/03 01:36:55  cheshire
 <rdar://problem/3605898> mDNSResponder will not launch if "nobody" user doesn't exist.
 If "nobody" user doesn't exist, log a message and continue as "root"
 
-Revision 1.134.2.4  2004/04/02 21:50:21  cheshire
+Revision 1.158  2004/04/02 21:39:05  cheshire
 Fix errors in comments
 
-Revision 1.134.2.3  2003/12/12 01:21:30  cheshire
-<rdar://problem/3491108> mDNSResponder should not run as root
+Revision 1.157  2004/03/19 18:49:10  ksekar
+Increased size check in freeL() to account for LargeCacheRecord
+structs larger than 8k
+
+Revision 1.156  2004/03/19 18:19:19  ksekar
+Fixed daemon.c to compile with malloc debugging turned on.
+
+Revision 1.155  2004/03/13 01:57:34  ksekar
+<rdar://problem/3192546>: DynDNS: Dynamic update of service records
+
+Revision 1.154  2004/03/12 08:42:47  cheshire
+<rdar://problem/3548256>: Should not allow empty string for resolve domain
+
+Revision 1.153  2004/03/12 08:08:51  cheshire
+Update comments
+
+Revision 1.152  2004/02/05 19:39:29  cheshire
+Move creation of /var/run/mDNSResponder.pid to uds_daemon.c,
+so that all platforms get this functionality
+
+Revision 1.151  2004/02/03 22:35:34  cheshire
+<rdar://problem/3548256>: Should not allow empty string for resolve domain
 
-Revision 1.134.2.2  2003/12/05 00:03:35  cheshire
-<rdar://problem/3487869> Use buffer size MAX_ESCAPED_DOMAIN_NAME instead of 256
+Revision 1.150  2004/01/28 21:14:23  cheshire
+Reconcile debug_mode and gDebugLogging into a single flag (mDNS_DebugMode)
 
-Revision 1.134.2.1  2003/12/03 11:00:09  cheshire
-Update "mDNSResponderVersion" mechanism to allow dots so we can do mDNSResponder-58.1 for SUPan
+Revision 1.149  2004/01/28 02:30:08  ksekar
+Added default Search Domains to unicast browsing, controlled via
+Networking sharing prefs pane.  Stopped sending unicast messages on
+every interface.  Fixed unicast resolving via mach-port API.
+
+Revision 1.148  2004/01/25 00:03:20  cheshire
+Change to use mDNSVal16() instead of private PORT_AS_NUM() macro
+
+Revision 1.147  2004/01/19 19:51:46  cheshire
+Fix compiler error (mixed declarations and code) on some versions of Linux
+
+Revision 1.146  2003/12/08 21:00:46  rpantos
+Changes to support mDNSResponder on Linux.
+
+Revision 1.145  2003/12/05 22:08:07  cheshire
+Update version string to "mDNSResponder-61", including new mechanism to allow dots (e.g. 58.1)
+
+Revision 1.144  2003/11/19 23:21:08  ksekar
+<rdar://problem/3486646>: config change handler not called for dns-sd services
+
+Revision 1.143  2003/11/14 21:18:32  cheshire
+<rdar://problem/3484766>: Security: Crashing bug in mDNSResponder
+Fix code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1005) instead of 256-byte buffers.
+
+Revision 1.142  2003/11/08 22:18:29  cheshire
+<rdar://problem/3477870>: Don't need to show process ID in *every* mDNSResponder syslog message
+
+Revision 1.141  2003/11/07 02:30:57  cheshire
+Also check per-slot cache use counts in SIGINFO state log
+
+Revision 1.140  2003/10/21 19:58:26  cheshire
+<rdar://problem/3459037> Syslog messages should show TTL as signed (for overdue records)
+
+Revision 1.139  2003/10/21 00:10:18  rpantos
+<rdar://problem/3409401>: mDNSResponder should not run as root
+
+Revision 1.138  2003/10/07 20:16:58  cheshire
+Shorten syslog message a bit
+
+Revision 1.137  2003/09/23 02:12:43  cheshire
+Also include port number in list of services registered via new UDS API
+
+Revision 1.136  2003/09/23 02:07:25  cheshire
+Include port number in DNSServiceRegistration START/STOP messages
+
+Revision 1.135  2003/09/23 01:34:02  cheshire
+In SIGINFO state log, show remaining TTL on cache records, and port number on ServiceRegistrations
 
 Revision 1.134  2003/08/21 20:01:37  cheshire
 <rdar://problem/3387941> Traffic reduction: Detect long-lived Resolve() calls, and report them in syslog
@@ -109,8 +222,7 @@ Revision 1.122  2003/07/23 00:00:04  cheshire
 Add comments
 
 Revision 1.121  2003/07/20 03:38:51  ksekar
-Bug #: 3320722
-Completed support for Unix-domain socket based API.
+<rdar://problem/3320722> Completed support for Unix-domain socket based API.
 
 Revision 1.120  2003/07/18 00:30:00  cheshire
 <rdar://problem/3268878> Remove mDNSResponder version from packet header and use HINFO record instead
@@ -139,7 +251,7 @@ standard error file descriptors to /dev/null just like any other
 well behaved daemon
 
 Revision 1.112  2003/06/25 23:42:19  ksekar
-Bug #: <rdar://problem/3249292>: Feature: New Rendezvous APIs (#7875)
+<rdar://problem/3249292>: Feature: New Rendezvous APIs (#7875)
 Reviewed by: Stuart Cheshire
 Added files necessary to implement Unix domain sockets based enhanced
 Rendezvous APIs, and integrated with existing Mach-port based daemon.
@@ -185,7 +297,7 @@ Revision 1.101  2003/05/22 00:26:55  cheshire
 Modify error message to explain that this is technically legal, but may indicate a bug.
 
 Revision 1.100  2003/05/21 21:02:24  ksekar
-Bug #: <rdar://problem/3247035>: Service should be prefixed
+<rdar://problem/3247035>: Service should be prefixed
 Changed kmDNSBootstrapName to "com.apple.mDNSResponderRestart" since we're changing the main
 Mach message port to "com.apple.mDNSResponder.
 
@@ -231,12 +343,11 @@ Add $Log header
 #include "mDNSClientAPI.h"                     // Defines the interface to the client layer above
 #include "mDNSMacOSX.h"                                // Defines the specific types needed to run mDNS on this platform
 
-extern mDNSs32 CountSubTypes(char *regtype);
-extern AuthRecord *AllocateSubTypes(mDNSs32 NumSubTypes, char *p);
+#include "uds_daemon.h"                                // Interface to the server side implementation of dns_sd.h
 
-#include <DNSServiceDiscovery/DNSServiceDiscovery.h>
+#include "GenLinkedList.h"
 
-#define ENABLE_UDS 1
+#include <DNSServiceDiscovery/DNSServiceDiscovery.h>
 
 //*************************************************************************************************************
 // Macros
@@ -247,14 +358,18 @@ extern AuthRecord *AllocateSubTypes(mDNSs32 NumSubTypes, char *p);
 #define STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s) #s 
 #define STRINGIFY(s) STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s)
 
+// convenience definition 
+#define        _UNUSED __attribute__ ((unused))
+
 //*************************************************************************************************************
 // Globals
 
+#define LOCAL_DEFAULT_REG 1 // empty string means register in the local domain
+#define DEFAULT_REG_DOMAIN "apple.com." // used if the above flag is turned off
 mDNSexport mDNS mDNSStorage;
 static mDNS_PlatformSupport PlatformStorage;
 #define RR_CACHE_SIZE 64
 static CacheRecord rrcachestorage[RR_CACHE_SIZE];
-static const char PID_FILE[] = "/var/run/mDNSResponder.pid";
 
 static const char kmDNSBootstrapName[] = "com.apple.mDNSResponderRestart";
 static mach_port_t client_death_port = MACH_PORT_NULL;
@@ -272,12 +387,6 @@ static mach_port_t server_priv_port  = MACH_PORT_NULL;
 
 static int restarting_via_mach_init = 0;
 
-#if MDNS_DEBUGMSGS
-int debug_mode = 1;
-#else
-int debug_mode = 0;
-#endif
-
 //*************************************************************************************************************
 // Active client list structures
 
@@ -299,11 +408,18 @@ struct DNSServiceBrowserResult_struct
        };
 
 typedef struct DNSServiceBrowser_struct DNSServiceBrowser;
+
+typedef struct DNSServiceBrowserQuestion
+       {
+    struct DNSServiceBrowserQuestion *next;
+    DNSQuestion q;
+       } DNSServiceBrowserQuestion;
+
 struct DNSServiceBrowser_struct
        {
        DNSServiceBrowser *next;
        mach_port_t ClientMachPort;
-       DNSQuestion q;
+    DNSServiceBrowserQuestion *qlist;
        DNSServiceBrowserResult *results;
        mDNSs32 lastsuccess;
        };
@@ -318,15 +434,30 @@ struct DNSServiceResolver_struct
        mDNSs32          ReportTime;
        };
 
+
+typedef struct ExtraRecordRef
+       {
+    ExtraResourceRecord *localRef;  // extra added to .local service
+    ExtraResourceRecord *globalRef; // extra added to default global service (may be NULL)
+    struct ExtraRecordRef *next;
+       } ExtraRecordRef;
+
 typedef struct DNSServiceRegistration_struct DNSServiceRegistration;
 struct DNSServiceRegistration_struct
        {
        DNSServiceRegistration *next;
        mach_port_t ClientMachPort;
        mDNSBool autoname;
-       mDNSBool autorename;
+       mDNSBool autorenameLS;
+    mDNSBool autorenameGS;
+    mDNSBool deallocate;  // gs and ls (below) will receive separate MemFree callbacks,
+                          // the latter of which must deallocate the wrapper structure.
+                          // ls MemFree callback: if (!gs) free wrapper;  else set deallocate flag
+                          // gs callback: if (deallocate) free wrapper;  else free (gs), gs = NULL 
        domainlabel name;
-       ServiceRecordSet s;
+    ExtraRecordRef   *ExtraRefList;
+    ServiceRecordSet *gs; // default "global" (wide area) service (may be NULL)
+    ServiceRecordSet ls;  // .local service (also used if client passes an explicit domain)
        // Don't add any fields after ServiceRecordSet.
        // This is where the implicit extra space goes if we allocate an oversized ServiceRecordSet object
        };
@@ -352,7 +483,7 @@ static void validatelists(mDNS *const m)
        AuthRecord                  *rr;
        CacheRecord                 *cr;
        DNSQuestion                 *q;
-       mDNSs32 slot;
+       mDNSu32 slot;
        
        for (e = DNSServiceDomainEnumerationList; e; e=e->next)
                if (e->ClientMachPort == 0 || e->ClientMachPort == (mach_port_t)~0)
@@ -371,12 +502,12 @@ static void validatelists(mDNS *const m)
                        LogMsg("!!!! DNSServiceRegistrationList: %p is garbage (%X) !!!!", r, r->ClientMachPort);
 
        for (rr = m->ResourceRecords; rr; rr=rr->next)
-               if (rr->RecordType == 0 || rr->RecordType == 0xFF)
-                       LogMsg("!!!! ResourceRecords list: %p is garbage (%X) !!!!", rr, rr->RecordType);
+               if (rr->resrec.RecordType == 0 || rr->resrec.RecordType == 0xFF)
+                       LogMsg("!!!! ResourceRecords list: %p is garbage (%X) !!!!", rr, rr->resrec.RecordType);
 
        for (rr = m->DuplicateRecords; rr; rr=rr->next)
-               if (rr->RecordType == 0 || rr->RecordType == 0xFF)
-                       LogMsg("!!!! DuplicateRecords list: %p is garbage (%X) !!!!", rr, rr->RecordType);
+               if (rr->resrec.RecordType == 0 || rr->resrec.RecordType == 0xFF)
+                       LogMsg("!!!! DuplicateRecords list: %p is garbage (%X) !!!!", rr, rr->resrec.RecordType);
 
        for (q = m->Questions; q; q=q->next)
                if (q->ThisQInterval == (mDNSs32)~0)
@@ -384,8 +515,8 @@ static void validatelists(mDNS *const m)
 
        for (slot = 0; slot < CACHE_HASH_SLOTS; slot++)
                for (cr = mDNSStorage.rrcache_hash[slot]; cr; cr=cr->next)
-                       if (cr->RecordType == 0 || cr->RecordType == 0xFF)
-                               LogMsg("!!!! Cache slot %lu: %p is garbage (%X) !!!!", slot, rr, rr->RecordType);
+                       if (cr->resrec.RecordType == 0 || cr->resrec.RecordType == 0xFF)
+                               LogMsg("!!!! Cache slot %lu: %p is garbage (%X) !!!!", slot, rr, rr->resrec.RecordType);
        }
 
 void *mallocL(char *msg, unsigned int size)
@@ -417,7 +548,7 @@ void freeL(char *msg, void *x)
                unsigned long *mem = ((unsigned long *)x) - 2;
                if (mem[0] != 0xDEAD1234)
                        { LogMsg("free( %s @ %p ) !!!! NOT ALLOCATED !!!!", msg, &mem[2]); return; }
-               if (mem[1] > 8000)
+               if (mem[1] > 24000)
                        { LogMsg("free( %s : %ld @ %p) too big!", msg, mem[1], &mem[2]); return; }
                LogMalloc("free( %s : %ld @ %p)", msg, mem[1], &mem[2]);
                //bzero(mem, mem[1]+8);
@@ -432,25 +563,46 @@ void freeL(char *msg, void *x)
 //*************************************************************************************************************
 // Client Death Detection
 
-mDNSlocal void FreeDNSServiceRegistration(DNSServiceRegistration *x)
+mDNSlocal void FreeSRS(ServiceRecordSet *s)
        {
-       while (x->s.Extras)
+       while (s->Extras)
                {
-               ExtraResourceRecord *extras = x->s.Extras;
-               x->s.Extras = x->s.Extras->next;
+               ExtraResourceRecord *extras = s->Extras;
+               s->Extras = s->Extras->next;
                if (extras->r.resrec.rdata != &extras->r.rdatastorage)
                        freeL("Extra RData", extras->r.resrec.rdata);
                freeL("ExtraResourceRecord", extras);
                }
 
-       if (x->s.RR_TXT.resrec.rdata != &x->s.RR_TXT.rdatastorage)
-                       freeL("TXT RData", x->s.RR_TXT.resrec.rdata);
+       if (s->RR_TXT.resrec.rdata != &s->RR_TXT.rdatastorage)
+                       freeL("TXT RData", s->RR_TXT.resrec.rdata);
 
-       if (x->s.SubTypes) freeL("ServiceSubTypes", x->s.SubTypes);
+       if (s->SubTypes) freeL("ServiceSubTypes", s->SubTypes); 
+       }
+
+mDNSlocal void FreeDNSServiceRegistration(ServiceRecordSet *srs)
+       {
+       DNSServiceRegistration *x = srs->ServiceContext;
+       ExtraRecordRef *ref, *fptr;
        
-       freeL("DNSServiceRegistration", x);
+       FreeSRS(srs); 
+       if (srs == x->gs)
+               {
+               freeL("DNSServiceRegistration GlobalService", srs);
+               x->gs = NULL;
+               }
+       else x->deallocate = mDNStrue;
+
+       if (x->deallocate && !x->gs)
+               {
+               ref = x->ExtraRefList;
+               while (ref)                     
+                       { fptr = ref; ref = ref->next; freeL("ExtraRecordRef", fptr); }
+               freeL("DNSServiceRegistration", x);
+               }
        }
 
+
 // AbortClient finds whatever client is identified by the given Mach port,
 // stops whatever operation that client was doing, and frees its memory.
 // In the case of a service registration, the actual freeing may be deferred
@@ -479,12 +631,19 @@ mDNSlocal void AbortClient(mach_port_t ClientMachPort, void *m)
        while (*b && (*b)->ClientMachPort != ClientMachPort) b = &(*b)->next;
        if (*b)
                {
-               DNSServiceBrowser *x = *b;
+               DNSServiceBrowser *x = *b;              
+               DNSServiceBrowserQuestion *freePtr, *qptr = x->qlist;
                *b = (*b)->next;
-               if (m && m != x)
-                       LogMsg("%5d: DNSServiceBrowser(%##s) STOP; WARNING m %p != x %p", ClientMachPort, x->q.qname.c, m, x);
-               else LogOperation("%5d: DNSServiceBrowser(%##s) STOP", ClientMachPort, x->q.qname.c);
-               mDNS_StopBrowse(&mDNSStorage, &x->q);
+               while (qptr)
+                       {
+                       if (m && m != x)
+                               LogMsg("%5d: DNSServiceBrowser(%##s) STOP; WARNING m %p != x %p", ClientMachPort, qptr->q.qname.c, m, x);
+                       else LogOperation("%5d: DNSServiceBrowser(%##s) STOP", ClientMachPort, qptr->q.qname.c);
+                       mDNS_StopBrowse(&mDNSStorage, &qptr->q);
+                       freePtr = qptr;
+                       qptr = qptr->next;                      
+                       freeL("DNSServiceBrowserQuestion", freePtr);
+                       }
                while (x->results)
                        {
                        DNSServiceBrowserResult *r = x->results;
@@ -513,16 +672,30 @@ mDNSlocal void AbortClient(mach_port_t ClientMachPort, void *m)
                {
                DNSServiceRegistration *x = *r;
                *r = (*r)->next;
-               x->autorename = mDNSfalse;
+               x->autorenameLS = mDNSfalse;
+               x->autorenameGS = mDNSfalse;
                if (m && m != x)
-                       LogMsg("%5d: DNSServiceRegistration(%##s) STOP; WARNING m %p != x %p", ClientMachPort, x->s.RR_SRV.resrec.name.c, m, x);
-               else LogOperation("%5d: DNSServiceRegistration(%##s) STOP", ClientMachPort, x->s.RR_SRV.resrec.name.c);
+                       {
+                       LogMsg("%5d: DNSServiceRegistration(%##s, %u) STOP; WARNING m %p != x %p", ClientMachPort, x->ls.RR_SRV.resrec.name.c, SRS_PORT(&x->ls), m, x);
+                       if (x->gs) LogMsg("%5d: DNSServiceRegistration(%##s, %u) STOP; WARNING m %p != x %p", ClientMachPort, x->gs->RR_SRV.resrec.name.c, SRS_PORT(x->gs), m, x);
+                       }
+               else
+                       {
+                       LogOperation("%5d: DNSServiceRegistration(%##s, %u) STOP", ClientMachPort, x->ls.RR_SRV.resrec.name.c, SRS_PORT(&x->ls));
+                       if (x->gs) LogOperation("%5d: DNSServiceRegistration(%##s, %u) STOP", ClientMachPort, x->gs->RR_SRV.resrec.name.c, SRS_PORT(x->gs));
+                       }
                // If mDNS_DeregisterService() returns mStatus_NoError, that means that the service was found in the list,
                // is sending its goodbye packet, and we'll get an mStatus_MemFree message when we can free the memory.
                // If mDNS_DeregisterService() returns an error, it means that the service had already been removed from
                // the list, so we should go ahead and free the memory right now
-               if (mDNS_DeregisterService(&mDNSStorage, &x->s) != mStatus_NoError)
-                       FreeDNSServiceRegistration(x);
+               if (x->gs && mDNS_DeregisterService(&mDNSStorage, x->gs))
+                       {
+                       // Deregister returned an error, so we free immediately
+                       FreeSRS(x->gs);
+                       x->gs = NULL;
+                       }
+               if (mDNS_DeregisterService(&mDNSStorage, &x->ls))
+                       FreeDNSServiceRegistration(&x->ls);
                return;
                }
 
@@ -537,15 +710,25 @@ mDNSlocal void AbortClientWithLogMessage(mach_port_t c, char *reason, char *msg,
        DNSServiceBrowser           *b = DNSServiceBrowserList;
        DNSServiceResolver          *l = DNSServiceResolverList;
        DNSServiceRegistration      *r = DNSServiceRegistrationList;
+       DNSServiceBrowserQuestion   *qptr;
+
        while (e && e->ClientMachPort != c) e = e->next;
        while (b && b->ClientMachPort != c) b = b->next;
        while (l && l->ClientMachPort != c) l = l->next;
        while (r && r->ClientMachPort != c) r = r->next;
-       if      (e) LogMsg("%5d: DomainEnumeration(%##s) %s%s",                   c, e->dom.qname.c,            reason, msg);
-       else if (b) LogMsg("%5d: Browser(%##s) %s%s",                             c, b->q.qname.c,              reason, msg);
-       else if (l) LogMsg("%5d: Resolver(%##s) %s%s",                            c, l->i.name.c,               reason, msg);
-       else if (r) LogMsg("%5d: Registration(%##s) %s%s",                        c, r->s.RR_SRV.resrec.name.c, reason, msg);
-       else        LogMsg("%5d: (%s) %s, but no record of client can be found!", c,                            reason, msg);
+       if      (e)     LogMsg("%5d: DomainEnumeration(%##s) %s%s",                   c, e->dom.qname.c,            reason, msg);
+       else if (b)
+               {
+               for (qptr = b->qlist; qptr; qptr = qptr->next)
+                               LogMsg("%5d: Browser(%##s) %s%s",                             c, qptr->q.qname.c,              reason, msg);
+               }
+       else if (l)     LogMsg("%5d: Resolver(%##s) %s%s",                            c, l->i.name.c,               reason, msg);
+       else if (r)
+               {
+                           LogMsg("%5d: Registration(%##s) %s%s",                        c, r->ls.RR_SRV.resrec.name.c, reason, msg);
+               if (r->gs)  LogMsg("%5d: Registration(%##s) %s%s",                        c, r->gs->RR_SRV.resrec.name.c, reason, msg);
+               }
+       else            LogMsg("%5d: (%s) %s, but no record of client can be found!", c,                            reason, msg);
 
        AbortClient(c, m);
        }
@@ -556,14 +739,20 @@ mDNSlocal mDNSBool CheckForExistingClient(mach_port_t c)
        DNSServiceBrowser           *b = DNSServiceBrowserList;
        DNSServiceResolver          *l = DNSServiceResolverList;
        DNSServiceRegistration      *r = DNSServiceRegistrationList;
+       DNSServiceBrowserQuestion   *qptr;
+       
        while (e && e->ClientMachPort != c) e = e->next;
        while (b && b->ClientMachPort != c) b = b->next;
        while (l && l->ClientMachPort != c) l = l->next;
        while (r && r->ClientMachPort != c) r = r->next;
        if (e) LogMsg("%5d: DomainEnumeration(%##s) already exists!", c, e->dom.qname.c);
-       if (b) LogMsg("%5d: Browser(%##s) already exists!",           c, b->q.qname.c);
+       if (b)
+               {
+               for (qptr = b->qlist; qptr; qptr = qptr->next)
+                       LogMsg("%5d: Browser(%##s) already exists!",          c, qptr->q.qname.c);
+               }
        if (l) LogMsg("%5d: Resolver(%##s) already exists!",          c, l->i.name.c);
-       if (r) LogMsg("%5d: Registration(%##s) already exists!",      c, r->s.RR_SRV.resrec.name.c);
+       if (r) LogMsg("%5d: Registration(%##s) already exists!",      c, r->ls.RR_SRV.resrec.name.c);
        return(e || b || l || r);
        }
 
@@ -579,7 +768,7 @@ mDNSlocal void ClientDeathCallback(CFMachPortRef unusedport, void *voidmsg, CFIn
                AbortClient(deathMessage->not_port, NULL);
 
                /* Deallocate the send right that came in the dead name notification */
-               mach_port_destroy( mach_task_self(), deathMessage->not_port );
+               mach_port_destroy(mach_task_self(), deathMessage->not_port);
                }
        }
 
@@ -661,8 +850,8 @@ mDNSexport kern_return_t provide_DNSServiceDomainEnumerationCreate_rpc(mach_port
                { AbortBlockedClient(x->ClientMachPort, "local enumeration", x); return(mStatus_UnknownErr); }
 
        // Do the operation
-       err           = mDNS_GetDomains(&mDNSStorage, &x->dom, dt1, mDNSInterface_Any, FoundDomain, x);
-       if (!err) err = mDNS_GetDomains(&mDNSStorage, &x->def, dt2, mDNSInterface_Any, FoundDomain, x);
+       err           = mDNS_GetDomains(&mDNSStorage, &x->dom, dt1, NULL, mDNSInterface_LocalOnly, FoundDomain, x);
+       if (!err) err = mDNS_GetDomains(&mDNSStorage, &x->def, dt2, NULL, mDNSInterface_LocalOnly, FoundDomain, x);
        if (err) { AbortClient(client, x); errormsg = "mDNS_GetDomains"; goto fail; }
        
        // Succeeded: Wrap up and return
@@ -717,43 +906,70 @@ mDNSexport kern_return_t provide_DNSServiceBrowserCreate_rpc(mach_port_t unuseds
        (void)unusedserver;             // Unused
        mStatus err = mStatus_NoError;
        const char *errormsg = "Unknown";
+       DNameListElem *SearchDomains = NULL, *sdPtr;
+       DNSServiceBrowserQuestion *qptr;
+       
        if (client == (mach_port_t)-1)      { err = mStatus_Invalid; errormsg = "Client id -1 invalid";     goto fail; }
        if (CheckForExistingClient(client)) { err = mStatus_Invalid; errormsg = "Client id already in use"; goto fail; }
 
        // Check other parameters
        domainname t, d;
-       t.c[0] = 0;
-       mDNSs32 NumSubTypes = CountSubTypes(regtype);
-       if (NumSubTypes < 0 || NumSubTypes > 1) { errormsg = "Bad Service SubType"; goto badparam; }
-       if (NumSubTypes == 1 && !AppendDNSNameString(&t, regtype + strlen(regtype) + 1))
-                                               { errormsg = "Bad Service SubType"; goto badparam; }
-       if (!regtype[0] || !AppendDNSNameString(&t, regtype))                  { errormsg = "Illegal regtype"; goto badparam; }
-       if (!MakeDomainNameFromDNSNameString(&d, *domain ? domain : "local.")) { errormsg = "Illegal domain";  goto badparam; }
+       if (!regtype[0] || !MakeDomainNameFromDNSNameString(&t, regtype))      { errormsg = "Illegal regtype"; goto badparam; }
 
        // Allocate memory, and handle failure
        DNSServiceBrowser *x = mallocL("DNSServiceBrowser", sizeof(*x));
        if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; }
-
+       
        // Set up object, and link into list
        x->ClientMachPort = client;
        x->results = NULL;
        x->lastsuccess = 0;
+       x->qlist = NULL;        
        x->next = DNSServiceBrowserList;
        DNSServiceBrowserList = x;
 
-       // Do the operation
-       LogOperation("%5d: DNSServiceBrowse(%##s%##s) START", client, t.c, d.c);
-       err = mDNS_StartBrowse(&mDNSStorage, &x->q, &t, &d, mDNSInterface_Any, FoundInstance, x);
-       if (err) { AbortClient(client, x); errormsg = "mDNS_StartBrowse"; goto fail; }
-
+       //!!!KRS browse locally for ichat
+       if (!domain[0] && (!strcmp(regtype, "_ichat._tcp.") || !strcmp(regtype, "_presence._tcp.")))
+               domain = "local.";
+       
+       if (domain[0])
+               {
+               // Start browser for an explicit domain
+               x->qlist = mallocL("DNSServiceBrowserQuestion", sizeof(DNSServiceBrowserQuestion));
+               x->qlist->next = NULL;
+               if (!x->qlist)  { err = mStatus_UnknownErr; AbortClient(client, x); errormsg = "malloc"; goto fail; }
+               
+               if (!MakeDomainNameFromDNSNameString(&d, domain)) { errormsg = "Illegal domain";  goto badparam; }
+               LogOperation("%5d: DNSServiceBrowse(%##s%##s) START", client, t.c, d.c);
+               err = mDNS_StartBrowse(&mDNSStorage, &x->qlist->q, &t, &d, mDNSInterface_Any, FoundInstance, x);
+               if (err) { AbortClient(client, x); errormsg = "mDNS_StartBrowse"; goto fail; }
+               }
+       else
+               {
+               // Start browser on all domains
+               SearchDomains = mDNSPlatformGetSearchDomainList();
+               if (!SearchDomains) { AbortClient(client, x); errormsg = "GetSearchDomainList"; goto fail; }
+               for (sdPtr = SearchDomains; sdPtr; sdPtr = sdPtr->next)
+                       {
+                       qptr = mallocL("DNSServiceBrowserQuestion", sizeof(DNSServiceBrowserQuestion));
+                       if (!qptr)  { err = mStatus_UnknownErr; AbortClient(client, x); errormsg = "malloc"; goto fail; }
+                       qptr->next = x->qlist;
+                       x->qlist = qptr;
+                       LogOperation("%5d: DNSServiceBrowse(%##s%##s) START", client, t.c, sdPtr->name.c);
+                       err = mDNS_StartBrowse(&mDNSStorage, &qptr->q, &t, &sdPtr->name, mDNSInterface_Any, FoundInstance, x);
+                       if (err) { AbortClient(client, x); errormsg = "mDNS_StartBrowse"; goto fail; }                  
+                       }               
+               }
        // Succeeded: Wrap up and return
        EnableDeathNotificationForClient(client, x);
+       mDNS_FreeDNameList(SearchDomains);
        return(mStatus_NoError);
-
-badparam:
+       
+       badparam:
        err = mStatus_BadParamErr;
 fail:
        LogMsg("%5d: DNSServiceBrowse(\"%s\", \"%s\") failed: %s (%ld)", client, regtype, domain, errormsg, err);
+       if (SearchDomains) mDNS_FreeDNameList(SearchDomains);
        return(err);
        }
 
@@ -834,8 +1050,8 @@ mDNSlocal void FoundInstanceInfo(mDNS *const m, ServiceInfoQuery *query)
                }
        cstring[i-1] = 0;               // Put the terminating NULL on the end
        
-       LogOperation("%5d: DNSServiceResolver(%##s) -> %#a:%d", x->ClientMachPort,
-               x->i.name.c, &query->info->ip, (int)query->info->port.b[0] << 8 | query->info->port.b[1]);
+       LogOperation("%5d: DNSServiceResolver(%##s) -> %#a:%u", x->ClientMachPort,
+               x->i.name.c, &query->info->ip, mDNSVal16(query->info->port));
        status = DNSServiceResolverReply_rpc(x->ClientMachPort,
                (char*)&interface, (char*)&address, cstring, 0, MDNS_MM_TIMEOUT);
        if (status == MACH_SEND_TIMED_OUT)
@@ -857,7 +1073,7 @@ mDNSexport kern_return_t provide_DNSServiceResolverResolve_rpc(mach_port_t unuse
        domainname t, d, srv;
        if (!name[0]    || !MakeDomainLabelFromLiteralString(&n, name))        { errormsg = "Bad Instance Name"; goto badparam; }
        if (!regtype[0] || !MakeDomainNameFromDNSNameString(&t, regtype))      { errormsg = "Bad Service Type";  goto badparam; }
-       if (!MakeDomainNameFromDNSNameString(&d, *domain ? domain : "local.")) { errormsg = "Bad Domain";        goto badparam; }
+       if (!domain[0]  || !MakeDomainNameFromDNSNameString(&d, domain))       { errormsg = "Bad Domain";        goto badparam; }
        if (!ConstructServiceName(&srv, &n, &t, &d))                           { errormsg = "Bad Name";          goto badparam; }
 
        // Allocate memory, and handle failure
@@ -885,7 +1101,7 @@ mDNSexport kern_return_t provide_DNSServiceResolverResolve_rpc(mach_port_t unuse
        EnableDeathNotificationForClient(client, x);
        return(mStatus_NoError);
 
-badparam:
+badparam: 
        err = mStatus_BadParamErr;
 fail:
        LogMsg("%5d: DNSServiceResolve(\"%s\", \"%s\", \"%s\") failed: %s (%ld)", client, name, regtype, domain, errormsg, err);
@@ -902,7 +1118,7 @@ mDNSlocal void RegCallback(mDNS *const m, ServiceRecordSet *const sr, mStatus re
        if (result == mStatus_NoError)
                {
                kern_return_t status;
-               LogOperation("%5d: DNSServiceRegistration(%##s) Name Registered", x->ClientMachPort, sr->RR_SRV.resrec.name.c);
+               LogOperation("%5d: DNSServiceRegistration(%##s, %u) Name Registered", x->ClientMachPort, sr->RR_SRV.resrec.name.c, SRS_PORT(sr));
                status = DNSServiceRegistrationReply_rpc(x->ClientMachPort, result, MDNS_MM_TIMEOUT);
                if (status == MACH_SEND_TIMED_OUT)
                        AbortBlockedClient(x->ClientMachPort, "registration success", x);
@@ -910,7 +1126,7 @@ mDNSlocal void RegCallback(mDNS *const m, ServiceRecordSet *const sr, mStatus re
 
        else if (result == mStatus_NameConflict)
                {
-               LogOperation("%5d: DNSServiceRegistration(%##s) Name Conflict", x->ClientMachPort, sr->RR_SRV.resrec.name.c);
+               LogOperation("%5d: DNSServiceRegistration(%##s, %u) Name Conflict", x->ClientMachPort, sr->RR_SRV.resrec.name.c, SRS_PORT(sr));
                // Note: By the time we get the mStatus_NameConflict message, the service is already deregistered
                // and the memory is free, so we don't have to wait for an mStatus_MemFree message as well.
                if (x->autoname)
@@ -925,18 +1141,22 @@ mDNSlocal void RegCallback(mDNS *const m, ServiceRecordSet *const sr, mStatus re
                                AbortBlockedClient(x->ClientMachPort, "registration conflict", x);
                        }
                }
-
+       
        else if (result == mStatus_MemFree)
                {
-               if (x->autorename)
+               mDNSBool *autorename = (sr == &x->ls ? &x->autorenameLS : &x->autorenameGS); 
+               if (*autorename)
                        {
                        debugf("RegCallback renaming %#s to %#s", x->name.c, mDNSStorage.nicelabel.c);
-                       x->autorename = mDNSfalse;
+                       *autorename = mDNSfalse;
                        x->name = mDNSStorage.nicelabel;
-                       mDNS_RenameAndReregisterService(m, &x->s, &x->name);
+                       mDNS_RenameAndReregisterService(m, sr, &x->name);
                        }
                else
                        {
+                       // SANITY CHECK: Should only get mStatus_MemFree as a result of calling mDNS_DeregisterService()
+                       // and should only get it with x->autorename false if we've already removed the record from our
+                       // list, but this check is just to make sure...
                        DNSServiceRegistration **r = &DNSServiceRegistrationList;
                        while (*r && *r != x) r = &(*r)->next;
                        if (*r)
@@ -944,14 +1164,18 @@ mDNSlocal void RegCallback(mDNS *const m, ServiceRecordSet *const sr, mStatus re
                                LogMsg("RegCallback: %##s Still in DNSServiceRegistration list; removing now", sr->RR_SRV.resrec.name.c);
                                *r = (*r)->next;
                                }
-                       LogOperation("%5d: DNSServiceRegistration(%##s) Memory Free", x->ClientMachPort, sr->RR_SRV.resrec.name.c);
-                       FreeDNSServiceRegistration(x);
+                       // END SANITY CHECK
+                       LogOperation("%5d: DNSServiceRegistration(%##s, %u) Memory Free", x->ClientMachPort, sr->RR_SRV.resrec.name.c, SRS_PORT(sr));
+                       FreeDNSServiceRegistration(sr);
                        }
                }
        
        else
-               LogMsg("%5d: DNSServiceRegistration(%##s) Unknown Result %ld",
-                       x->ClientMachPort, sr->RR_SRV.resrec.name.c, result);
+               {
+               LogMsg("%5d: DNSServiceRegistration(%##s, %u) Unknown Result %ld",
+                       x->ClientMachPort, sr->RR_SRV.resrec.name.c, SRS_PORT(sr), result);
+               if (sr == x->gs) { freeL("RegCallback - ServiceRecordSet", x->gs); x->gs = NULL; }
+               }
        }
 
 mDNSlocal void CheckForDuplicateRegistrations(DNSServiceRegistration *x, domainname *srv, mDNSIPPort port)
@@ -965,23 +1189,35 @@ mDNSlocal void CheckForDuplicateRegistrations(DNSServiceRegistration *x, domainn
                        count++;
 
        if (count > 1)
-               LogMsg("%5d: Client application registered %d identical instances of service %##s port %d.",
-                       x->ClientMachPort, count, srv->c, (int)port.b[0] << 8 | port.b[1]);
+               LogMsg("%5d: Client application registered %d identical instances of service %##s port %u.",
+                       x->ClientMachPort, count, srv->c, mDNSVal16(port));
        }
 
-mDNSexport kern_return_t provide_DNSServiceRegistrationCreate_rpc(mach_port_t unusedserver, mach_port_t client,
-       DNSCString name, DNSCString regtype, DNSCString domain, int notAnIntPort, DNSCString txtRecord)
+// Pass NULL for x to allocate the structure (for local service).  Call again w/ initialized x to add a global service.
+mDNSlocal DNSServiceRegistration *RegisterService(mach_port_t client, DNSCString name, DNSCString regtype, DNSCString domain,
+                                                                                                 int notAnIntPort, DNSCString txtRecord, DNSServiceRegistration *x)
        {
-       // Check client parameter
-       (void)unusedserver;             // Unused
+       ServiceRecordSet *srs = NULL;  // record set to use in registration operation
        mStatus err = mStatus_NoError;
        const char *errormsg = "Unknown";
-       if (client == (mach_port_t)-1)      { err = mStatus_Invalid; errormsg = "Client id -1 invalid";     goto fail; }
-       if (CheckForExistingClient(client)) { err = mStatus_Invalid; errormsg = "Client id already in use"; goto fail; }
-
-       // Check for sub-types after the service type
-       mDNSs32 NumSubTypes = CountSubTypes(regtype);
-       if (NumSubTypes < 0) { errormsg = "Bad Service SubType"; goto badparam; }
+       
+    // Check for sub-types after the service type
+       AuthRecord *SubTypes = mDNSNULL;
+       mDNSu32 i, NumSubTypes = 0;
+       char *comma = regtype;
+       while (*comma && *comma != ',') comma++;
+       if (*comma)                                     // If we found a comma...
+               {
+               *comma = 0;                             // Overwrite the first comma with a nul
+               char *p = comma + 1;    // Start scanning from the next character
+               while (*p)
+                       {
+                       if ( !(*p && *p != ',')) { errormsg = "Bad Service SubType";  goto badparam; }
+                       while (*p && *p != ',') p++;
+                       if (*p) *p++ = 0;
+                       NumSubTypes++;
+                       }
+               }
 
        // Check other parameters
        domainlabel n;
@@ -989,8 +1225,9 @@ mDNSexport kern_return_t provide_DNSServiceRegistrationCreate_rpc(mach_port_t un
        domainname srv;
        if (!name[0]) n = mDNSStorage.nicelabel;
        else if (!MakeDomainLabelFromLiteralString(&n, name))                  { errormsg = "Bad Instance Name"; goto badparam; }
-       if (!regtype[0] || !MakeDomainNameFromDNSNameString(&t, regtype))      { errormsg = "Bad Service Type";  goto badparam; }
-       if (!MakeDomainNameFromDNSNameString(&d, *domain ? domain : "local.")) { errormsg = "Bad Domain";        goto badparam; }
+       if (!regtype[0] || !MakeDomainNameFromDNSNameString(&t, regtype))      { errormsg = "Bad Service Type";  goto badparam; }       
+       
+       if (!MakeDomainNameFromDNSNameString(&d, domain))                      { errormsg = "Bad Domain";        goto badparam; }
        if (!ConstructServiceName(&srv, &n, &t, &d))                           { errormsg = "Bad Name";          goto badparam; }
 
        mDNSIPPort port;
@@ -1028,50 +1265,100 @@ mDNSexport kern_return_t provide_DNSServiceRegistrationCreate_rpc(mach_port_t un
                size = data_len;
 
        // Allocate memory, and handle failure
-       DNSServiceRegistration *x = mallocL("DNSServiceRegistration", sizeof(*x) - sizeof(RDataBody) + size);
-       if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; }
-
-       AuthRecord *SubTypes = AllocateSubTypes(NumSubTypes, regtype);
-       if (NumSubTypes && !SubTypes)
-               { freeL("DNSServiceRegistration", x); err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; }
-
-       // Set up object, and link into list
-       x->ClientMachPort = client;
-       x->autoname = (!name[0]);
-       x->autorename = mDNSfalse;
-       x->name = n;
-       x->next = DNSServiceRegistrationList;
-       DNSServiceRegistrationList = x;
+       if (!x)
+               {
+               x = mallocL("DNSServiceRegistration", sizeof(*x) - sizeof(RDataBody) + size);
+               if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; }               
+               bzero(x, sizeof(*x) - sizeof(RDataBody) + size);
+               // Set up object, and link into list
+               x->ClientMachPort = client;
+               x->autoname = (!name[0]);
+               x->name = n;
+               x->next = DNSServiceRegistrationList;
+               DNSServiceRegistrationList = x;         
+               srs = &x->ls; 
+               }
+       else
+               {
+               x->gs = mallocL("DNSServiceRegistration GlobalService", sizeof(ServiceRecordSet) - sizeof(RDataBody) + size);
+               if (!x->gs) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; } 
+               srs = x->gs;
+               bzero(srs, sizeof(ServiceRecordSet) - sizeof(RDataBody) + size);
+               }
+       
+       if (NumSubTypes)
+               {
+               SubTypes = mallocL("ServiceSubTypes", NumSubTypes * sizeof(AuthRecord));
+               if (!SubTypes) { freeL("DNSServiceRegistration", x); err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; }
+               for (i = 0; i < NumSubTypes; i++)
+                       {
+                       comma++;                                // Advance over the nul character
+                       MakeDomainNameFromDNSNameString(&SubTypes[i].resrec.name, comma);
+                       while (*comma) comma++; // Advance comma to point to the next terminating nul
+                       }
+               }
 
        // Do the operation
-       LogOperation("%5d: DNSServiceRegistration(\"%s\", \"%s\", \"%s\") START", x->ClientMachPort, name, regtype, domain);
+       LogOperation("%5d: DNSServiceRegistration(\"%s\", \"%s\", \"%s\", %u) START",
+               x->ClientMachPort, name, regtype, domain, mDNSVal16(port));
        // Some clients use mDNS for lightweight copy protection, registering a pseudo-service with
        // a port number of zero. When two instances of the protected client are allowed to run on one
        // machine, we don't want to see misleading "Bogus client" messages in syslog and the console.
        if (port.NotAnInteger) CheckForDuplicateRegistrations(x, &srv, port);
 
-       err = mDNS_RegisterService(&mDNSStorage, &x->s,
-               &x->name, &t, &d,               // Name, type, domain
+       err = mDNS_RegisterService(&mDNSStorage, srs,
+               &x->name, &t, &d,       // Name, type, domain
                mDNSNULL, port,                 // Host and port
                txtinfo, data_len,              // TXT data, length
                SubTypes, NumSubTypes,  // Subtypes
                mDNSInterface_Any,              // Interface ID
                RegCallback, x);                // Callback and context
 
-       if (err) { AbortClient(client, x); errormsg = "mDNS_RegisterService"; goto fail; }
+       if (err)
+               {
+               if (srs == &x->ls) AbortClient(client, x);  // don't abort client for global service
+               else FreeDNSServiceRegistration(x->gs);  
+               errormsg = "mDNS_RegisterService";
+               goto fail; 
+               }
+       return x;
+       
+badtxt:
+       LogMsg("%5d: TXT record: %.100s...", client, txtRecord);
+badparam:
+       err = mStatus_BadParamErr;
+fail:
+       LogMsg("%5d: DNSServiceRegister(\"%s\", \"%s\", \"%s\", %d) failed: %s (%ld)",
+                  client, name, regtype, domain, notAnIntPort, errormsg, err);
+       return NULL;
+       }
 
+mDNSexport kern_return_t provide_DNSServiceRegistrationCreate_rpc(mach_port_t unusedserver, mach_port_t client,
+       DNSCString name, DNSCString regtype, DNSCString domain, int notAnIntPort, DNSCString txtRecord)
+       {
+       // Check client parameter
+       (void)unusedserver;             // Unused
+       mStatus err = mStatus_NoError;
+       const char *errormsg = "Unknown";
+       DNSServiceRegistration *x = NULL;
+       if (client == (mach_port_t)-1)      { err = mStatus_Invalid; errormsg = "Client id -1 invalid";     goto fail; }
+       if (CheckForExistingClient(client)) { err = mStatus_Invalid; errormsg = "Client id already in use"; goto fail; }
+
+       x = RegisterService(client, name, regtype, *domain ? domain : "local.", notAnIntPort, txtRecord, NULL);
+       if (!x) { err = mStatus_UnknownErr;  goto fail; } 
+
+    //!!!KRS if we got a dynamic reg domain from the config file, use it for default (except for iChat)
+       if (!*domain && mDNSStorage.uDNS_info.ServiceRegDomain[0] && strcmp(regtype, "_presence._tcp.") && strcmp(regtype, "_ichat._tcp."))
+               x = RegisterService(client, name, regtype,  mDNSStorage.uDNS_info.ServiceRegDomain, notAnIntPort, txtRecord, x);                
+       
        // Succeeded: Wrap up and return
        EnableDeathNotificationForClient(client, x);
        return(mStatus_NoError);
 
-badtxt:
-       LogMsg("%5d: TXT record: %.100s...", client, txtRecord);
-badparam:
-       err = mStatus_BadParamErr;
 fail:
        LogMsg("%5d: DNSServiceRegister(\"%s\", \"%s\", \"%s\", %d) failed: %s (%ld)",
-               client, name, regtype, domain, notAnIntPort, errormsg, err);
-       return(err);
+                  client, name, regtype, domain, notAnIntPort, errormsg, err);
+       return mStatus_UnknownErr;
        }
        
 mDNSlocal void mDNS_StatusCallback(mDNS *const m, mStatus result)
@@ -1084,8 +1371,9 @@ mDNSlocal void mDNS_StatusCallback(mDNS *const m, mStatus result)
                        if (r->autoname && !SameDomainLabel(r->name.c, mDNSStorage.nicelabel.c))
                                {
                                debugf("NetworkChanged renaming %#s to %#s", r->name.c, mDNSStorage.nicelabel.c);
-                               r->autorename = mDNStrue;
-                               mDNS_DeregisterService(&mDNSStorage, &r->s);
+                               r->autorenameLS = mDNStrue;
+                               mDNS_DeregisterService(&mDNSStorage, &r->ls);
+                               if (r->gs) { mDNS_DeregisterService(&mDNSStorage, r->gs); r->autorenameGS = mDNStrue; }
                                }
                udsserver_handle_configchange();
                }
@@ -1101,22 +1389,17 @@ mDNSlocal void mDNS_StatusCallback(mDNS *const m, mStatus result)
 //*************************************************************************************************************
 // Add / Update / Remove records from existing Registration
 
-mDNSexport kern_return_t provide_DNSServiceRegistrationAddRecord_rpc(mach_port_t unusedserver, mach_port_t client,
-       int type, const char *data, mach_msg_type_number_t data_len, uint32_t ttl, natural_t *reference)
+
+mDNSlocal ExtraResourceRecord *AddExtraRecord(DNSServiceRegistration *x, ServiceRecordSet *srs, mach_port_t client,
+                                                                                         int type, const char *data, mach_msg_type_number_t data_len, uint32_t ttl)
        {
-       // Check client parameter
-       (void)unusedserver;             // Unused
        mStatus err = mStatus_NoError;
        const char *errormsg = "Unknown";
        domainname *name = (domainname *)"";
-       if (client == (mach_port_t)-1) { err = mStatus_Invalid;         errormsg = "Client id -1 invalid"; goto fail; }
-       DNSServiceRegistration *x = DNSServiceRegistrationList;
-       while (x && x->ClientMachPort != client) x = x->next;
-       if (!x)                        { err = mStatus_BadReferenceErr; errormsg = "No such client";       goto fail; }
-       name = &x->s.RR_SRV.resrec.name;
+       name = &srs->RR_SRV.resrec.name;
 
-       // Check other parameters
-       if (data_len > 8192) { err = mStatus_BadParamErr; errormsg = "data_len > 8K"; goto fail; }
+       (void)x;  // unused
+       
        unsigned int size = sizeof(RDataBody);
        if (size < data_len)
                size = data_len;
@@ -1133,56 +1416,79 @@ mDNSexport kern_return_t provide_DNSServiceRegistrationAddRecord_rpc(mach_port_t
        
        // Do the operation
        LogOperation("%5d: DNSServiceRegistrationAddRecord(%##s, type %d, length %d) REF %p",
-               client, x->s.RR_SRV.resrec.name.c, type, data_len, extra);
-       err = mDNS_AddRecordToService(&mDNSStorage, &x->s, extra, &extra->r.rdatastorage, ttl);
-       *reference = (natural_t)extra;
-       if (err) { errormsg = "mDNS_AddRecordToService"; goto fail; }
+               client, srs->RR_SRV.resrec.name.c, type, data_len, extra);
+       err = mDNS_AddRecordToService(&mDNSStorage, srs, extra, &extra->r.rdatastorage, ttl);
+
+       if (err)
+               {
+               freeL("Extra Resource Record", extra);
+               errormsg = "mDNS_AddRecordToService";
+               goto fail;
+               }
        
-       // Succeeded: Wrap up and return
-       return(mStatus_NoError);
+       return extra;
        
 fail:
        LogMsg("%5d: DNSServiceRegistrationAddRecord(%##s, type %d, length %d) failed: %s (%ld)", client, name->c, type, data_len, errormsg, err);
-       return(err);
+       return NULL;
        }
 
-mDNSlocal void UpdateCallback(mDNS *const m, AuthRecord *const rr, RData *OldRData)
-       {
-       (void)m;                // Unused
-       if (OldRData != &rr->rdatastorage)
-               freeL("Old RData", OldRData);
-       }
 
-mDNSexport kern_return_t provide_DNSServiceRegistrationUpdateRecord_rpc(mach_port_t unusedserver, mach_port_t client,
-       natural_t reference, const char *data, mach_msg_type_number_t data_len, uint32_t ttl)
+mDNSexport kern_return_t provide_DNSServiceRegistrationAddRecord_rpc(mach_port_t unusedserver, mach_port_t client,
+       int type, const char *data, mach_msg_type_number_t data_len, uint32_t ttl, natural_t *reference)
        {
        // Check client parameter
        (void)unusedserver;             // Unused
        mStatus err = mStatus_NoError;
        const char *errormsg = "Unknown";
-       domainname *name = (domainname *)"";
        if (client == (mach_port_t)-1) { err = mStatus_Invalid;         errormsg = "Client id -1 invalid"; goto fail; }
        DNSServiceRegistration *x = DNSServiceRegistrationList;
        while (x && x->ClientMachPort != client) x = x->next;
        if (!x)                        { err = mStatus_BadReferenceErr; errormsg = "No such client";       goto fail; }
-       name = &x->s.RR_SRV.resrec.name;
 
        // Check other parameters
        if (data_len > 8192) { err = mStatus_BadParamErr; errormsg = "data_len > 8K"; goto fail; }
+
+       ExtraRecordRef *ref = mallocL("ExtraRecordRef", sizeof(ExtraRecordRef));
+       if (!ref) { LogMsg("ERROR: malloc"); return mStatus_NoMemoryErr; }
+
+       ref->localRef = AddExtraRecord(x, &x->ls, client, type, data, data_len, ttl);
+       if (!ref->localRef) { freeL("ExtraRecordRef", ref); *reference = (natural_t)NULL; return mStatus_UnknownErr; }
+
+       if (x->gs) ref->globalRef = AddExtraRecord(x, x->gs, client, type, data, data_len, ttl);  // return success even if global case fails
+       else ref->globalRef = NULL;
+       
+       // Succeeded: Wrap up and return
+       ref->next = x->ExtraRefList;
+       x->ExtraRefList = ref;
+       *reference = (natural_t)ref;
+       return mStatus_NoError;
+
+fail:
+       LogMsg("%5d: DNSServiceRegistrationAddRecord(%##s, type %d, length %d) failed: %s (%ld)", client, x->name.c, type, data_len, errormsg, err);
+       return mStatus_UnknownErr;
+       }
+
+mDNSlocal void UpdateCallback(mDNS *const m, AuthRecord *const rr, RData *OldRData)
+       {
+       (void)m;                // Unused
+       if (OldRData != &rr->rdatastorage)
+               freeL("Old RData", OldRData);
+       }
+
+mDNSlocal mStatus UpdateRecord(ServiceRecordSet *srs, mach_port_t client, AuthRecord *rr, const char *data, mach_msg_type_number_t data_len, uint32_t ttl)
+       {
+    // Check client parameter
+       mStatus err = mStatus_NoError;
+       const char *errormsg = "Unknown";
+       domainname *name = (domainname *)"";
+
+       name = &srs->RR_SRV.resrec.name;
+
        unsigned int size = sizeof(RDataBody);
-       if (size < data_len)
+    if (size < data_len)
                size = data_len;
 
-       // Find the record we're updating. NULL reference means update the primary TXT record
-       AuthRecord *rr = &x->s.RR_TXT;
-       if (reference)  // Scan our list to make sure we're updating a valid record that was previously added
-               {
-               ExtraResourceRecord *e = x->s.Extras;
-               while (e && e != (ExtraResourceRecord*)reference) e = e->next;
-               if (!e) { err = mStatus_BadReferenceErr; errormsg = "No such record"; goto fail; }
-               rr = &e->r;
-               }
-
        // Allocate memory, and handle failure
        RData *newrdata = mallocL("RData", sizeof(*newrdata) - sizeof(RDataBody) + size);
        if (!newrdata) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; }
@@ -1192,16 +1498,89 @@ mDNSexport kern_return_t provide_DNSServiceRegistrationUpdateRecord_rpc(mach_por
        memcpy(&newrdata->u, data, data_len);
        
        // Do the operation
-       LogOperation("%5d: DNSServiceRegistrationUpdateRecord(%##s, %X, new length %d)",
-               client, x->s.RR_SRV.resrec.name.c, reference, data_len);
+       LogOperation("%5d: DNSServiceRegistrationUpdateRecord(%##s, new length %d)",
+               client, srs->RR_SRV.resrec.name.c, data_len);
+
        err = mDNS_Update(&mDNSStorage, rr, ttl, data_len, newrdata, UpdateCallback);
-       if (err) { errormsg = "mDNS_Update"; goto fail; }
+       if (err)
+               {
+               errormsg = "mDNS_Update";
+               freeL("RData", newrdata);
+               return err;
+               }   
+       return(mStatus_NoError);
+
+fail:
+       LogMsg("%5d: DNSServiceRegistrationUpdateRecord(%##s, %d) failed: %s (%ld)", client, name->c, data_len, errormsg, err);
+       return(err);
+       }       
+
+
+mDNSexport kern_return_t provide_DNSServiceRegistrationUpdateRecord_rpc(mach_port_t unusedserver, mach_port_t client,
+               natural_t reference, const char *data, mach_msg_type_number_t data_len, uint32_t ttl)
+       {
+    // Check client parameter
+       mStatus err = mStatus_NoError;
+       const char *errormsg = "Unknown";
+       domainname *name = (domainname *)"";
+       AuthRecord *gRR, *lRR;
+
+       (void)unusedserver;  // unused
+    if (client == (mach_port_t)-1) { err = mStatus_Invalid;         errormsg = "Client id -1 invalid"; goto fail; }
+       DNSServiceRegistration *x = DNSServiceRegistrationList;
+       while (x && x->ClientMachPort != client) x = x->next;
+       if (!x)                        { err = mStatus_BadReferenceErr; errormsg = "No such client";       goto fail; }
+
+       // Check other parameters
+       if (data_len > 8192) { err = mStatus_BadParamErr; errormsg = "data_len > 8K"; goto fail; }
+
+       // Find the record we're updating. NULL reference means update the primary TXT record
+       if (!reference)
+               {
+               lRR = &x->ls.RR_TXT;
+               gRR = x->gs ? &x->gs->RR_TXT : NULL;
+               }
+       else
+               {
+               ExtraRecordRef *ref;
+               for (ref = x->ExtraRefList; ref; ref= ref->next)                        
+                       if (ref == (ExtraRecordRef *)reference) break;
+               if (!ref) { err = mStatus_BadReferenceErr; errormsg = "No such record"; goto fail; }
+               lRR = &ref->localRef->r;
+               gRR = ref->globalRef ? &ref->globalRef->r : NULL;
+               }
+
+       err = UpdateRecord(&x->ls, client, lRR, data, data_len, ttl);
+       if (err) goto fail;
+
+       if (gRR) UpdateRecord(x->gs, client, gRR, data, data_len, ttl); // don't return error if global fails
+       return mStatus_NoError;
+       
+fail:
+       LogMsg("%5d: DNSServiceRegistrationUpdateRecord(%##s, %X, %d) failed: %s (%ld)", client, name->c, reference, data_len, errormsg, err);
+       return(err);
+       }
+
+mDNSlocal mStatus RemoveRecord(ServiceRecordSet *srs, ExtraResourceRecord *extra, mach_port_t client)
+       {
+       domainname *name = &srs->RR_SRV.resrec.name;
+       mStatus err = mStatus_NoError;
+       const char *errormsg = "Unknown";
        
+       // Do the operation
+       LogOperation("%5d: DNSServiceRegistrationRemoveRecord(%##s)", client, srs->RR_SRV.resrec.name.c);
+
+       err = mDNS_RemoveRecordFromService(&mDNSStorage, srs, extra);
+       if (err) { errormsg = "mDNS_RemoveRecordFromService (No such record)"; goto fail; }
+
        // Succeeded: Wrap up and return
+       if (extra->r.resrec.rdata != &extra->r.rdatastorage)
+               freeL("Extra RData", extra->r.resrec.rdata);
+       freeL("ExtraResourceRecord", extra);
        return(mStatus_NoError);
 
 fail:
-       LogMsg("%5d: DNSServiceRegistrationUpdateRecord(%##s, %X, %d) failed: %s (%ld)", client, name->c, reference, data_len, errormsg, err);
+       LogMsg("%5d: DNSServiceRegistrationRemoveRecord(%##s, %X) failed: %s", client, name->c, errormsg, err);
        return(err);
        }
 
@@ -1212,27 +1591,33 @@ mDNSexport kern_return_t provide_DNSServiceRegistrationRemoveRecord_rpc(mach_por
        (void)unusedserver;             // Unused
        mStatus err = mStatus_NoError;
        const char *errormsg = "Unknown";
-       domainname *name = (domainname *)"";
+       ExtraRecordRef *ref, *prev = NULL;
        if (client == (mach_port_t)-1) { err = mStatus_Invalid;         errormsg = "Client id -1 invalid"; goto fail; }
        DNSServiceRegistration *x = DNSServiceRegistrationList;
        while (x && x->ClientMachPort != client) x = x->next;
        if (!x)                        { err = mStatus_BadReferenceErr; errormsg = "No such client";       goto fail; }
-       name = &x->s.RR_SRV.resrec.name;
 
-       // Do the operation
-       LogOperation("%5d: DNSServiceRegistrationRemoveRecord(%##s, %X)", client, x->s.RR_SRV.resrec.name.c, reference);
-       ExtraResourceRecord *extra = (ExtraResourceRecord*)reference;
-       err = mDNS_RemoveRecordFromService(&mDNSStorage, &x->s, extra);
-       if (err) { errormsg = "mDNS_RemoveRecordFromService (No such record)"; goto fail; }
+       ref = x->ExtraRefList;
+       while (ref)
+               {
+               if (ref == (ExtraRecordRef *)ref) break;
+               prev = ref;
+          ref = ref->next;
+               }
+       
+       if (!ref) { err = mStatus_BadReferenceErr; errormsg = "No such reference"; goto fail; }
+       err = RemoveRecord(&x->ls, ref->localRef, client);
+       if (x->gs && ref->globalRef) RemoveRecord(x->gs, ref->globalRef, client);  // don't return error if this fails
 
-       // Succeeded: Wrap up and return
-       if (extra->r.resrec.rdata != &extra->r.rdatastorage)
-               freeL("Extra RData", extra->r.resrec.rdata);
-       freeL("ExtraResourceRecord", extra);
-       return(mStatus_NoError);
+       // delete the ref struct
+       if (prev) prev->next = ref->next;
+       else x->ExtraRefList = ref->next;
+       ref->next = NULL;
+       freeL("ExtraRecordRef", ref);
+       return err;
 
 fail:
-       LogMsg("%5d: DNSServiceRegistrationRemoveRecord(%##s, %X) failed: %s (%ld)", client, name->c, reference, errormsg, err);
+       LogMsg("%5d: DNSServiceRegistrationRemoveRecord(%X) failed: %s (%ld)", client, reference, errormsg, err);
        return(err);
        }
 
@@ -1400,10 +1785,10 @@ mDNSlocal void ExitCallback(CFMachPortRef port, void *msg, CFIndex size, void *i
        debugf("ExitCallback: RR Cache now using %d records, %d active", mDNSStorage.rrcache_used, rrcache_active);
 */
 
-       LogMsg("%s stopping", mDNSResponderVersionString);
+       LogMsgIdent(mDNSResponderVersionString, "stopping");
 
        debugf("ExitCallback: destroyBootstrapService");
-       if (!debug_mode)
+       if (!mDNS_DebugMode)
                destroyBootstrapService();
 
        debugf("ExitCallback: Aborting MIG clients");
@@ -1418,9 +1803,7 @@ mDNSlocal void ExitCallback(CFMachPortRef port, void *msg, CFIndex size, void *i
 
        debugf("ExitCallback: mDNS_Close");
        mDNS_Close(&mDNSStorage);
-#if ENABLE_UDS
        if (udsserver_exit() < 0) LogMsg("ExitCallback: udsserver_exit failed");
-#endif
        exit(0);
        }
 
@@ -1450,42 +1833,74 @@ mDNSlocal void INFOCallback(CFMachPortRef port, void *msg, CFIndex size, void *i
        DNSServiceBrowser           *b;
        DNSServiceResolver          *l;
        DNSServiceRegistration      *r;
-       mDNSs32 slot;
+       NetworkInterfaceInfoOSX     *i;
+       mDNSu32 slot;
        CacheRecord *rr;
        mDNSu32 CacheUsed = 0, CacheActive = 0;
+       mDNSs32 now = mDNSPlatformTimeNow();
 
-       LogMsg("%s ---- BEGIN STATE LOG ----", mDNSResponderVersionString);
+       LogMsgIdent(mDNSResponderVersionString, "---- BEGIN STATE LOG ----");
 
        for (slot = 0; slot < CACHE_HASH_SLOTS; slot++)
+               {
+               mDNSu32 SlotUsed = 0;
                for (rr = mDNSStorage.rrcache_hash[slot]; rr; rr=rr->next)
                        {
+                       mDNSs32 remain = rr->resrec.rroriginalttl - (now - rr->TimeRcvd) / mDNSPlatformOneSecond;
                        CacheUsed++;
+                       SlotUsed++;
                        if (rr->CRActiveQuestion) CacheActive++;
-                       LogMsg("%s %-5s%-6s%s", rr->CRActiveQuestion ? "Active:  " : "Inactive:", DNSTypeName(rr->resrec.rrtype),
+                       LogMsgNoIdent("%s%6ld %-6s%-6s%s", rr->CRActiveQuestion ? "*" : " ", remain, DNSTypeName(rr->resrec.rrtype),
                                ((NetworkInterfaceInfoOSX *)rr->resrec.InterfaceID)->ifa_name, GetRRDisplayString(&mDNSStorage, rr));
                        usleep(1000);   // Limit rate a little so we don't flood syslog too fast
                        }
+               if (mDNSStorage.rrcache_used[slot] != SlotUsed)
+                       LogMsgNoIdent("Cache use mismatch: rrcache_used[slot] is %lu, true count %lu", mDNSStorage.rrcache_used[slot], SlotUsed);
+               }
        if (mDNSStorage.rrcache_totalused != CacheUsed)
-               LogMsg("Cache use mismatch: rrcache_totalused is %lu, true count %lu", mDNSStorage.rrcache_totalused, CacheUsed);
+               LogMsgNoIdent("Cache use mismatch: rrcache_totalused is %lu, true count %lu", mDNSStorage.rrcache_totalused, CacheUsed);
        if (mDNSStorage.rrcache_active != CacheActive)
-               LogMsg("Cache use mismatch: rrcache_active is %lu, true count %lu", mDNSStorage.rrcache_active, CacheActive);
-       LogMsg("Cache currently contains %lu records; %lu referenced by active questions", CacheUsed, CacheActive);
+               LogMsgNoIdent("Cache use mismatch: rrcache_active is %lu, true count %lu", mDNSStorage.rrcache_active, CacheActive);
+       LogMsgNoIdent("Cache currently contains %lu records; %lu referenced by active questions", CacheUsed, CacheActive);
 
        for (e = DNSServiceDomainEnumerationList; e; e=e->next)
-               LogMsg("%5d: DomainEnumeration   %##s", e->ClientMachPort, e->dom.qname.c);
+               LogMsgNoIdent("%5d: DomainEnumeration   %##s", e->ClientMachPort, e->dom.qname.c);
 
        for (b = DNSServiceBrowserList; b; b=b->next)
-               LogMsg("%5d: ServiceBrowse       %##s", b->ClientMachPort, b->q.qname.c);
-
+               {
+               DNSServiceBrowserQuestion *qptr;
+               for (qptr = b->qlist; qptr; qptr = qptr->next)
+                       LogMsgNoIdent("%5d: ServiceBrowse       %##s", b->ClientMachPort, qptr->q.qname.c);
+               }
        for (l = DNSServiceResolverList; l; l=l->next)
-               LogMsg("%5d: ServiceResolve      %##s", l->ClientMachPort, l->i.name.c);
+               LogMsgNoIdent("%5d: ServiceResolve      %##s", l->ClientMachPort, l->i.name.c);
 
        for (r = DNSServiceRegistrationList; r; r=r->next)
-               LogMsg("%5d: ServiceRegistration %##s", r->ClientMachPort, r->s.RR_SRV.resrec.name.c);
+               {
+               LogMsgNoIdent("%5d: ServiceRegistration %##s %u", r->ClientMachPort, r->ls.RR_SRV.resrec.name.c, mDNSVal16(r->ls.RR_SRV.resrec.rdata->u.srv.port));
+               if (r->gs) LogMsgNoIdent("%5d: ServiceRegistration %##s %u", r->ClientMachPort, r->gs->RR_SRV.resrec.name.c, mDNSVal16(r->gs->RR_SRV.resrec.rdata->u.srv.port));
+               }
 
        udsserver_info();
 
-       LogMsg("%s ----  END STATE LOG  ----", mDNSResponderVersionString);
+       for (i = mDNSStorage.p->InterfaceList; i; i = i->next)
+               {
+               if (!i->Exists)
+                       LogMsgNoIdent("Interface: %s %5s(%lu) DORMANT",
+                               i->sa_family == AF_INET ? "v4" : i->sa_family == AF_INET6 ? "v6" : "??", i->ifa_name, i->scope_id);
+               else
+                       LogMsgNoIdent("Interface: %s %5s(%lu) %s %s %2d %s %2d InterfaceID %p %s %s %#a",
+                               i->sa_family == AF_INET ? "v4" : i->sa_family == AF_INET6 ? "v6" : "??", i->ifa_name, i->scope_id,
+                               i->ifinfo.InterfaceActive ? "Active" : "      ",
+                               i->ifinfo.IPv4Available ? "v4" : "  ", i->ss.sktv4,
+                               i->ifinfo.IPv6Available ? "v6" : "  ", i->ss.sktv6,
+                               i->ifinfo.InterfaceID,
+                               i->ifinfo.Advertise ? "Adv"  : "   ",
+                               i->ifinfo.McastTxRx ? "TxRx" : "    ",
+                               &i->ifinfo.ip);
+               }
+
+       LogMsgIdent(mDNSResponderVersionString, "----  END STATE LOG  ----");
        }
 
 mDNSlocal void HandleSIGINFO(int signal)
@@ -1529,6 +1944,7 @@ mDNSlocal kern_return_t mDNSDaemonInitialize(void)
                rrcachestorage, RR_CACHE_SIZE,
                mDNS_Init_AdvertiseLocalAddresses,
                mDNS_StatusCallback, mDNS_Init_NoInitCallbackContext);
+       
        if (err) { LogMsg("Daemon start: mDNS_Init failed %ld", err); return(err); }
 
        client_death_port = CFMachPortGetPort(d_port);
@@ -1543,13 +1959,9 @@ mDNSlocal kern_return_t mDNSDaemonInitialize(void)
        CFRelease(s_rls);
        CFRelease(e_rls);
        CFRelease(i_rls);
-       if (debug_mode) printf("Service registered with Mach Port %d\n", m_port);
-#if ENABLE_UDS
-       err = udsserver_init();
+       if (mDNS_DebugMode) printf("Service registered with Mach Port %d\n", m_port);
+       err = udsserver_init(&mDNSStorage);
        if (err) { LogMsg("Daemon start: udsserver_init failed"); return err; }
-       err = udsserver_add_rl_source();
-       if (err) { LogMsg("Daemon start: udsserver_add_rl_source failed"); return err; }
-#endif
        return(err);
        }
 
@@ -1558,11 +1970,11 @@ mDNSlocal mDNSs32 mDNSDaemonIdle(void)
        // 1. Call mDNS_Execute() to let mDNSCore do what it needs to do
        mDNSs32 nextevent = mDNS_Execute(&mDNSStorage);
 
-       mDNSs32 now = mDNSPlatformTimeNow();
-
+       mDNSs32 now = mDNSPlatformTimeNow();    
+       
        // 2. Deliver any waiting browse messages to clients
        DNSServiceBrowser *b = DNSServiceBrowserList;
-
+                   
        while (b)
                {
                // NOTE: Need to advance b to the next element BEFORE we call DeliverInstance(), because in the
@@ -1611,7 +2023,7 @@ mDNSlocal mDNSs32 mDNSDaemonIdle(void)
                if (l->ReportTime && now - l->ReportTime >= 0)
                        {
                        l->ReportTime = 0;
-                       LogMsg("%5d: DNSServiceResolver(%##s) has remained active for over two minutes. "
+                       LogMsg("%5d: DNSServiceResolver(%##s) active for over two minutes. "
                                "This places considerable burden on the network.", l->ClientMachPort, l->i.name.c);
                        }
 
@@ -1622,11 +2034,10 @@ mDNSexport int main(int argc, char **argv)
        {
        int i;
        kern_return_t status;
-       FILE *fp;
-
+       
        for (i=1; i<argc; i++)
                {
-               if (!strcmp(argv[i], "-d")) debug_mode = 1;
+               if (!strcmp(argv[i], "-d")) mDNS_DebugMode = mDNStrue;
                }
 
        signal(SIGINT,  HandleSIGTERM);         // SIGINT is what you get for a Ctrl-C
@@ -1634,14 +2045,12 @@ mDNSexport int main(int argc, char **argv)
        signal(SIGINFO, HandleSIGINFO);
 
        // Register the server with mach_init for automatic restart only during normal (non-debug) mode
-    if (!debug_mode)
-               registerBootstrapService();
+    if (!mDNS_DebugMode) registerBootstrapService();
 
-       if (!debug_mode && !restarting_via_mach_init)
+       if (!mDNS_DebugMode && !restarting_via_mach_init)
                exit(0); /* mach_init will restart us immediately as a daemon */
 
-       // Unlike deamon(), mach_init does redirect standard file descriptors to /dev/null
-       if (!debug_mode)
+       if (!mDNS_DebugMode)
                {
                int fd = open(_PATH_DEVNULL, O_RDWR, 0);
                if (fd != -1)
@@ -1655,20 +2064,14 @@ mDNSexport int main(int argc, char **argv)
                        }
                }
 
-       fp = fopen(PID_FILE, "w");
-       if (fp != NULL)
-               {
-               fprintf(fp, "%d\n", getpid());
-               fclose(fp);
-               }
-       
-       LogMsg("%s starting", mDNSResponderVersionString);
+       // First do the all the initialization we need root privilege for, before we change to user "nobody"
+       LogMsgIdent(mDNSResponderVersionString, "starting");
        status = mDNSDaemonInitialize();
 
        // Now that we're finished with anything privileged, switch over to running as "nobody"
-       const struct passwd *pw = getpwnam( "nobody");
-       if ( pw != NULL)
-               setuid( pw->pw_uid);
+       const struct passwd *pw = getpwnam("nobody");
+       if (pw != NULL)
+               setuid(pw->pw_uid);
        else
                setuid(-2);             // User "nobody" is -2; use that value if "nobody" does not appear in the password database
 
@@ -1688,13 +2091,19 @@ mDNSexport int main(int argc, char **argv)
                        // 1. Before going into a blocking wait call and letting our process to go sleep,
                        // call mDNSDaemonIdle to allow any deferred work to be completed.
                        mDNSs32 nextevent = mDNSDaemonIdle();
-#if ENABLE_UDS
                        nextevent = udsserver_idle(nextevent);
-#endif
 
                        // 2. Work out how long we expect to sleep before the next scheduled task
                        mDNSs32 ticks = nextevent - mDNSPlatformTimeNow();
-                       if (ticks < 1) ticks = 1;
+                       static mDNSs32 RepeatedBusy = 0;        // Debugging sanity check, to guard against CPU spins
+                       if (ticks > 1)
+                               RepeatedBusy = 0;
+                       else
+                               {
+                               ticks = 1;
+                               if (++RepeatedBusy >= mDNSPlatformOneSecond * 10)
+                                       { LogMsg("Task Scheduling Error: Continuously busy for the last ten seconds"); RepeatedBusy = 0; }
+                               }
                        CFAbsoluteTime interval = (CFAbsoluteTime)ticks / (CFAbsoluteTime)mDNSPlatformOneSecond;
                                        
                        // 3. Now do a blocking "CFRunLoopRunInMode" call so we sleep until
@@ -1717,10 +2126,98 @@ mDNSexport int main(int argc, char **argv)
                mDNS_Close(&mDNSStorage);
                }
 
-       destroyBootstrapService();
+       if (!mDNS_DebugMode) destroyBootstrapService();
 
        return(status);
        }
 
+//             uds_daemon.c support routines           /////////////////////////////////////////////
+
+// We keep a list of client-supplied event sources in PosixEventSource records 
+struct CFSocketEventSource
+       {
+       udsEventCallback                        Callback;
+       void                                            *Context;
+       int                                                     fd;
+       struct  CFSocketEventSource     *Next;
+       CFSocketRef                                     SocketRef;
+       CFRunLoopSourceRef                      RLS;
+       };
+typedef struct CFSocketEventSource     CFSocketEventSource;
+
+static GenLinkedList   gEventSources;                  // linked list of CFSocketEventSource's
+
+static void cf_callback(CFSocketRef s _UNUSED, CFSocketCallBackType t _UNUSED, CFDataRef dr _UNUSED, const void *c _UNUSED, void *i)
+       // Called by CFSocket when data appears on socket
+       {
+       CFSocketEventSource     *source = (CFSocketEventSource*) i;
+       source->Callback(source->Context);
+       }
+
+mStatus udsSupportAddFDToEventLoop(int fd, udsEventCallback callback, void *context)
+       // Arrange things so that callback is called with context when data appears on fd
+       {
+       CFSocketEventSource     *newSource;
+       CFSocketContext cfContext =     { 0, NULL, NULL, NULL, NULL     };
+       
+       if (gEventSources.LinkOffset == 0)
+               InitLinkedList(&gEventSources, offsetof(CFSocketEventSource, Next));
+
+       if (fd >= FD_SETSIZE || fd < 0)
+               return mStatus_UnsupportedErr;
+       if (callback == NULL)
+               return mStatus_BadParamErr;
+
+       newSource = (CFSocketEventSource*) calloc(1, sizeof *newSource);
+       if (NULL == newSource)
+               return mStatus_NoMemoryErr;
+
+       newSource->Callback = callback;
+       newSource->Context = context;
+       newSource->fd = fd;
+
+       cfContext.info = newSource;
+       if ( NULL != (newSource->SocketRef = CFSocketCreateWithNative(kCFAllocatorDefault, fd, kCFSocketReadCallBack, 
+                                                                                                                                       cf_callback, &cfContext)) &&
+                NULL != (newSource->RLS = CFSocketCreateRunLoopSource(kCFAllocatorDefault, newSource->SocketRef, 0)))
+               {
+               CFRunLoopAddSource(CFRunLoopGetCurrent(), newSource->RLS, kCFRunLoopDefaultMode);
+               AddToTail(&gEventSources, newSource);
+               }
+       else
+               {
+               if (newSource->SocketRef)
+                       {
+                       CFSocketInvalidate(newSource->SocketRef);  // automatically closes socket
+                       CFRelease(newSource->SocketRef);
+                       }
+               return mStatus_NoMemoryErr;
+               }
+
+       return mStatus_NoError;
+       }
+
+mStatus udsSupportRemoveFDFromEventLoop(int fd)
+       // Reverse what was done in udsSupportAddFDToEventLoop().
+       {
+       CFSocketEventSource     *iSource;
+
+       for (iSource=(CFSocketEventSource*)gEventSources.Head; iSource; iSource = iSource->Next)
+               {
+               if (fd == iSource->fd)
+                       {
+                       RemoveFromList(&gEventSources, iSource);
+                       CFRunLoopRemoveSource(CFRunLoopGetCurrent(), iSource->RLS, kCFRunLoopDefaultMode);
+                       CFRunLoopSourceInvalidate(iSource->RLS);
+                       CFRelease(iSource->RLS);
+                       CFSocketInvalidate(iSource->SocketRef);
+                       CFRelease(iSource->SocketRef);
+                       free(iSource);
+                       return mStatus_NoError;
+                       }
+               }
+       return mStatus_NoSuchNameErr;
+       }
+
 // For convenience when using the "strings" command, this is the last thing in the file
 mDNSexport const char mDNSResponderVersionString[] = STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")";
diff --git a/mDNSMacOSX/dnssd_clientstub.c b/mDNSMacOSX/dnssd_clientstub.c
deleted file mode 100755 (executable)
index 7277eda..0000000
+++ /dev/null
@@ -1,998 +0,0 @@
-/*
- * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- * 
- * @APPLE_LICENSE_HEADER_END@
-
-    Change History (most recent first):
-
-$Log: dnssd_clientstub.c,v $
-Revision 1.9  2003/08/15 21:30:39  cheshire
-Bring up to date with LibInfo version
-
-Revision 1.8  2003/08/13 23:54:52  ksekar
-Bringing dnssd_clientstub.c up to date with Libinfo, per radar 3376640
-
-Revision 1.7  2003/08/12 19:56:25  cheshire
-Update to APSL 2.0
-
- */
-
-#include "dnssd_ipc.h"
-
-#define CTL_PATH_PREFIX "/tmp/dnssd_clippath."
-// error socket (if needed) is named "dnssd_clipath.[pid].xxx:n" where xxx are the
-// last 3 digits of the time (in seconds) and n is the 6-digit microsecond time
-
-// general utility functions
-static DNSServiceRef connect_to_server(void);
-DNSServiceErrorType deliver_request(void *msg, DNSServiceRef sdr, int reuse_sd);
-static ipc_msg_hdr *create_hdr(int op, int *len, char **data_start, int reuse_socket);
-static int my_read(int sd, char *buf, int len);
-static int my_write(int sd, char *buf, int len);
-static int domain_ends_in_dot(const char *dom);
-// server response handlers
-static void handle_query_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *msg);
-static void handle_browse_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data);
-static void handle_regservice_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data);
-static void handle_regrecord_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data);
-static void handle_enumeration_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data);
-static void handle_resolve_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data);
-
-typedef struct _DNSServiceRef_t
-    {
-    int sockfd;  // connected socket between client and daemon
-    int op;      // request/reply_op_t
-    process_reply_callback process_reply;
-    void *app_callback;
-    void *app_context;
-    uint32_t max_index;  //largest assigned record index - 0 if no additl. recs registered
-    } _DNSServiceRef_t;
-
-typedef struct _DNSRecordRef_t
-    {
-    void *app_context;
-    DNSServiceRegisterRecordReply app_callback;
-    DNSRecordRef recref;
-    int record_index;  // index is unique to the ServiceDiscoveryRef
-    DNSServiceRef sdr;
-    } _DNSRecordRef_t;
-
-
-// exported functions
-
-int DNSServiceRefSockFD(DNSServiceRef sdRef)
-    {
-    if (!sdRef) return -1;
-    return sdRef->sockfd;
-    }
-
-// handle reply from server, calling application client callback.  If there is no reply
-// from the daemon on the socket contained in sdRef, the call will block.
-DNSServiceErrorType DNSServiceProcessResult(DNSServiceRef sdRef)
-    {
-    ipc_msg_hdr hdr;
-    char *data;
-
-    if (!sdRef || sdRef->sockfd < 0 || !sdRef->process_reply) 
-        return kDNSServiceErr_BadReference;
-
-    if (my_read(sdRef->sockfd, (void *)&hdr, sizeof(hdr)) < 0) 
-        return kDNSServiceErr_Unknown;
-    if (hdr.version != VERSION)
-        return kDNSServiceErr_Incompatible;
-    data = malloc(hdr.datalen);
-    if (!data) return kDNSServiceErr_NoMemory;
-    if (my_read(sdRef->sockfd, data, hdr.datalen) < 0) 
-        return kDNSServiceErr_Unknown;
-    sdRef->process_reply(sdRef, &hdr, data);
-    return kDNSServiceErr_Unknown;
-    }
-
-
-void DNSServiceRefDeallocate(DNSServiceRef sdRef)
-    {
-    if (!sdRef) return;
-    if (sdRef->sockfd > 0) close(sdRef->sockfd);
-    free(sdRef);
-    }
-
-
-DNSServiceErrorType DNSServiceResolve
-    (
-    DNSServiceRef                       *sdRef,
-    const DNSServiceFlags               flags,
-    const uint32_t                      interfaceIndex,
-    const char                          *name,
-    const char                          *regtype,
-    const char                          *domain,
-    const DNSServiceResolveReply        callBack,
-    void                                *context
-    )
-    {
-    char *msg = NULL, *ptr;
-    int len;
-    ipc_msg_hdr *hdr;
-    DNSServiceRef sdr;
-    DNSServiceErrorType err;
-    
-    if (!sdRef) return kDNSServiceErr_BadParam;
-    *sdRef = NULL;
-    
-    // calculate total message length
-    len = sizeof(flags);
-    len += sizeof(interfaceIndex);
-    len += strlen(name) + 1;
-    len += strlen(regtype) + 1;
-    len += strlen(domain) + 1;
-
-    hdr = create_hdr(resolve_request, &len, &ptr, 1);
-    if (!hdr) goto error;
-    msg = (void *)hdr;
-
-    put_flags(flags, &ptr);
-    put_long(interfaceIndex, &ptr);
-    put_string(name, &ptr);
-    put_string(regtype, &ptr);
-    put_string(domain, &ptr);
-    
-    sdr = connect_to_server();
-    if (!sdr) goto error;
-    err = deliver_request(msg, sdr, 1);
-    if (err)
-        {
-        DNSServiceRefDeallocate(sdr);
-        return err;
-        }
-    sdr->op = resolve_request;
-    sdr->process_reply = handle_resolve_response;
-    sdr->app_callback = callBack;
-    sdr->app_context = context;
-    *sdRef = sdr;
-    
-    return err;
-
-error:
-    if (msg) free(msg);
-    if (*sdRef) { free(*sdRef);  *sdRef = NULL; }
-    return kDNSServiceErr_Unknown;
-    }
-    
-    
-static void handle_resolve_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data)
-    {
-    DNSServiceFlags flags;
-    char fullname[kDNSServiceMaxDomainName];
-    char target[kDNSServiceMaxDomainName];
-    uint16_t port, txtlen;
-    uint32_t ifi;
-    DNSServiceErrorType err;
-    char *txtrecord;
-    
-    (void)hdr;          //unused
-    
-    flags = get_flags(&data);
-    ifi = get_long(&data);
-    err = get_error_code(&data);
-    get_string(&data, fullname, kDNSServiceMaxDomainName);
-    get_string(&data, target, kDNSServiceMaxDomainName);
-    port = get_short(&data);
-    txtlen = get_short(&data);
-    txtrecord = get_rdata(&data, txtlen);
-    
-    ((DNSServiceResolveReply)sdr->app_callback)(sdr, flags, ifi, err, fullname, target, port, txtlen, txtrecord, sdr->app_context);
-    }
-    
-    
-
-
-DNSServiceErrorType DNSServiceQueryRecord
-(
- DNSServiceRef                          *sdRef,
- const DNSServiceFlags                   flags,
- const uint32_t                         interfaceIndex,
- const char                             *name,
- const uint16_t                         rrtype,
- const uint16_t                         rrclass,
- const DNSServiceQueryRecordReply       callBack,
- void                                   *context
- )
-    {
-    char *msg = NULL, *ptr;
-    int len;
-    ipc_msg_hdr *hdr;
-    DNSServiceRef sdr;
-    DNSServiceErrorType err;
-    
-    if (!sdRef) return kDNSServiceErr_BadParam;
-    *sdRef = NULL;
-
-    if (!name) name = "\0";
-
-    // calculate total message length
-    len = sizeof(flags);
-    len += sizeof(uint32_t);  //interfaceIndex
-    len += strlen(name) + 1;
-    len += 2 * sizeof(uint16_t);  // rrtype, rrclass
-
-    hdr = create_hdr(query_request, &len, &ptr, 1);
-    if (!hdr) goto error;
-    msg = (void *)hdr;
-
-    put_flags(flags, &ptr);
-    put_long(interfaceIndex, &ptr);
-    put_string(name, &ptr);
-    put_short(rrtype, &ptr);
-    put_short(rrclass, &ptr);
-
-    sdr = connect_to_server();
-    if (!sdr) goto error;
-    err = deliver_request(msg, sdr, 1);
-    if (err)
-        {
-        DNSServiceRefDeallocate(sdr);
-        return err;
-        }
-
-    sdr->op = query_request;
-    sdr->process_reply = handle_query_response;
-    sdr->app_callback = callBack;
-    sdr->app_context = context;
-    *sdRef = sdr;
-    return err;
-
-error:
-    if (msg) free(msg);
-    if (*sdRef) { free(*sdRef);  *sdRef = NULL; }
-    return kDNSServiceErr_Unknown;
-    }
-
-
-static void handle_query_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data)
-    {
-    DNSServiceFlags flags;
-    uint32_t interfaceIndex, ttl;
-    DNSServiceErrorType errorCode;
-    char name[256]; 
-    uint16_t rrtype, rrclass, rdlen;
-    char *rdata;
-    (void)hdr;//Unused
-
-    flags = get_flags(&data);
-    interfaceIndex = get_long(&data);
-    errorCode = get_error_code(&data);
-    (get_string(&data, name, 256) < 0);
-    rrtype = get_short(&data);
-    rrclass = get_short(&data);
-    rdlen = get_short(&data);
-    rdata = get_rdata(&data, rdlen);
-    ttl = get_long(&data);
-    if (!rdata) return;
-    ((DNSServiceQueryRecordReply)sdr->app_callback)(sdr, flags, interfaceIndex, errorCode, name, rrtype, rrclass,
-                                              rdlen, rdata, ttl, sdr->app_context);
-    return;
-    }
-
-DNSServiceErrorType DNSServiceBrowse
-(
- DNSServiceRef                      *sdRef,
- const DNSServiceFlags              flags,
- const uint32_t                     interfaceIndex,
- const char                         *regtype,
- const char                         *domain,
- const DNSServiceBrowseReply        callBack,
- void                               *context
- )
-    {
-    char *msg = NULL, *ptr;
-    int len;
-    ipc_msg_hdr *hdr;
-    DNSServiceRef sdr;
-    DNSServiceErrorType err;
-
-    if (!sdRef) return kDNSServiceErr_BadParam;
-    *sdRef = NULL;
-
-    if (!domain) domain = "";
-
-    len = sizeof(flags);
-    len += sizeof(interfaceIndex);
-    len += strlen(regtype) + 1;
-    len += strlen(domain) + 1;
-
-    hdr = create_hdr(browse_request, &len, &ptr, 1);
-    if (!hdr) goto error;
-    msg = (char *)hdr;
-    put_flags(flags, &ptr);
-    put_long(interfaceIndex, &ptr);
-    put_string(regtype, &ptr);
-    put_string(domain, &ptr);
-
-    sdr = connect_to_server();
-    if (!sdr) goto error;
-    err = deliver_request(msg, sdr, 1);
-    if (err)
-        {
-        DNSServiceRefDeallocate(sdr);
-        return err;
-        }
-    sdr->op = browse_request;
-    sdr->process_reply = handle_browse_response;
-    sdr->app_callback = callBack;
-    sdr->app_context = context;
-    *sdRef = sdr;
-    return err;
-
-error:
-    if (msg) free(msg);
-    if (*sdRef) { free(*sdRef);  *sdRef = NULL; }
-    return kDNSServiceErr_Unknown;
-    }
-
-
-
-
-static void handle_browse_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data)
-    {
-    DNSServiceFlags      flags;
-    uint32_t                      interfaceIndex;
-    DNSServiceErrorType      errorCode;
-    char replyName[256], replyType[256], replyDomain[256];
-        (void)hdr;//Unused
-
-    flags = get_flags(&data);
-    interfaceIndex = get_long(&data);
-    errorCode = get_error_code(&data);
-    get_string(&data, replyName, 256);
-    get_string(&data, replyType, 256);
-    get_string(&data, replyDomain, 256);
-    ((DNSServiceBrowseReply)sdr->app_callback)(sdr, flags, interfaceIndex, errorCode, replyName, replyType, replyDomain, sdr->app_context);
-    }
-
-
-DNSServiceErrorType DNSServiceRegister
-    (
-    DNSServiceRef                       *sdRef,
-    const DNSServiceFlags               flags,
-    const uint32_t                      interfaceIndex,
-    const char                          *name,         
-    const char                          *regtype,  
-    const char                          *domain,       
-    const char                          *host,         
-    const uint16_t                      port,
-    const uint16_t                      txtLen,
-    const void                          *txtRecord,    
-    const DNSServiceRegisterReply       callBack,      
-    void                                *context       
-    )
-    {
-    char *msg = NULL, *ptr;
-    int len;
-    ipc_msg_hdr *hdr;
-    DNSServiceRef sdr;
-    DNSServiceErrorType err;
-
-    if (!sdRef) return kDNSServiceErr_BadParam;
-    *sdRef = NULL;
-
-    if (!name) name = "";
-    if (!regtype) return kDNSServiceErr_BadParam;
-    if (!domain) domain = "";
-    if (!host) host = "";
-    if (!txtRecord) (char *)txtRecord = "";
-    
-    // auto-name must also have auto-rename
-    if (!name[0]  && (flags & kDNSServiceFlagsNoAutoRename))
-        return kDNSServiceErr_BadParam;
-
-    // no callback must have auto-name
-    if (!callBack && name[0]) return kDNSServiceErr_BadParam;
-
-    len = sizeof(DNSServiceFlags);
-    len += sizeof(uint32_t);  // interfaceIndex
-    len += strlen(name) + strlen(regtype) + strlen(domain) + strlen(host) + 4;
-    len += 2 * sizeof(uint16_t);  // port, txtLen
-    len += txtLen;
-
-    hdr = create_hdr(reg_service_request, &len, &ptr, 1);
-    if (!hdr) goto error;
-    if (!callBack) hdr->flags |= IPC_FLAGS_NOREPLY;
-    msg = (char *)hdr;
-    put_flags(flags, &ptr);
-    put_long(interfaceIndex, &ptr);
-    put_string(name, &ptr);
-    put_string(regtype, &ptr);
-    put_string(domain, &ptr);
-    put_string(host, &ptr);
-    put_short(port, &ptr);
-    put_short(txtLen, &ptr);
-    put_rdata(txtLen, txtRecord, &ptr);
-
-    sdr = connect_to_server();
-    if (!sdr) goto error;
-    err = deliver_request(msg, sdr, 1);
-    if (err)
-        {
-        DNSServiceRefDeallocate(sdr);
-        return err;
-        }
-        
-    sdr->op = reg_service_request;
-    sdr->process_reply = callBack ? handle_regservice_response : NULL;
-    sdr->app_callback = callBack;
-    sdr->app_context = context;
-    *sdRef = sdr;
-
-    return err;
-    
-error:
-    if (msg) free(msg);
-    if (*sdRef)         { free(*sdRef);  *sdRef = NULL; }
-    return kDNSServiceErr_Unknown;
-    }
-
-
-static void handle_regservice_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data)
-    {
-    DNSServiceFlags flags;
-    uint32_t interfaceIndex;
-    DNSServiceErrorType errorCode;
-    char name[256], regtype[256], domain[256];
-        (void)hdr;//Unused
-
-    flags = get_flags(&data);
-    interfaceIndex = get_long(&data);
-    errorCode = get_error_code(&data);
-    get_string(&data, name, 256);
-    get_string(&data, regtype, 256);
-    get_string(&data, domain, 256);
-    ((DNSServiceRegisterReply)sdr->app_callback)(sdr, flags, errorCode, name, regtype, domain, sdr->app_context);
-    }
-
-DNSServiceErrorType DNSServiceEnumerateDomains
-(
- DNSServiceRef                    *sdRef,
- const DNSServiceFlags            flags,
- const uint32_t                   interfaceIndex,
- const DNSServiceDomainEnumReply  callBack,
- void                             *context
- )
-    {
-    char *msg = NULL, *ptr;
-    int len;
-    ipc_msg_hdr *hdr;
-    DNSServiceRef sdr;
-    DNSServiceErrorType err;
-
-
-    if (!sdRef) return kDNSServiceErr_BadParam;
-    *sdRef = NULL;
-
-    len = sizeof(DNSServiceFlags);
-    len += sizeof(uint32_t);
-
-    hdr = create_hdr(enumeration_request, &len, &ptr, 1);
-    if (!hdr) goto error;
-    msg = (void *)hdr;
-
-    put_flags(flags, &ptr);
-    put_long(interfaceIndex, &ptr);
-
-    sdr = connect_to_server();
-    if (!sdr) goto error;
-    err = deliver_request(msg, sdr, 1);
-    if (err)
-        {
-        DNSServiceRefDeallocate(sdr);
-        return err;
-        }
-
-    sdr->op = enumeration_request;
-    sdr->process_reply = handle_enumeration_response;
-    sdr->app_callback = callBack;
-    sdr->app_context = context;
-    *sdRef = sdr;
-    return err;
-
-error:
-    if (msg) free(msg);
-    if (*sdRef) { free(*sdRef);  *sdRef = NULL; }
-    return kDNSServiceErr_Unknown;
-    }
-
-
-static void handle_enumeration_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data)
-    {
-    DNSServiceFlags flags;
-    uint32_t interfaceIndex;
-    DNSServiceErrorType err;
-    char domain[256];
-        (void)hdr;//Unused
-
-    flags = get_flags(&data);
-    interfaceIndex = get_long(&data);
-    err = get_error_code(&data);
-    get_string(&data, domain, 256);
-    ((DNSServiceDomainEnumReply)sdr->app_callback)(sdr, flags, interfaceIndex, err, domain, sdr->app_context);
-    }
-
-
-DNSServiceErrorType DNSServiceCreateConnection(DNSServiceRef *sdRef)
-    {
-    if (!sdRef) return kDNSServiceErr_BadParam;
-    *sdRef = connect_to_server();
-    if (!*sdRef)
-            return kDNSServiceErr_Unknown;
-    (*sdRef)->op = connection;
-    (*sdRef)->process_reply = handle_regrecord_response;
-    return 0;
-    }
-
-
-
-static void handle_regrecord_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data)
-    {
-    DNSServiceFlags flags;
-    uint32_t interfaceIndex;
-    DNSServiceErrorType errorCode;
-    DNSRecordRef rref = hdr->client_context.context;
-    
-    if (sdr->op != connection) 
-        {
-        rref->app_callback(rref->sdr, rref, 0, kDNSServiceErr_Unknown, rref->app_context);
-        return;
-        }
-    flags = get_flags(&data);
-    interfaceIndex = get_long(&data);
-    errorCode = get_error_code(&data);
-
-    rref->app_callback(rref->sdr, rref, flags, errorCode, rref->app_context);
-    }
-
-DNSServiceErrorType DNSServiceRegisterRecord
-(
- const DNSServiceRef                    sdRef,
- DNSRecordRef                           *RecordRef,  
- const DNSServiceFlags                  flags,
- const uint32_t                         interfaceIndex,
- const char                             *fullname,
- const uint16_t                         rrtype,
- const uint16_t                         rrclass,
- const uint16_t                         rdlen,
- const void                             *rdata,
- const uint32_t                         ttl,
- const DNSServiceRegisterRecordReply    callBack,
- void                                   *context
- )
-    {
-    char *msg = NULL, *ptr;
-    int len;
-    ipc_msg_hdr *hdr = NULL;
-    DNSServiceRef tmp = NULL;
-    DNSRecordRef rref = NULL;
-    
-    if (!sdRef || sdRef->op != connection || sdRef->sockfd < 0) 
-        return kDNSServiceErr_BadReference;
-    *RecordRef = NULL;
-    
-    len = sizeof(DNSServiceFlags);
-    len += 2 * sizeof(uint32_t);  // interfaceIndex, ttl
-    len += 3 * sizeof(uint16_t);  // rrtype, rrclass, rdlen
-    len += strlen(fullname) + 1;
-    len += rdlen;
-
-    hdr = create_hdr(reg_record_request, &len, &ptr, 0);
-    if (!hdr) goto error;
-    msg = (char *)hdr;
-    put_flags(flags, &ptr);
-    put_long(interfaceIndex, &ptr);
-    put_string(fullname, &ptr);
-    put_short(rrtype, &ptr);
-    put_short(rrclass, &ptr);
-    put_short(rdlen, &ptr);
-    put_rdata(rdlen, rdata, &ptr);
-    put_long(ttl, &ptr);
-
-    rref = malloc(sizeof(_DNSRecordRef_t));
-    if (!rref) goto error;
-    rref->app_context = context;
-    rref->app_callback = callBack;
-    rref->record_index = sdRef->max_index++;
-    rref->sdr = sdRef;
-    *RecordRef = rref;
-    hdr->client_context.context = rref;
-    hdr->reg_index = rref->record_index;  
-    
-    return deliver_request(msg, sdRef, 0);
-
-error:
-    if (rref) free(rref);
-    if (tmp) free(tmp);
-    if (hdr) free(hdr);
-    return kDNSServiceErr_Unknown;
-    }
-
-//sdRef returned by DNSServiceRegister()
-DNSServiceErrorType DNSServiceAddRecord
-    (
-    const DNSServiceRef                 sdRef,
-    DNSRecordRef                        *RecordRef,
-    const DNSServiceFlags               flags,
-    const uint16_t                      rrtype,
-    const uint16_t                      rdlen,
-    const void                          *rdata,
-    const uint32_t                      ttl
-    )
-    {
-    ipc_msg_hdr *hdr;
-    int len = 0;
-    char *ptr;
-    DNSRecordRef rref;
-
-    if (!sdRef || (sdRef->op != reg_service_request) || !RecordRef) 
-        return kDNSServiceErr_BadReference;
-    *RecordRef = NULL;
-    
-    len += 2 * sizeof(uint16_t);  //rrtype, rdlen
-    len += rdlen;
-    len += sizeof(uint32_t);
-    len += sizeof(DNSServiceFlags);
-
-    hdr = create_hdr(add_record_request, &len, &ptr, 0);
-    if (!hdr) return kDNSServiceErr_Unknown;
-    put_flags(flags, &ptr);
-    put_short(rrtype, &ptr);
-    put_short(rdlen, &ptr);
-    put_rdata(rdlen, rdata, &ptr);
-    put_long(ttl, &ptr);
-
-    rref = malloc(sizeof(_DNSRecordRef_t));
-    if (!rref) goto error;
-    rref->app_context = NULL;
-    rref->app_callback = NULL;
-    rref->record_index = sdRef->max_index++;
-    rref->sdr = sdRef;
-    *RecordRef = rref;
-    hdr->client_context.context = rref;
-    hdr->reg_index = rref->record_index;  
-    return deliver_request((char *)hdr, sdRef, 0);
-
-error:
-    if (hdr) free(hdr);
-    if (rref) free(rref);
-    if (*RecordRef) *RecordRef = NULL;
-    return kDNSServiceErr_Unknown;
-}
-    
-
-//DNSRecordRef returned by DNSServiceRegisterRecord or DNSServiceAddRecord
-DNSServiceErrorType DNSServiceUpdateRecord
-    (
-    const DNSServiceRef                 sdRef,
-    DNSRecordRef                        RecordRef,
-    const DNSServiceFlags               flags,
-    const uint16_t                      rdlen,
-    const void                          *rdata,
-    const uint32_t                      ttl
-    )
-    {
-    ipc_msg_hdr *hdr;
-    int len = 0;
-    char *ptr;
-
-    if (!sdRef || !RecordRef || !sdRef->max_index) 
-        return kDNSServiceErr_BadReference;
-    
-    len += sizeof(uint16_t);
-    len += rdlen;
-    len += sizeof(uint32_t);
-    len += sizeof(DNSServiceFlags);
-
-    hdr = create_hdr(update_record_request, &len, &ptr, 0);
-    if (!hdr) return kDNSServiceErr_Unknown;
-    hdr->reg_index = RecordRef ? RecordRef->record_index : TXT_RECORD_INDEX;
-    put_flags(flags, &ptr);
-    put_short(rdlen, &ptr);
-    put_rdata(rdlen, rdata, &ptr);
-    put_long(ttl, &ptr);
-    return deliver_request((char *)hdr, sdRef, 0);
-    }
-    
-
-
-DNSServiceErrorType DNSServiceRemoveRecord
-(
- const DNSServiceRef            sdRef,
- const DNSRecordRef             RecordRef,
- const DNSServiceFlags          flags
- )
-    {
-    ipc_msg_hdr *hdr;
-    int len = 0;
-    char *ptr;
-    DNSServiceErrorType err;
-
-    if (!sdRef || !RecordRef || !sdRef->max_index) 
-        return kDNSServiceErr_BadReference;
-    
-    len += sizeof(flags);
-    hdr = create_hdr(remove_record_request, &len, &ptr, 0);
-    if (!hdr) return kDNSServiceErr_Unknown;
-    hdr->reg_index = RecordRef->record_index;
-    put_flags(flags, &ptr);
-    err = deliver_request((char *)hdr, sdRef, 0);
-    if (!err) free(RecordRef);
-    return err;
-    }
-
-
-void DNSServiceReconfirmRecord
-(
- const DNSServiceFlags              flags,
- const uint32_t                     interfaceIndex,
- const char                         *fullname,
- const uint16_t                     rrtype,
- const uint16_t                     rrclass,
- const uint16_t                     rdlen,
- const void                         *rdata
- )
-    {
-    char *ptr;
-    int len;
-    ipc_msg_hdr *hdr;
-    DNSServiceRef tmp;
-
-    len = sizeof(DNSServiceFlags);
-    len += sizeof(uint32_t);
-    len += strlen(fullname) + 1;
-    len += 3 * sizeof(uint16_t);
-    len += rdlen;
-    tmp = connect_to_server();
-    if (!tmp) return;
-    hdr = create_hdr(reconfirm_record_request, &len, &ptr, 1);
-    if (!hdr) return;
-
-    put_flags(flags, &ptr);
-    put_long(interfaceIndex, &ptr);
-    put_string(fullname, &ptr);
-    put_short(rrtype, &ptr);
-    put_short(rrclass, &ptr);
-    put_short(rdlen, &ptr);
-    put_rdata(rdlen, rdata, &ptr);
-    my_write(tmp->sockfd, (char *)hdr, len);
-    DNSServiceRefDeallocate(tmp);
-    }
-        
-        
-int DNSServiceConstructFullName 
-    (
-    char                      *fullName,
-    const char                *service,      /* may be NULL */
-    const char                *regtype,
-    const char                *domain
-    )
-    {
-    int len;
-    u_char c;
-    char *fn = fullName;
-    const char *s = service;
-    const char *r = regtype;
-    const char *d = domain;
-    
-    if (service)
-        {
-        while(*s)
-            {
-            c = *s++;
-            if (c == '.' || (c == '\\')) *fn++ = '\\';          // escape dot and backslash literals
-            else if (c <= ' ')                                  // escape non-printable characters
-                {
-                *fn++ = '\\';
-                *fn++ = (char) ('0' + (c / 100));
-                *fn++ = (char) ('0' + (c / 10) % 10);
-                c = (u_char)('0' + (c % 10));
-                }
-                *fn++ = c;
-            }
-        *fn++ = '.';
-        }
-
-    if (!regtype) return -1;
-    len = strlen(regtype);
-    if (domain_ends_in_dot(regtype)) len--;
-    if (len < 4) return -1;                                     // regtype must end in _udp or _tcp
-    if (strncmp((regtype + len - 4), "_tcp", 4) && strncmp((regtype + len - 4), "_udp", 4)) return -1;
-    while(*r)
-        *fn++ = *r++;                                                                                                                                                                                        
-    if (!domain_ends_in_dot(regtype)) *fn++ = '.';
-                                                                                        
-    if (!domain) return -1;
-    len = strlen(domain);
-    if (!len) return -1;
-    while(*d) 
-        *fn++ = *d++;                                           
-    if (!domain_ends_in_dot(domain)) *fn++ = '.';
-    *fn = '\0';
-    return 0;
-    }
-        
-static int domain_ends_in_dot(const char *dom)
-    {
-    while(*dom && *(dom + 1))
-        {
-        if (*dom == '\\')       // advance past escaped byte sequence
-            {           
-            if (*(dom + 1) >= '0' && *(dom + 1) <= '9') dom += 4;
-            else dom += 2;
-            }
-        else dom++;             // else read one character
-        }
-        return (*dom == '.');
-    }
-
-
-
-    // return a connected service ref (deallocate with DNSServiceRefDeallocate)
-static DNSServiceRef connect_to_server(void)
-    {
-    struct sockaddr_un saddr;
-    DNSServiceRef sdr;
-
-    sdr = malloc(sizeof(_DNSServiceRef_t));
-    if (!sdr) return NULL;
-
-    if ((sdr->sockfd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0) 
-        {
-        free(sdr);
-        return NULL;
-        }
-
-    saddr.sun_family = AF_LOCAL;
-    strcpy(saddr.sun_path, MDNS_UDS_SERVERPATH);
-    if (connect(sdr->sockfd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0)
-        {
-        free(sdr);
-        return NULL;
-        }
-    return sdr; 
-    }
-
-
-
-
-int my_write(int sd, char *buf, int len)
-    {
-    if (send(sd, buf, len, MSG_WAITALL) != len)   return -1;
-    return 0;
-    }
-
-
-// read len bytes.  return 0 on success, -1 on error
-int my_read(int sd, char *buf, int len)
-    {
-    if (recv(sd, buf, len, MSG_WAITALL) != len)  return -1;
-    return 0;
-    }
-
-
-DNSServiceErrorType deliver_request(void *msg, DNSServiceRef sdr, int reuse_sd)
-    {
-    ipc_msg_hdr *hdr = msg;
-    mode_t mask;
-    struct sockaddr_un caddr, daddr;  // (client and daemon address structs)
-    char *path = NULL;
-    int listenfd = -1, errsd = -1, len;
-    DNSServiceErrorType err = kDNSServiceErr_Unknown;
-    
-    if (!hdr || sdr->sockfd < 0) return kDNSServiceErr_Unknown;
-
-    if (!reuse_sd) 
-        {
-        // setup temporary error socket
-        if ((listenfd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0) 
-            goto cleanup;
-
-        bzero(&caddr, sizeof(caddr));
-        caddr.sun_family = AF_LOCAL;
-        caddr.sun_len = sizeof(struct sockaddr_un);
-        path = (char *)msg + sizeof(ipc_msg_hdr);
-        strcpy(caddr.sun_path, path);
-        mask = umask(0);
-        if (bind(listenfd, (struct sockaddr *)&caddr, sizeof(caddr)) < 0)
-          {
-            umask(mask);
-            goto cleanup;
-          }
-        umask(mask);
-        listen(listenfd, 1);
-        }
-        
-    if (my_write(sdr->sockfd, msg, hdr->datalen + sizeof(ipc_msg_hdr)) < 0)  
-        goto cleanup;
-    free(msg);
-    msg = NULL;
-
-    if (reuse_sd) errsd = sdr->sockfd;
-    else 
-        {
-        len = sizeof(daddr);
-        errsd = accept(listenfd, (struct sockaddr *)&daddr, &len);
-        if (errsd < 0)  goto cleanup;
-        }
-    
-    len = recv(errsd, &err, sizeof(err), MSG_WAITALL);
-    if (len != sizeof(err))
-        {
-        err = kDNSServiceErr_Unknown;
-        }
-cleanup:
-    if (!reuse_sd && listenfd > 0) close(listenfd);
-    if (!reuse_sd && errsd > 0) close(errsd);   
-    if (!reuse_sd && path) unlink(path);
-    if (msg) free(msg);
-    return err;
-    }
-    
-    
-    
-/* create_hdr
- *
- * allocate and initialize an ipc message header.  value of len should initially be the
- * length of the data, and is set to the value of the data plus the header.  data_start 
- * is set to point to the beginning of the data section.  reuse_socket should be non-zero
- * for calls that can receive an immediate error return value on their primary socket.
- * if zero, the path to a control socket is appended at the beginning of the message buffer.
- * data_start is set past this string.
- */
-     
-static ipc_msg_hdr *create_hdr(int op, int *len, char **data_start, int reuse_socket)
-    {
-    char *msg = NULL;
-    ipc_msg_hdr *hdr;
-    int datalen;
-    char ctrl_path[256];
-    struct timeval time;
-
-    if (!reuse_socket)
-        {
-        if (gettimeofday(&time, NULL) < 0) return NULL;
-        sprintf(ctrl_path, "%s%d-%.3x-%.6u", CTL_PATH_PREFIX, (int)getpid(), 
-                time.tv_sec & 0xFFF, time.tv_usec);
-
-        *len += strlen(ctrl_path) + 1;
-        }
-    
-        
-    datalen = *len;
-    *len += sizeof(ipc_msg_hdr);
-
-    // write message to buffer
-    msg = malloc(*len);
-    if (!msg) return NULL;
-
-    bzero(msg, *len);
-    hdr = (void *)msg;
-    hdr->datalen = datalen;
-    hdr->version = VERSION;
-    hdr->op.request_op = op;
-    if (reuse_socket) hdr->flags |= IPC_FLAGS_REUSE_SOCKET;
-    *data_start = msg + sizeof(ipc_msg_hdr);
-    if (!reuse_socket)  put_string(ctrl_path, data_start);
-    return hdr;
-    }
diff --git a/mDNSMacOSX/dnssd_ipc.c b/mDNSMacOSX/dnssd_ipc.c
deleted file mode 100644 (file)
index 186f4d3..0000000
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- * 
- * @APPLE_LICENSE_HEADER_END@
-
-    Change History (most recent first):
-
-$Log: dnssd_ipc.c,v $
-Revision 1.7  2003/08/12 19:56:25  cheshire
-Update to APSL 2.0
-
- */
-
-#include "dnssd_ipc.h"
-
-void put_flags(const DNSServiceFlags flags, char **ptr)
-    {
-    memcpy(*ptr, &flags, sizeof(DNSServiceFlags));
-    *ptr += sizeof(flags);
-    }
-
-DNSServiceFlags get_flags(char **ptr)
-    {
-    DNSServiceFlags flags;
-       
-    flags = *(DNSServiceFlags *)*ptr;
-    *ptr += sizeof(DNSServiceFlags);
-    return flags;
-    }
-
-void put_long(const uint32_t l, char **ptr)
-    {
-
-    *(uint32_t *)(*ptr) = l;
-    *ptr += sizeof(uint32_t);
-    }
-
-uint32_t get_long(char **ptr)
-    {
-    uint32_t l;
-       
-    l = *(uint32_t *)(*ptr);
-    *ptr += sizeof(uint32_t);
-    return l;
-    }
-
-void put_error_code(const DNSServiceErrorType error, char **ptr)
-    {
-    memcpy(*ptr, &error, sizeof(error));
-    *ptr += sizeof(DNSServiceErrorType);
-    }
-
-DNSServiceErrorType get_error_code(char **ptr)
-    {
-    DNSServiceErrorType error;
-       
-    error = *(DNSServiceErrorType *)(*ptr);
-    *ptr += sizeof(DNSServiceErrorType);
-    return error;
-    }
-
-void put_short(const uint16_t s, char **ptr)
-    {
-    *(uint16_t *)(*ptr) = s;
-    *ptr += sizeof(uint16_t);
-    }
-
-uint16_t get_short(char **ptr)
-    {
-    uint16_t s;
-
-    s = *(uint16_t *)(*ptr);
-    *ptr += sizeof(uint16_t);
-    return s;
-    }
-
-
-int put_string(const char *str, char **ptr)
-    {
-    if (!str) str = "";
-    strcpy(*ptr, str);
-    *ptr += strlen(str) + 1;
-    return 0;
-    }
-
-// !!!KRS we don't properly handle the case where the string is longer than the buffer!!!      
-int get_string(char **ptr, char *buffer, int buflen)
-    {
-    int overrun;
-    
-    overrun = (int)strlen(*ptr) <  buflen ? 0 : -1;
-    strncpy(buffer, *ptr,  buflen - 1);
-    buffer[buflen - 1] = '\0';
-    *ptr += strlen(buffer) + 1;
-    return overrun;
-    }  
-
-void put_rdata(const int rdlen, const char *rdata, char **ptr)
-    {
-    memcpy(*ptr, rdata, rdlen);
-    *ptr += rdlen;     
-    }
-
-char *get_rdata(char **ptr, int rdlen)
-    {
-    char *rd;
-               
-    rd = *ptr;
-    *ptr += rdlen;
-    return rd;
-    }
-
-
-
-
-
-
-
-
-
diff --git a/mDNSMacOSX/dnssd_ipc.h b/mDNSMacOSX/dnssd_ipc.h
deleted file mode 100644 (file)
index 2b7b323..0000000
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- * 
- * @APPLE_LICENSE_HEADER_END@
-
-    Change History (most recent first):
-
-$Log: dnssd_ipc.h,v $
-Revision 1.6  2003/08/12 19:56:25  cheshire
-Update to APSL 2.0
-
- */
-
-#ifndef DNSSD_IPC_H
-#define DNSSD_IPC_H
-
-#include "dns_sd.h"
-#include <sys/types.h>
-#include <unistd.h>
-#include <sys/un.h>
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/stat.h>
-
-//#define UDSDEBUG  // verbose debug output
-
-// General UDS constants
-#define MDNS_UDS_SERVERPATH "/var/run/mDNSResponder" 
-#define LISTENQ 100
-#define TXT_RECORD_INDEX -1    // record index for default text record
-#define MAX_CTLPATH 256            // longest legal control path length
-
-// IPC data encoding constants and types
-#define VERSION 1
-#define IPC_FLAGS_NOREPLY 1    // set flag if no asynchronous replies are to be sent to client
-#define IPC_FLAGS_REUSE_SOCKET 2 // set flag if synchronous errors are to be sent via the primary socket
-                                // (if not set, first string in message buffer must be path to error socket
-
-
-typedef enum
-    {
-    connection = 1,           // connected socket via DNSServiceConnect()
-    reg_record_request,          // reg/remove record only valid for connected sockets
-    remove_record_request,
-    enumeration_request,
-    reg_service_request,
-    browse_request,
-    resolve_request,
-    query_request,
-    reconfirm_record_request,
-    add_record_request,
-    update_record_request
-    } request_op_t;
-
-typedef enum
-    {
-    enumeration_reply = 64,
-    reg_service_reply,
-    browse_reply,
-    resolve_reply,
-    query_reply,
-    reg_record_reply
-    } reply_op_t;
-
-
-typedef struct ipc_msg_hdr_struct ipc_msg_hdr;
-
-
-// client stub callback to process message from server and deliver results to
-// client application
-
-typedef void (*process_reply_callback)
-    (
-    DNSServiceRef sdr,
-    ipc_msg_hdr *hdr,
-    char *msg
-    );
-
-// allow 64-bit client to interoperate w/ 32-bit daemon
-typedef union
-    {
-    void *context;
-    uint32_t ptr64[2];
-    } client_context_t;
-
-
-typedef struct ipc_msg_hdr_struct
-    {
-    uint32_t version;
-    uint32_t datalen;
-    uint32_t flags;
-    union
-       {
-        request_op_t request_op;
-        reply_op_t reply_op;
-       } op;
-    client_context_t client_context; // context passed from client, returned by server in corresponding reply
-    int reg_index;                   // identifier for a record registered via DNSServiceRegisterRecord() on a
-    // socket connected by DNSServiceConnect().  Must be unique in the scope of the connection, such that and
-    // index/socket pair uniquely identifies a record.  (Used to select records for removal by DNSServiceRemoveRecord())
-    } ipc_msg_hdr_struct;                      
-
-
-
-
-// routines to write to and extract data from message buffers.
-// caller responsible for bounds checking.  
-// ptr is the address of the pointer to the start of the field.
-// it is advanced to point to the next field, or the end of the message
-
-
-void put_flags(const DNSServiceFlags flags, char **ptr);
-DNSServiceFlags get_flags(char **ptr);
-
-void put_long(const uint32_t l, char **ptr);
-uint32_t get_long(char **ptr);
-
-void put_error_code(const DNSServiceErrorType, char **ptr);
-DNSServiceErrorType get_error_code(char **ptr);
-
-int put_string(const char *str, char **ptr);
-int get_string(char **ptr, char *buffer, int buflen);
-
-void put_rdata(const int rdlen, const char *rdata, char **ptr);
-char *get_rdata(char **ptr, int rdlen);  // return value is rdata pointed to by *ptr - 
-                                         // rdata is not copied from buffer.
-
-void put_short(uint16_t s, char **ptr);
-uint16_t get_short(char **ptr);
-
-
-
-#endif // DNSSD_IPC_H
-
-
-
-
-
-
-
-
-
-
-
diff --git a/mDNSMacOSX/mDNSMacOSX.c b/mDNSMacOSX/mDNSMacOSX.c
deleted file mode 100644 (file)
index 4276c86..0000000
+++ /dev/null
@@ -1,1494 +0,0 @@
-/*
- * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- * 
- * @APPLE_LICENSE_HEADER_END@
-
-    Change History (most recent first):
-
-$Log: mDNSMacOSX.c,v $
-Revision 1.115.2.4  2004/04/23 00:34:06  cheshire
-<rdar://problem/3628978>: mDNSResponder messages on wake
-Take care to correctly update InterfaceIDs when a dormant interface comes back to life
-
-Revision 1.115.2.3  2004/04/08 23:18:11  cheshire
-<rdar://problem/3609972> When interface turned off, browse "remove" events delivered with interface index zero
-Refinement from Bob Bradley: Should use "mDNS *const m" instead of referencing mDNSStorage directly
-
-Revision 1.115.2.2  2004/04/08 00:42:37  cheshire
-<rdar://problem/3609972> When interface turned off, browse "remove" events delivered with interface index zero
-Unify use of the InterfaceID field, and make code that walks the list respect the CurrentlyActive flag
-
-Revision 1.115.2.1  2004/04/07 01:08:15  cheshire
-<rdar://problem/3609972> When interface turned off, browse "remove" events delivered with interface index zero
-
-Revision 1.115  2003/09/10 00:45:55  cheshire
-<rdar://problem/3412328> Don't log "sendto failed" errors during the first two minutes of startup
-
-Revision 1.114  2003/08/27 02:55:13  cheshire
-<rdar://problem/3387910>:      Bug: Don't report mDNSPlatformSendUDP sendto errno 64 (Host is down)
-
-Revision 1.113  2003/08/19 22:20:00  cheshire
-<rdar://problem/3376721> Don't use IPv6 on interfaces that have a routable IPv4 address configured
-More minor refinements
-
-Revision 1.112  2003/08/19 03:04:43  cheshire
-<rdar://problem/3376721> Don't use IPv6 on interfaces that have a routable IPv4 address configured
-
-Revision 1.111  2003/08/18 22:53:37  cheshire
-<rdar://problem/3382647> mDNSResponder divide by zero in mDNSPlatformTimeNow()
-
-Revision 1.110  2003/08/16 03:39:00  cheshire
-<rdar://problem/3338440> InterfaceID -1 indicates "local only"
-
-Revision 1.109  2003/08/15 02:19:49  cheshire
-<rdar://problem/3375225> syslog messages: myCFSocketCallBack recvfrom skt 6 error -1 errno 35
-Also limit number of messages to at most 100
-
-Revision 1.108  2003/08/12 22:24:52  cheshire
-<rdar://problem/3375225> syslog messages: myCFSocketCallBack recvfrom skt 6 error -1 errno 35
-This message indicates a kernel bug, but still we don't want to flood syslog.
-Do a sleep(1) after writing this log message, to limit the rate.
-
-Revision 1.107  2003/08/12 19:56:25  cheshire
-Update to APSL 2.0
-
-Revision 1.106  2003/08/12 13:48:32  cheshire
-Add comment explaining clockdivisor calculation
-
-Revision 1.105  2003/08/12 13:44:14  cheshire
-<rdar://problem/3370229> mDNSResponder *VERY* unhappy if time goes backwards
-Use mach_absolute_time() (which is guaranteed to always go forwards, resetting only on reboot)
-instead of gettimeofday() (which can jump back if the user manually changes their time/date)
-
-Revision 1.104  2003/08/12 13:12:07  cheshire
-Textual search/replace: Indicate local functions using "mDNSlocal" instead of "static"
-
-Revision 1.103  2003/08/08 18:36:04  cheshire
-<rdar://problem/3344154> Only need to revalidate on interface removal on platforms that have the PhantomInterfaces bug
-
-Revision 1.102  2003/08/06 00:14:52  cheshire
-<rdar://problem/3330324> Need to check IP TTL on responses
-Also add corresponding checks in the IPv6 code path
-
-Revision 1.101  2003/08/05 22:20:16  cheshire
-<rdar://problem/3330324> Need to check IP TTL on responses
-
-Revision 1.100  2003/08/05 21:18:50  cheshire
-<rdar://problem/3363185> mDNSResponder should ignore 6to4
-Only use interfaces that are marked as multicast-capable (IFF_MULTICAST)
-
-Revision 1.99  2003/08/05 20:13:52  cheshire
-<rdar://problem/3294080> mDNSResponder using IPv6 interfaces before they are ready
-Ignore interfaces with the IN6_IFF_NOTREADY flag set
-
-Revision 1.98  2003/07/20 03:38:51  ksekar
-Bug #: 3320722
-Completed support for Unix-domain socket based API.
-
-Revision 1.97  2003/07/19 03:15:16  cheshire
-Add generic MemAllocate/MemFree prototypes to mDNSPlatformFunctions.h,
-and add the obvious trivial implementations to each platform support layer
-
-Revision 1.96  2003/07/18 00:30:00  cheshire
-<rdar://problem/3268878> Remove mDNSResponder version from packet header and use HINFO record instead
-
-Revision 1.95  2003/07/12 03:15:20  cheshire
-<rdar://problem/3324848> After SCDynamicStore notification, mDNSResponder updates
-m->hostlabel even if user hasn't actually actually changed their dot-local hostname
-
-Revision 1.94  2003/07/03 00:51:54  cheshire
-<rdar://problem/3287213> When select() and recvmgs() disagree, get more info from kernel about the socket state
-
-Revision 1.93  2003/07/03 00:09:14  cheshire
-<rdar://problem/3286004> New APIs require a mDNSPlatformInterfaceIDfromInterfaceIndex() call
-Additional refinement suggested by Josh: Use info->scope_id instead of if_nametoindex(info->ifa_name);
-
-Revision 1.92  2003/07/02 21:19:51  cheshire
-<rdar://problem/3313413> Update copyright notices, etc., in source code comments
-
-Revision 1.91  2003/06/24 01:53:51  cheshire
-Minor update to comments
-
-Revision 1.90  2003/06/24 01:51:47  cheshire
-<rdar://problem/3303118> Oops: Double-dispose of sockets
-Don't need to close sockets: CFSocketInvalidate() does that for us
-
-Revision 1.89  2003/06/21 18:12:47  cheshire
-<rdar://problem/3296061> Rendezvous cannot handle interfaces whose total name is >3 chars
-One-line change: should say "IF_NAMESIZE", not sizeof(ifname)
-
-Revision 1.88  2003/06/12 23:38:37  cheshire
-<rdar://problem/3291162> mDNSResponder doesn't detect some configuration changes
-Also check that scope_id matches before concluding that two interfaces are the same
-
-Revision 1.87  2003/06/10 01:14:11  cheshire
-<rdar://problem/3286004> New APIs require a mDNSPlatformInterfaceIDfromInterfaceIndex() call
-
-Revision 1.86  2003/05/28 02:41:52  cheshire
-<rdar://problem/3034346> Time to remove Mac OS 9 UDP Port 53 legacy support
-
-Revision 1.85  2003/05/28 02:39:47  cheshire
-Minor change to debugging messages
-
-Revision 1.84  2003/05/27 22:29:40  cheshire
-Remove out-dated comment
-
-Revision 1.83  2003/05/26 03:21:29  cheshire
-Tidy up address structure naming:
-mDNSIPAddr         => mDNSv4Addr (for consistency with mDNSv6Addr)
-mDNSAddr.addr.ipv4 => mDNSAddr.ip.v4
-mDNSAddr.addr.ipv6 => mDNSAddr.ip.v6
-
-Revision 1.82  2003/05/26 03:01:27  cheshire
-<rdar://problem/3268904> sprintf/vsprintf-style functions are unsafe; use snprintf/vsnprintf instead
-
-Revision 1.81  2003/05/24 02:06:42  cheshire
-<rdar://problem/3268480> IPv6 Multicast Loopback doesn't work
-Tried setting IPV6_MULTICAST_LOOP; it doesn't help.
-However, it is probably wise to have the code explicitly set this socket
-option anyway, in case the default changes in later versions of Unix.
-
-Revision 1.80  2003/05/24 02:02:24  cheshire
-<rdar://problem/3221880> if_indextoname consumes a lot of CPU
-Fix error in myIfIndexToName; was returning prematurely
-
-Revision 1.79  2003/05/23 23:07:44  cheshire
-<rdar://problem/3268199> Must not write to stderr when running as daemon
-
-Revision 1.78  2003/05/23 01:19:04  cheshire
-<rdar://problem/3267085> mDNSResponder needs to signal type of service to AirPort
-Mark packets as high-throughput/low-delay (i.e. lowest reliability) to get maximum 802.11 multicast rate
-
-Revision 1.77  2003/05/23 01:12:05  cheshire
-Minor code tidying
-
-Revision 1.76  2003/05/22 01:26:01  cheshire
-Tidy up log messages
-
-Revision 1.75  2003/05/22 00:07:09  cheshire
-<rdar://problem/3264366> myCFSocketCallBack recvfrom(5) error 1, errno 35
-Extra logging to determine whether there is a bug in CFSocket
-
-Revision 1.74  2003/05/21 20:20:12  cheshire
-Fix warnings (mainly printf format string warnings, like using "%d" where
-it should say "%lu", etc.) and improve error logging (use strerror()
-to include textual error message as well as numeric error in log messages).
-
-Revision 1.73  2003/05/21 17:56:29  ksekar
-Bug #: <rdar://problem/3191277>:       mDNSResponder doesn't watch for IPv6 address changes
-
-Revision 1.72  2003/05/14 18:48:41  cheshire
-<rdar://problem/3159272> mDNSResponder should be smarter about reconfigurations
-More minor refinements:
-CFSocket.c needs to do *all* its mDNS_DeregisterInterface calls before freeing memory
-mDNS_DeregisterInterface revalidates cache record when *any* representative of an interface goes away
-
-Revision 1.71  2003/05/14 07:08:37  cheshire
-<rdar://problem/3159272> mDNSResponder should be smarter about reconfigurations
-Previously, when there was any network configuration change, mDNSResponder
-would tear down the entire list of active interfaces and start again.
-That was very disruptive, and caused the entire cache to be flushed,
-and caused lots of extra network traffic. Now it only removes interfaces
-that have really gone, and only adds new ones that weren't there before.
-
-Revision 1.70  2003/05/07 18:30:24  cheshire
-Fix signed/unsigned comparison warning
-
-Revision 1.69  2003/05/06 20:14:44  cheshire
-Change "tp" to "tv"
-
-Revision 1.68  2003/05/06 00:00:49  cheshire
-<rdar://problem/3248914> Rationalize naming of domainname manipulation functions
-
-Revision 1.67  2003/04/29 00:43:44  cheshire
-Fix compiler warnings
-
-Revision 1.66  2003/04/26 02:41:58  cheshire
-<rdar://problem/3241281> Change timenow from a local variable to a structure member
-
-Revision 1.65  2003/04/26 02:34:01  cheshire
-Add missing mDNSexport
-
-Revision 1.64  2003/04/15 16:48:06  jgraessl
-Bug #: 3228833
-Modified code in CFSocket notifier function to read all packets on the socket
-instead of reading only one packet every time the notifier was called.
-
-Revision 1.63  2003/04/15 16:33:50  jgraessl
-Bug #: 3221880
-Switched to our own copy of if_indextoname to improve performance.
-
-Revision 1.62  2003/03/28 01:55:44  cheshire
-Minor improvements to debugging messages
-
-Revision 1.61  2003/03/27 03:30:56  cheshire
-<rdar://problem/3210018> Name conflicts not handled properly, resulting in memory corruption, and eventual crash
-Problem was that HostNameCallback() was calling mDNS_DeregisterInterface(), which is not safe in a callback
-Fixes:
-1. Make mDNS_DeregisterInterface() safe to call from a callback
-2. Make HostNameCallback() use mDNS_DeadvertiseInterface() instead
-   (it never really needed to deregister the interface at all)
-
-Revision 1.60  2003/03/15 04:40:38  cheshire
-Change type called "mDNSOpaqueID" to the more descriptive name "mDNSInterfaceID"
-
-Revision 1.59  2003/03/11 01:23:26  cheshire
-Bug #: 3194246 mDNSResponder socket problems
-
-Revision 1.58  2003/03/06 01:43:04  cheshire
-Bug #: 3189097 Additional debugging code in mDNSResponder
-Improve "LIST_ALL_INTERFACES" output
-
-Revision 1.57  2003/03/05 22:36:27  cheshire
-Bug #: 3186338 Loopback doesn't work with mDNSResponder-27
-Temporary workaround: Skip loopback interface *only* if we found at least one v4 interface to use
-
-Revision 1.56  2003/03/05 01:50:38  cheshire
-Bug #: 3189097 Additional debugging code in mDNSResponder
-
-Revision 1.55  2003/02/21 01:54:09  cheshire
-Bug #: 3099194 mDNSResponder needs performance improvements
-Switched to using new "mDNS_Execute" model (see "Implementer Notes.txt")
-
-Revision 1.54  2003/02/20 06:48:35  cheshire
-Bug #: 3169535 Xserve RAID needs to do interface-specific registrations
-Reviewed by: Josh Graessley, Bob Bradley
-
-Revision 1.53  2003/01/29 02:21:23  cheshire
-Return mStatus_Invalid if can't send packet because socket not available
-
-Revision 1.52  2003/01/28 19:39:43  jgraessl
-Enabling AAAA over IPv4 support.
-
-Revision 1.51  2003/01/28 05:11:23  cheshire
-Fixed backwards comparison in SearchForInterfaceByName
-
-Revision 1.50  2003/01/13 23:49:44  jgraessl
-Merged changes for the following fixes in to top of tree:
-3086540  computer name changes not handled properly
-3124348  service name changes are not properly handled
-3124352  announcements sent in pairs, failing chattiness test
-
-Revision 1.49  2002/12/23 22:13:30  jgraessl
-Reviewed by: Stuart Cheshire
-Initial IPv6 support for mDNSResponder.
-
-Revision 1.48  2002/11/22 01:37:52  cheshire
-Bug #: 3108426 mDNSResponder is monitoring ServiceEntities instead of InterfaceEntities
-
-Revision 1.47  2002/09/21 20:44:51  zarzycki
-Added APSL info
-
-Revision 1.46  2002/09/19 21:25:35  cheshire
-mDNS_snprintf() doesn't need to be in a separate file
-
-Revision 1.45  2002/09/17 01:45:13  cheshire
-Add LIST_ALL_INTERFACES symbol for debugging
-
-Revision 1.44  2002/09/17 01:36:23  cheshire
-Move Puma support to CFSocketPuma.c
-
-Revision 1.43  2002/09/17 01:05:28  cheshire
-Change mDNS_AdvertiseLocalAddresses to be an Init parameter instead of a global
-
-Revision 1.42  2002/09/16 23:13:50  cheshire
-Minor code tidying
-
- */
-
-// ***************************************************************************
-// mDNS-CFSocket.c:
-// Supporting routines to run mDNS on a CFRunLoop platform
-// ***************************************************************************
-
-// Open Transport 2.7.x on Mac OS 9 used to send Multicast DNS queries to UDP port 53,
-// before the Multicast DNS port was changed to 5353. For this reason, the mDNSResponder
-// in earlier versions of Mac OS X 10.2 Jaguar used to set mDNS_AllowPort53 to 1 to allow
-// it to also listen and answer queries on UDP port 53. Now that Transport 2.8 (included in
-// the Classic subsystem of Mac OS X 10.2 Jaguar) has been corrected to issue Multicast DNS
-// queries on UDP port 5353, this backwards-compatibility legacy support is no longer needed.
-#define mDNS_AllowPort53 0
-
-// For debugging, set LIST_ALL_INTERFACES to 1 to display all found interfaces,
-// including ones that mDNSResponder chooses not to use.
-#define LIST_ALL_INTERFACES 0
-
-// For enabling AAAA records over IPv4. Setting this to 0 sends only
-// A records over IPv4 and AAAA over IPv6. Setting this to 1 sends both
-// AAAA and A records over both IPv4 and IPv6.
-#define AAAA_OVER_V4   1
-
-#include "mDNSClientAPI.h"          // Defines the interface provided to the client layer above
-#include "mDNSPlatformFunctions.h"     // Defines the interface to the supporting layer below
-#include "mDNSMacOSX.h"                                // Defines the specific types needed to run mDNS on this platform
-
-#include <stdio.h>
-#include <unistd.h>                                    // For select() and close()
-#include <stdarg.h>                                    // For va_list support
-#include <net/if.h>
-#include <net/if_dl.h>
-#include <sys/uio.h>
-#include <sys/param.h>
-#include <sys/socket.h>
-#include <sys/sysctl.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-
-#include <netinet/in.h>                                // For IP_RECVTTL
-#ifndef IP_RECVTTL
-#define IP_RECVTTL 24  /* bool; receive reception TTL w/dgram */
-#endif
-
-#include <netinet/in_systm.h>          // For n_long, required by <netinet/ip.h> below
-#include <netinet/ip.h>                                // For IPTOS_LOWDELAY etc.
-#include <netinet6/in6_var.h>          // For IN6_IFF_NOTREADY etc.
-
-// Code contributed by Dave Heller:
-// Define RUN_ON_PUMA_WITHOUT_IFADDRS to compile code that will
-// work on Mac OS X 10.1, which does not have the getifaddrs call.
-#define RUN_ON_PUMA_WITHOUT_IFADDRS 0
-#if RUN_ON_PUMA_WITHOUT_IFADDRS
-#include "CFSocketPuma.c"
-#else
-#include <ifaddrs.h>
-#endif
-
-#include <IOKit/IOKitLib.h>
-#include <IOKit/IOMessage.h>
-#include <mach/mach_time.h>
-
-// ***************************************************************************
-// Globals
-
-static mDNSu32 clockdivisor = 0;
-
-// ***************************************************************************
-// Macros
-
-#define mDNSSameIPv4Address(A,B) ((A).NotAnInteger == (B).NotAnInteger)
-#define mDNSSameIPv6Address(A,B) ((A).l[0] == (B).l[0] && (A).l[1] == (B).l[1] && (A).l[2] == (B).l[2] && (A).l[3] == (B).l[3])
-
-#define mDNSAddressIsAllDNSLinkGroup(X) (                                                     \
-       ((X)->type == mDNSAddrType_IPv4 && mDNSSameIPv4Address((X)->ip.v4, AllDNSLinkGroup  )) || \
-       ((X)->type == mDNSAddrType_IPv6 && mDNSSameIPv6Address((X)->ip.v6, AllDNSLinkGroupv6))    )
-
-// ***************************************************************************
-// Functions
-
-// Note, this uses mDNS_vsnprintf instead of standard "vsnprintf", because mDNS_vsnprintf knows
-// how to print special data types like IP addresses and length-prefixed domain names
-#if MDNS_DEBUGMSGS
-mDNSexport void debugf_(const char *format, ...)
-       {
-       unsigned char buffer[512];
-       va_list ptr;
-       va_start(ptr,format);
-       buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0;
-       va_end(ptr);
-       fprintf(stderr,"%s\n", buffer);
-       fflush(stderr);
-       }
-#endif
-
-#if MDNS_DEBUGMSGS > 1
-mDNSexport void verbosedebugf_(const char *format, ...)
-       {
-       unsigned char buffer[512];
-       va_list ptr;
-       va_start(ptr,format);
-       buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0;
-       va_end(ptr);
-       fprintf(stderr,"%s\n", buffer);
-       fflush(stderr);
-       }
-#endif
-
-mDNSexport void LogMsg(const char *format, ...)
-       {
-       unsigned char buffer[512];
-       va_list ptr;
-       va_start(ptr,format);
-       buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0;
-       va_end(ptr);
-       
-       extern int debug_mode;
-       if (debug_mode)         // In debug_mode we write to stderr
-               {
-               fprintf(stderr,"%s\n", buffer);
-               fflush(stderr);
-               }
-       else                            // else, in production mode, we write to syslog
-               {
-               openlog("mDNSResponder", LOG_CONS | LOG_PERROR | LOG_PID, LOG_DAEMON);
-               syslog(LOG_ERR, "%s", buffer);
-               closelog();
-               }
-       }
-
-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;
-       }
-
-mDNSlocal int myIfIndexToName(u_short index, char* name)
-       {
-       struct ifaddrs *ifa;
-       for (ifa = myGetIfAddrs(0); ifa; ifa = ifa->ifa_next)
-               if (ifa->ifa_addr->sa_family == AF_LINK)
-                       if (((struct sockaddr_dl*)ifa->ifa_addr)->sdl_index == index)
-                               { strncpy(name, ifa->ifa_name, IF_NAMESIZE); return 0; }
-       return -1;
-       }
-
-mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(const mDNS *const m, mDNSu32 index)
-       {
-       NetworkInterfaceInfoOSX *i;
-       if (index == (uint32_t)~0) return((mDNSInterfaceID)~0);
-       if (index)
-               for (i = m->p->InterfaceList; i; i = i->next)
-                       if (i->ifinfo.InterfaceID && i->scope_id == index)      // Don't get tricked by inactive interfaces
-                               return(i->ifinfo.InterfaceID);
-       return(mDNSNULL);
-       }
-       
-mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(const mDNS *const m, mDNSInterfaceID id)
-       {
-       NetworkInterfaceInfoOSX *i;
-       if (id == (mDNSInterfaceID)~0) return((mDNSu32)~0);
-       if (id)
-               for (i = m->p->InterfaceList; i; i = i->next)
-                       // Don't use i->ifinfo.InterfaceID here because we want to find inactive interfaces where that's not set
-                       if ((mDNSInterfaceID)i == id)
-                               return i->scope_id;
-       return 0;
-       }
-
-mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end,
-       mDNSInterfaceID InterfaceID, mDNSIPPort srcPort, const mDNSAddr *dst, mDNSIPPort dstPort)
-       {
-       #pragma unused(m)
-       NetworkInterfaceInfoOSX *info = (NetworkInterfaceInfoOSX *)InterfaceID;
-       struct sockaddr_storage to;
-       int s, err;
-
-       if (!InterfaceID) { LogMsg("mDNSPlatformSendUDP ERROR! Cannot send from zero InterfaceID"); return mStatus_BadParamErr; }
-
-       if (dst->type == mDNSAddrType_IPv4)
-               {
-               struct sockaddr_in*     sin_to = (struct sockaddr_in*)&to;
-               sin_to->sin_len                 = sizeof(*sin_to);
-               sin_to->sin_family      = AF_INET;
-               sin_to->sin_port        = dstPort.NotAnInteger;
-               sin_to->sin_addr.s_addr = dst->ip.v4.NotAnInteger;
-               }
-       else if (dst->type == mDNSAddrType_IPv6)
-               {
-               struct sockaddr_in6* sin6_to = (struct sockaddr_in6*)&to;
-               sin6_to->sin6_len               = sizeof(*sin6_to);
-               sin6_to->sin6_family    = AF_INET6;
-               sin6_to->sin6_port              = dstPort.NotAnInteger;
-               sin6_to->sin6_flowinfo  = 0;
-               sin6_to->sin6_addr              = *(struct in6_addr*)&dst->ip.v6;
-               sin6_to->sin6_scope_id  = info->scope_id;
-               }
-       else
-               {
-               LogMsg("mDNSPlatformSendUDP: dst is not an IPv4 or IPv6 address!\n");
-               return mStatus_BadParamErr;
-               }
-
-       if (srcPort.NotAnInteger == MulticastDNSPort.NotAnInteger)
-               {
-               if      (dst->type == mDNSAddrType_IPv4) s = info->sktv4;
-               else if (dst->type == mDNSAddrType_IPv6) s = info->sktv6;
-               else                                     s = -1;
-               }
-#if mDNS_AllowPort53
-       else if (srcPort.NotAnInteger == UnicastDNSPort.NotAnInteger && dst->type == mDNSAddrType_IPv4)
-               s = info->skt53;
-#endif
-       else { LogMsg("Source port %d not allowed", (mDNSu16)srcPort.b[0]<<8 | srcPort.b[1]); return(-1); }
-       
-       if (s >= 0)
-               verbosedebugf("mDNSPlatformSendUDP: sending on InterfaceID %X %s/%d to %#a:%d skt %d",
-                       InterfaceID, info->ifa_name, dst->type, dst, (mDNSu16)dstPort.b[0]<<8 | dstPort.b[1], s);
-       else
-               verbosedebugf("mDNSPlatformSendUDP: NOT sending on InterfaceID %X %s/%d (socket of this type not available)",
-                       InterfaceID, info->ifa_name, dst->type, dst, (mDNSu16)dstPort.b[0]<<8 | dstPort.b[1]);
-
-       // Note: When sending, mDNSCore may often ask us to send both a v4 multicast packet and then a v6 multicast packet
-       // If we don't have the corresponding type of socket available, then return mStatus_Invalid
-       if (s < 0) return(mStatus_Invalid);
-
-       err = sendto(s, msg, (UInt8*)end - (UInt8*)msg, 0, (struct sockaddr *)&to, to.ss_len);
-       if (err < 0)
-               {
-               // Don't report EHOSTDOWN (i.e. ARP failure) to unicast destinations
-               if (errno == EHOSTDOWN && !mDNSAddressIsAllDNSLinkGroup(dst)) return(err);
-               // Don't report EHOSTUNREACH in the first two minutes after boot
-               // This is because mDNSResponder intentionally starts up early in the boot process (See <rdar://problem/3409090>)
-               // but this means that sometimes it starts before configd has finished setting up the multicast routing entries.
-               if (errno == EHOSTUNREACH && (mDNSu32)(m->timenow) < (mDNSu32)(mDNSPlatformOneSecond * 120)) return(err);
-               LogMsg("mDNSPlatformSendUDP sendto failed to send packet on InterfaceID %p %s/%ld to %#a:%d skt %d error %d errno %d (%s)",
-                       InterfaceID, info->ifa_name, dst->type, dst, (mDNSu16)dstPort.b[0]<<8 | dstPort.b[1], s, err, errno, strerror(errno));
-               return(err);
-               }
-       
-       return(mStatus_NoError);
-       }
-
-mDNSlocal ssize_t myrecvfrom(const int s, void *const buffer, const size_t max,
-       struct sockaddr *const from, size_t *const fromlen, mDNSAddr *dstaddr, char ifname[IF_NAMESIZE], mDNSu8 *ttl)
-       {
-       static unsigned int numLogMessages = 0;
-       struct iovec databuffers = { (char *)buffer, max };
-       struct msghdr   msg;
-       ssize_t         n;
-       struct cmsghdr *cmPtr;
-       char            ancillary[1024];
-
-       *ttl = 255;                     // If kernel fails to provide TTL data (e.g. Jaguar doesn't) then assume the TTL was 255 as it should be
-
-       // Set up the message
-       msg.msg_name       = (caddr_t)from;
-       msg.msg_namelen    = *fromlen;
-       msg.msg_iov        = &databuffers;
-       msg.msg_iovlen     = 1;
-       msg.msg_control    = (caddr_t)&ancillary;
-       msg.msg_controllen = sizeof(ancillary);
-       msg.msg_flags      = 0;
-       
-       // Receive the data
-       n = recvmsg(s, &msg, 0);
-       if (n<0)
-               {
-               if (errno != EWOULDBLOCK && numLogMessages++ < 100) LogMsg("CFSocket.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("CFSocket.c: recvmsg(%d) msg.msg_controllen %d < sizeof(struct cmsghdr) %lu",
-                       s, msg.msg_controllen, sizeof(struct cmsghdr));
-               return(-1);
-               }
-       if (msg.msg_flags & MSG_CTRUNC)
-               {
-               if (numLogMessages++ < 100) LogMsg("CFSocket.c: recvmsg(%d) msg.msg_flags & MSG_CTRUNC", s);
-               return(-1);
-               }
-       
-       *fromlen = msg.msg_namelen;
-       
-       // Parse each option out of the ancillary data.
-       for (cmPtr = CMSG_FIRSTHDR(&msg); cmPtr; cmPtr = CMSG_NXTHDR(&msg, cmPtr))
-               {
-               // debugf("myrecvfrom cmsg_level %d cmsg_type %d", cmPtr->cmsg_level, cmPtr->cmsg_type);
-               if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVDSTADDR)
-                       {
-                       dstaddr->type = mDNSAddrType_IPv4;
-                       dstaddr->ip.v4.NotAnInteger = *(u_int32_t*)CMSG_DATA(cmPtr);
-                       }
-               if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVIF)
-                       {
-                       struct sockaddr_dl *sdl = (struct sockaddr_dl *)CMSG_DATA(cmPtr);
-                       if (sdl->sdl_nlen < IF_NAMESIZE)
-                               {
-                               mDNSPlatformMemCopy(sdl->sdl_data, ifname, sdl->sdl_nlen);
-                               ifname[sdl->sdl_nlen] = 0;
-                               // debugf("IP_RECVIF sdl_index %d, sdl_data %s len %d", sdl->sdl_index, ifname, sdl->sdl_nlen);
-                               }
-                       }
-               if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVTTL)
-                       {
-                       *ttl = *(u_char*)CMSG_DATA(cmPtr);
-                       }
-               if (cmPtr->cmsg_level == IPPROTO_IPV6 && cmPtr->cmsg_type == IPV6_PKTINFO)
-                       {
-                       struct in6_pktinfo *ip6_info = (struct in6_pktinfo*)CMSG_DATA(cmPtr);
-                       dstaddr->type = mDNSAddrType_IPv6;
-                       dstaddr->ip.v6 = *(mDNSv6Addr*)&ip6_info->ipi6_addr;
-                       myIfIndexToName(ip6_info->ipi6_ifindex, ifname);
-                       }
-               if (cmPtr->cmsg_level == IPPROTO_IPV6 && cmPtr->cmsg_type == IPV6_HOPLIMIT)
-                       {
-                       *ttl = *(int*)CMSG_DATA(cmPtr);
-                       }
-               }
-
-       return(n);
-       }
-
-mDNSlocal void myCFSocketCallBack(CFSocketRef cfs, CFSocketCallBackType CallBackType, CFDataRef address, const void *data, void *context)
-       {
-       mDNSAddr senderAddr, destAddr;
-       mDNSIPPort senderPort, destPort = MulticastDNSPort;
-       NetworkInterfaceInfoOSX *info = (NetworkInterfaceInfoOSX *)context;
-       mDNS *const m = info->m;
-       DNSMessage packet;
-       struct sockaddr_storage from;
-       size_t fromlen = sizeof(from);
-       char packetifname[IF_NAMESIZE] = "";
-       int err, s1 = -1, skt = CFSocketGetNative(cfs);
-       int count = 0;
-       
-       (void)address;  // Parameter not used
-       (void)data;             // Parameter not used
-       
-       if (CallBackType != kCFSocketReadCallBack) LogMsg("myCFSocketCallBack: Why is CallBackType %d not kCFSocketReadCallBack?", CallBackType);
-
-#if mDNS_AllowPort53
-       if      (cfs == info->cfs53) { s1 = info->skt53; destPort = UnicastDNSPort; }
-       else
-#endif
-       if      (cfs == info->cfsv4) s1 = info->sktv4;
-       else if (cfs == info->cfsv6) s1 = info->sktv6;
-
-       if (s1 < 0 || s1 != skt)
-               {
-               LogMsg("myCFSocketCallBack: s1 %d native socket %d, cfs %p", s1, skt, cfs);
-#if mDNS_AllowPort53
-               LogMsg("myCFSocketCallBack: cfs53 %p, skt53 %d", info->cfs53, info->skt53);
-#endif
-               LogMsg("myCFSocketCallBack: cfsv4 %p, sktv4 %d", info->cfsv4, info->sktv4);
-               LogMsg("myCFSocketCallBack: cfsv6 %p, sktv6 %d", info->cfsv6, info->sktv6);
-               }
-
-       mDNSu8 ttl;
-       while ((err = myrecvfrom(s1, &packet, sizeof(packet), (struct sockaddr *)&from, &fromlen, &destAddr, packetifname, &ttl)) >= 0)
-               {
-               count++;
-               if (from.ss_family == AF_INET)
-                       {
-                       struct sockaddr_in *sin = (struct sockaddr_in*)&from;
-                       senderAddr.type = mDNSAddrType_IPv4;
-                       senderAddr.ip.v4.NotAnInteger = sin->sin_addr.s_addr;
-                       senderPort.NotAnInteger = sin->sin_port;
-                       }
-               else if (from.ss_family == AF_INET6)
-                       {
-                       struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&from;
-                       senderAddr.type = mDNSAddrType_IPv6;
-                       senderAddr.ip.v6 = *(mDNSv6Addr*)&sin6->sin6_addr;
-                       senderPort.NotAnInteger = sin6->sin6_port;
-                       }
-               else
-                       {
-                       LogMsg("myCFSocketCallBack from is unknown address family %d", from.ss_family);
-                       return;
-                       }
-
-               // Even though we indicated a specific interface in the IP_ADD_MEMBERSHIP call, a weirdness of the
-               // sockets API means that even though this socket has only officially joined the multicast group
-               // on one specific interface, the kernel will still deliver multicast packets to it no matter which
-               // interface they arrive on. According to the official Unix Powers That Be, this is Not A Bug.
-               // To work around this weirdness, we use the IP_RECVIF option to find the name of the interface
-               // on which the packet arrived, and ignore the packet if it really arrived on some other interface.
-               if (strcmp(info->ifa_name, packetifname))
-                       {
-                       verbosedebugf("myCFSocketCallBack got a packet from %#a to %#a on interface %#a/%s (Ignored -- really arrived on interface %s)",
-                               &senderAddr, &destAddr, &info->ifinfo.ip, info->ifa_name, packetifname);
-                       return;
-                       }
-               else
-                       verbosedebugf("myCFSocketCallBack got a packet from %#a to %#a on interface %#a/%s",
-                               &senderAddr, &destAddr, &info->ifinfo.ip, info->ifa_name);
-               
-               if (err < (int)sizeof(DNSMessageHeader)) { debugf("myCFSocketCallBack packet length (%d) too short", err); return; }
-               
-               mDNSCoreReceive(m, &packet, (unsigned char*)&packet + err, &senderAddr, senderPort, &destAddr, destPort, info->ifinfo.InterfaceID, ttl);
-               }
-
-       if (err < 0 && (errno != EWOULDBLOCK || count == 0))
-               {
-               // Something is busted here.
-               // CFSocket says there is a packet, but myrecvfrom says there is not.
-               // Try calling select() to get another opinion.
-               // Find out about other socket parameter that can help understand why select() says the socket is ready for read
-               // All of this is racy, as data may have arrived after the call to select()
-               int save_errno = errno;
-               int so_error = -1;
-               int so_nread = -1;
-               int fionread = -1;
-               int solen = sizeof(int);
-               fd_set readfds;
-               FD_ZERO(&readfds);
-               FD_SET(s1, &readfds);
-               struct timeval timeout;
-               timeout.tv_sec  = 0;
-               timeout.tv_usec = 0;
-               int selectresult = select(s1+1, &readfds, NULL, NULL, &timeout);
-               if (getsockopt(s1, SOL_SOCKET, SO_ERROR, &so_error, &solen) == -1)
-                       LogMsg("myCFSocketCallBack getsockopt(SO_ERROR) error %d", errno);
-               if (getsockopt(s1, SOL_SOCKET, SO_NREAD, &so_nread, &solen) == -1)
-                       LogMsg("myCFSocketCallBack getsockopt(SO_NREAD) error %d", errno);
-               if (ioctl(s1, FIONREAD, &fionread) == -1)
-                       LogMsg("myCFSocketCallBack ioctl(FIONREAD) error %d", errno);
-               static unsigned int numLogMessages = 0;
-               if (numLogMessages++ < 100)
-                       LogMsg("myCFSocketCallBack recvfrom skt %d error %d errno %d (%s) select %d (%spackets waiting) so_error %d so_nread %d fionread %d count %d",
-                               s1, err, save_errno, strerror(save_errno), selectresult, FD_ISSET(s1, &readfds) ? "" : "*NO* ", so_error, so_nread, fionread, count);
-               sleep(1);               // After logging this error, rate limit so we don't flood syslog
-               }
-       }
-
-// This gets the text of the field currently labelled "Computer Name" in the Sharing Prefs Control Panel
-mDNSlocal void GetUserSpecifiedFriendlyComputerName(domainlabel *const namelabel)
-       {
-       CFStringEncoding encoding = kCFStringEncodingUTF8;
-       CFStringRef cfs = SCDynamicStoreCopyComputerName(NULL, &encoding);
-       if (cfs)
-               {
-               CFStringGetPascalString(cfs, namelabel->c, sizeof(*namelabel), kCFStringEncodingUTF8);
-               CFRelease(cfs);
-               }
-       }
-
-// This gets the text of the field currently labelled "Rendezvous Name" in the Sharing Prefs Control Panel
-mDNSlocal void GetUserSpecifiedRFC1034ComputerName(domainlabel *const namelabel)
-       {
-       CFStringRef cfs = SCDynamicStoreCopyLocalHostName(NULL);
-       if (cfs)
-               {
-               CFStringGetPascalString(cfs, namelabel->c, sizeof(*namelabel), kCFStringEncodingUTF8);
-               CFRelease(cfs);
-               }
-       }
-
-mDNSlocal mStatus SetupSocket(NetworkInterfaceInfoOSX *i, mDNSIPPort port, int *s, CFSocketRef *c)
-       {
-       const int on = 1;
-       const int twofivefive = 255;
-
-       if (*s >= 0) { LogMsg("SetupSocket ERROR: socket %d is already set", *s); return(-1); }
-       if (*c) { LogMsg("SetupSocket ERROR: CFSocketRef %p is already set", *c); return(-1); }
-
-       // Open the socket...
-       int skt = socket(i->sa_family, SOCK_DGRAM, IPPROTO_UDP);
-       if (skt < 0) { LogMsg("socket error %d errno %d (%s)", skt, errno, strerror(errno)); return(skt); }
-
-       // ... with a shared UDP port
-       mStatus err = setsockopt(skt, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on));
-       if (err < 0) { LogMsg("setsockopt - SO_REUSEPORT error %ld errno %d (%s)", err, errno, strerror(errno)); return(err); }
-
-       if (i->sa_family == AF_INET)
-               {
-               // We want to receive destination addresses
-               err = setsockopt(skt, IPPROTO_IP, IP_RECVDSTADDR, &on, sizeof(on));
-               if (err < 0) { LogMsg("setsockopt - IP_RECVDSTADDR error %ld errno %d (%s)", err, errno, strerror(errno)); return(err); }
-               
-               // We want to receive interface identifiers
-               err = setsockopt(skt, IPPROTO_IP, IP_RECVIF, &on, sizeof(on));
-               if (err < 0) { LogMsg("setsockopt - IP_RECVIF error %ld errno %d (%s)", err, errno, strerror(errno)); return(err); }
-               
-               // We want to receive packet TTL value so we can check it
-               err = setsockopt(skt, IPPROTO_IP, IP_RECVTTL, &on, sizeof(on));
-               // We ignore errors here -- we already know Jaguar doesn't support this, but we can get by without it
-               
-               // Add multicast group membership on this interface
-               struct in_addr addr = { i->ifinfo.ip.ip.v4.NotAnInteger };
-               struct ip_mreq imr;
-               imr.imr_multiaddr.s_addr = AllDNSLinkGroup.NotAnInteger;
-               imr.imr_interface        = addr;
-               err = setsockopt(skt, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(imr));
-               if (err < 0) { LogMsg("setsockopt - IP_ADD_MEMBERSHIP error %ld errno %d (%s)", err, errno, strerror(errno)); return(err); }
-               
-               // Specify outgoing interface too
-               err = setsockopt(skt, IPPROTO_IP, IP_MULTICAST_IF, &addr, sizeof(addr));
-               if (err < 0) { LogMsg("setsockopt - IP_MULTICAST_IF error %ld errno %d (%s)", err, errno, strerror(errno)); return(err); }
-               
-               // Send unicast packets with TTL 255
-               err = setsockopt(skt, IPPROTO_IP, IP_TTL, &twofivefive, sizeof(twofivefive));
-               if (err < 0) { LogMsg("setsockopt - IP_TTL error %ld errno %d (%s)", err, errno, strerror(errno)); return(err); }
-               
-               // And multicast packets with TTL 255 too
-               err = setsockopt(skt, IPPROTO_IP, IP_MULTICAST_TTL, &twofivefive, sizeof(twofivefive));
-               if (err < 0) { LogMsg("setsockopt - IP_MULTICAST_TTL error %ld errno %d (%s)", err, errno, strerror(errno)); return(err); }
-
-               // Mark packets as high-throughput/low-delay (i.e. lowest reliability) to get maximum 802.11 multicast rate
-               const int ip_tosbits = IPTOS_LOWDELAY | IPTOS_THROUGHPUT;
-               err = setsockopt(skt, IPPROTO_IP, IP_TOS, &ip_tosbits, sizeof(ip_tosbits));
-               if (err < 0) { LogMsg("setsockopt - IP_TOS error %ld errno %d (%s)", err, errno, strerror(errno)); return(err); }
-
-               // And start listening for packets
-               struct sockaddr_in listening_sockaddr;
-               listening_sockaddr.sin_family      = AF_INET;
-               listening_sockaddr.sin_port        = port.NotAnInteger;
-               listening_sockaddr.sin_addr.s_addr = 0; // Want to receive multicasts AND unicasts on this socket
-               err = bind(skt, (struct sockaddr *) &listening_sockaddr, sizeof(listening_sockaddr));
-               if (err)
-                       {
-                       // If we fail to bind to port 53 (because we're not root), that's okay, just tidy up and silently continue
-                       if (port.NotAnInteger == UnicastDNSPort.NotAnInteger) { close(skt); err = 0; }
-                       else LogMsg("bind error %ld errno %d (%s)", err, errno, strerror(errno));
-                       return(err);
-                       }
-               }
-       else if (i->sa_family == AF_INET6)
-               {
-               // We want to receive destination addresses and receive interface identifiers
-               err = setsockopt(skt, IPPROTO_IPV6, IPV6_PKTINFO, &on, sizeof(on));
-               if (err < 0) { LogMsg("setsockopt - IPV6_PKTINFO error %ld errno %d (%s)", err, errno, strerror(errno)); return(err); }
-               
-               // We want to receive packet hop count value so we can check it
-               err = setsockopt(skt, IPPROTO_IPV6, IPV6_HOPLIMIT, &on, sizeof(on));
-               if (err < 0) { LogMsg("setsockopt - IPV6_HOPLIMIT error %ld errno %d (%s)", err, errno, strerror(errno)); return(err); }
-               
-               // We want to receive only IPv6 packets, without this option, we may
-               // get IPv4 addresses as mapped addresses.
-               err = setsockopt(skt, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
-               if (err < 0) { LogMsg("setsockopt - IPV6_V6ONLY error %ld errno %d (%s)", err, errno, strerror(errno)); return(err); }
-               
-               // Add multicast group membership on this interface
-               int     interface_id = if_nametoindex(i->ifa_name);
-               struct ipv6_mreq i6mr;
-               i6mr.ipv6mr_interface = interface_id;
-               i6mr.ipv6mr_multiaddr = *(struct in6_addr*)&AllDNSLinkGroupv6;
-               err = setsockopt(skt, IPPROTO_IPV6, IPV6_JOIN_GROUP, &i6mr, sizeof(i6mr));
-               if (err < 0) { LogMsg("setsockopt - IPV6_JOIN_GROUP error %ld errno %d (%s)", err, errno, strerror(errno)); return(err); }
-               
-               // Specify outgoing interface too
-               err = setsockopt(skt, IPPROTO_IPV6, IPV6_MULTICAST_IF, &interface_id, sizeof(interface_id));
-               if (err < 0) { LogMsg("setsockopt - IPV6_MULTICAST_IF error %ld errno %d (%s)", err, errno, strerror(errno)); return(err); }
-               
-               // Send unicast packets with TTL 255
-               err = setsockopt(skt, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &twofivefive, sizeof(twofivefive));
-               if (err < 0) { LogMsg("setsockopt - IPV6_UNICAST_HOPS error %ld errno %d (%s)", err, errno, strerror(errno)); return(err); }
-               
-               // And multicast packets with TTL 255 too
-               err = setsockopt(skt, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &twofivefive, sizeof(twofivefive));
-               if (err < 0) { LogMsg("setsockopt - IPV6_MULTICAST_HOPS error %ld errno %d (%s)", err, errno, strerror(errno)); return(err); }
-               
-               // Note: IPV6_TCLASS appears not to be implemented on OS X right now (or indeed on ANY version of Unix?)
-               #ifdef IPV6_TCLASS
-               // Mark packets as high-throughput/low-delay (i.e. lowest reliability) to get maximum 802.11 multicast rate
-               int tclass = IPTOS_LOWDELAY | IPTOS_THROUGHPUT; // This may not be right (since tclass is not implemented on OS X, I can't test it)
-               err = setsockopt(skt, IPPROTO_IPV6, IPV6_TCLASS, &tclass, sizeof(tclass));
-               if (err < 0) { LogMsg("setsockopt - IPV6_TCLASS error %ld errno %d (%s)", err, errno, strerror(errno)); return(err); }
-               #endif
-               
-               // Want to receive our own packets
-               err = setsockopt(skt, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &on, sizeof(on));
-               if (err < 0) { LogMsg("setsockopt - IPV6_MULTICAST_LOOP error %ld errno %d (%s)", err, errno, strerror(errno)); return(err); }
-               
-               // And start listening for packets
-               struct sockaddr_in6 listening_sockaddr6;
-               bzero(&listening_sockaddr6, sizeof(listening_sockaddr6));
-               listening_sockaddr6.sin6_len             = sizeof(listening_sockaddr6);
-               listening_sockaddr6.sin6_family      = AF_INET6;
-               listening_sockaddr6.sin6_port        = port.NotAnInteger;
-               listening_sockaddr6.sin6_flowinfo        = 0;
-//             listening_sockaddr6.sin6_addr = IN6ADDR_ANY_INIT; // Want to receive multicasts AND unicasts on this socket
-               listening_sockaddr6.sin6_scope_id        = 0;
-               err = bind(skt, (struct sockaddr *) &listening_sockaddr6, sizeof(listening_sockaddr6));
-               if (err) { LogMsg("bind error %ld errno %d (%s)", err, errno, strerror(errno)); return(err); }
-               }
-       
-       fcntl(skt, F_SETFL, fcntl(skt, F_GETFL, 0) | O_NONBLOCK); // set non-blocking
-       *s = skt;
-       CFSocketContext myCFSocketContext = { 0, i->ifinfo.InterfaceID, NULL, NULL, NULL };
-       *c = CFSocketCreateWithNative(kCFAllocatorDefault, *s, kCFSocketReadCallBack, myCFSocketCallBack, &myCFSocketContext);
-       CFRunLoopSourceRef rls = CFSocketCreateRunLoopSource(kCFAllocatorDefault, *c, 0);
-       CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
-       CFRelease(rls);
-       
-       return(err);
-       }
-
-mDNSlocal mStatus SetupAddr(mDNSAddr *ip, const struct sockaddr *const sa)
-       {
-       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(0);
-               }
-       else 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.__u6_addr.__u6_addr16[1] = 0;
-               ip->ip.v6 = *(mDNSv6Addr*)&ifa_addr->sin6_addr;
-               return(0);
-               }
-       else
-               {
-               LogMsg("SetupAddr invalid sa_family %d", sa->sa_family);
-               return(-1);
-               }
-       }
-
-mDNSlocal mStatus AddInterfaceToList(mDNS *const m, struct ifaddrs *ifa)
-       {
-       mDNSu32 scope_id = if_nametoindex(ifa->ifa_name);
-       mDNSAddr ip;
-       SetupAddr(&ip, ifa->ifa_addr);
-       NetworkInterfaceInfoOSX **p;
-       for (p = &m->p->InterfaceList; *p; p = &(*p)->next)
-               if (scope_id == (*p)->scope_id && mDNSSameAddress(&ip, &(*p)->ifinfo.ip))
-                       {
-                       debugf("AddInterfaceToList: Found existing interface %u with address %#a", scope_id, &ip);
-                       (*p)->CurrentlyActive = mDNStrue;
-                       return(0);
-                       }
-
-       debugf("AddInterfaceToList: Making   new   interface %u with address %#a", scope_id, &ip);
-       NetworkInterfaceInfoOSX *i = (NetworkInterfaceInfoOSX *)mallocL("NetworkInterfaceInfoOSX", sizeof(*i));
-       if (!i) return(-1);
-       i->ifa_name        = (char *)mallocL("NetworkInterfaceInfoOSX name", strlen(ifa->ifa_name) + 1);
-       if (!i->ifa_name) { freeL("NetworkInterfaceInfoOSX", i); return(-1); }
-       strcpy(i->ifa_name, ifa->ifa_name);
-
-       i->ifinfo.InterfaceID = mDNSNULL;
-       i->ifinfo.ip          = ip;
-       i->ifinfo.Advertise   = m->AdvertiseLocalAddresses;
-       i->ifinfo.TxAndRx     = mDNSfalse;              // For now; will be set up later at the end of UpdateInterfaceList
-
-       i->next            = mDNSNULL;
-       i->m               = m;
-       i->scope_id        = scope_id;
-       i->CurrentlyActive = mDNStrue;
-       i->sa_family       = ifa->ifa_addr->sa_family;
-       #if mDNS_AllowPort53
-       i->skt53 = -1;
-       i->cfs53 = NULL;
-       #endif
-       i->sktv4 = -1;
-       i->cfsv4 = NULL;
-       i->sktv6 = -1;
-       i->cfsv6 = NULL;
-       
-       if (!i->ifa_name) return(-1);
-       *p = i;
-       return(0);
-       }
-
-mDNSlocal NetworkInterfaceInfoOSX *FindRoutableIPv4(mDNS *const m, mDNSu32 scope_id)
-       {
-       NetworkInterfaceInfoOSX *i;
-       for (i = m->p->InterfaceList; i; i = i->next)
-               if (i->CurrentlyActive && i->scope_id == scope_id && i->ifinfo.ip.type == mDNSAddrType_IPv4)
-                       if (!(i->ifinfo.ip.ip.v4.b[0] == 169 && i->ifinfo.ip.ip.v4.b[1] == 254))
-                               return(i);
-       return(mDNSNULL);
-       }
-
-mDNSlocal mStatus UpdateInterfaceList(mDNS *const m)
-       {
-       mDNSBool foundav4           = mDNSfalse;
-       struct ifaddrs *ifa         = myGetIfAddrs(1);
-       struct ifaddrs *theLoopback = NULL;
-       int err = (ifa != NULL) ? 0 : (errno != 0 ? errno : -1);
-       int InfoSocket              = err ? -1 : socket(AF_INET6, SOCK_DGRAM, 0);
-       if (err) return(err);
-
-       // Set up the nice label
-       m->nicelabel.c[0] = 0;
-       GetUserSpecifiedFriendlyComputerName(&m->nicelabel);
-       if (m->nicelabel.c[0] == 0) MakeDomainLabelFromLiteralString(&m->nicelabel, "Macintosh");
-
-       // Set up the RFC 1034-compliant label
-       domainlabel hostlabel;
-       hostlabel.c[0] = 0;
-       GetUserSpecifiedRFC1034ComputerName(&hostlabel);
-       if (hostlabel.c[0] == 0) MakeDomainLabelFromLiteralString(&hostlabel, "Macintosh");
-       // If the user has changed their dot-local host name since the last time we checked, then update our local copy.
-       // If the user has not changed their dot-local host name, then leave ours alone (m->hostlabel may have gone through
-       // repeated conflict resolution to get to its current value, and if we reset it, we'll have to go through all that again.)
-       if (SameDomainLabel(m->p->userhostlabel.c, hostlabel.c))
-               debugf("Userhostlabel (%#s) unchanged since last time; not changing m->hostlabel (%#s)", m->p->userhostlabel.c, m->hostlabel.c);
-       else
-               {
-               debugf("Updating m->hostlabel to %#s", hostlabel.c);
-               m->p->userhostlabel = m->hostlabel = hostlabel;
-               mDNS_GenerateFQDN(m);
-               }
-
-       while (ifa)
-               {
-#if LIST_ALL_INTERFACES
-               if (ifa->ifa_addr->sa_family == AF_APPLETALK)
-                       debugf("UpdateInterfaceList: %4s(%d) Flags %04X Family %2d is AF_APPLETALK",
-                               ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
-               else if (ifa->ifa_addr->sa_family == AF_LINK)
-                       debugf("UpdateInterfaceList: %4s(%d) Flags %04X Family %2d is AF_LINK",
-                               ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
-               else if (ifa->ifa_addr->sa_family != AF_INET && ifa->ifa_addr->sa_family != AF_INET6)
-                       debugf("UpdateInterfaceList: %4s(%d) Flags %04X Family %2d not AF_INET (2) or AF_INET6 (30)",
-                               ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
-               if (!(ifa->ifa_flags & IFF_UP))
-                       debugf("UpdateInterfaceList: %4s(%d) Flags %04X Family %2d Interface not IFF_UP",
-                               ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
-               if (ifa->ifa_flags & IFF_POINTOPOINT)
-                       debugf("UpdateInterfaceList: %4s(%d) Flags %04X Family %2d Interface IFF_POINTOPOINT",
-                               ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
-               if (ifa->ifa_flags & IFF_LOOPBACK)
-                       debugf("UpdateInterfaceList: %4s(%d) Flags %04X Family %2d Interface IFF_LOOPBACK",
-                               ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
-#endif
-               if ((ifa->ifa_addr->sa_family == AF_INET || ifa->ifa_addr->sa_family == AF_INET6) &&
-                       (ifa->ifa_flags & IFF_MULTICAST) &&
-                   (ifa->ifa_flags & IFF_UP) && !(ifa->ifa_flags & IFF_POINTOPOINT))
-                       {
-                       int     ifru_flags6 = 0;
-                       if (ifa->ifa_addr->sa_family == AF_INET6 && InfoSocket >= 0)
-                               {
-                               struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
-                               struct in6_ifreq ifr6;
-                               bzero((char *)&ifr6, sizeof(ifr6));
-                               strncpy(ifr6.ifr_name, ifa->ifa_name, sizeof(ifr6.ifr_name));
-                               ifr6.ifr_addr = *sin6;
-                               if (ioctl(InfoSocket, SIOCGIFAFLAG_IN6, &ifr6) != -1)
-                                       ifru_flags6 = ifr6.ifr_ifru.ifru_flags6;
-                               verbosedebugf("%s %.16a %04X %04X", ifa->ifa_name, &sin6->sin6_addr, ifa->ifa_flags, ifru_flags6);
-                               }
-                       if (!(ifru_flags6 & (IN6_IFF_NOTREADY | IN6_IFF_DETACHED | IN6_IFF_DEPRECATED | IN6_IFF_TEMPORARY)))
-                               {
-                               if (ifa->ifa_flags & IFF_LOOPBACK)
-                                       theLoopback = ifa;
-                               else
-                                       {
-                                       AddInterfaceToList(m, ifa);
-                                       if (ifa->ifa_addr->sa_family == AF_INET)
-                                               foundav4 = mDNStrue;
-                                       }
-                               }
-                       }
-               ifa = ifa->ifa_next;
-               }
-
-//     Temporary workaround: Multicast loopback on IPv6 interfaces appears not to work.
-//     In the interim, we skip loopback interface only if we found at least one v4 interface to use
-       if (!foundav4 && theLoopback)
-               AddInterfaceToList(m, theLoopback);
-
-       // Now the list is complete, set the TxAndRx setting for each interface.
-       // We always send and receive using IPv4.
-       // To reduce traffic, we send and receive using IPv6 only on interfaces that have no routable IPv4 address.
-       // Having a routable IPv4 address assigned is a reasonable indicator of being on a large configured network,
-       // which means there's a good chance that most or all the other devices on that network should also have v4.
-       // By doing this we lose the ability to talk to true v6-only devices on that link, but we cut the packet rate in half.
-       // At this time, reducing the packet rate is more important than v6-only devices on a large configured network,
-       // so we are willing to make that sacrifice.
-       NetworkInterfaceInfoOSX *i;
-       for (i = m->p->InterfaceList; i; i = i->next)
-               if (i->CurrentlyActive)
-                       {
-                       mDNSBool txrx = ((i->ifinfo.ip.type == mDNSAddrType_IPv4) || !FindRoutableIPv4(m, i->scope_id));
-                       if (i->ifinfo.TxAndRx != txrx)
-                               {
-                               i->ifinfo.TxAndRx = txrx;
-                               i->CurrentlyActive = 2; // State change; need to deregister and reregister this interface
-                               }
-                       }
-
-       if (InfoSocket >= 0) close(InfoSocket);
-       return(err);
-       }
-
-mDNSlocal NetworkInterfaceInfoOSX *SearchForInterfaceByName(mDNS *const m, char *ifname, int type)
-       {
-       NetworkInterfaceInfoOSX *i;
-       for (i = m->p->InterfaceList; i; i = i->next)
-               if (!strcmp(i->ifa_name, ifname) &&
-                       i->CurrentlyActive &&
-                       ((AAAA_OVER_V4                                              ) ||
-                        (type == AF_INET  && i->ifinfo.ip.type == mDNSAddrType_IPv4) ||
-                        (type == AF_INET6 && i->ifinfo.ip.type == mDNSAddrType_IPv6) )) return(i);
-       return(NULL);
-       }
-
-mDNSlocal void SetupActiveInterfaces(mDNS *const m)
-       {
-       NetworkInterfaceInfoOSX *i;
-       for (i = m->p->InterfaceList; i; i = i->next)
-               if (i->CurrentlyActive)
-                       {
-                       mStatus err = 0;
-                       NetworkInterfaceInfo *n = &i->ifinfo;
-                       NetworkInterfaceInfoOSX *alias = SearchForInterfaceByName(m, i->ifa_name, i->sa_family);
-                       if (!alias) alias = i;
-                       
-                       if (n->InterfaceID && n->InterfaceID != (mDNSInterfaceID)alias)
-                               {
-                               LogMsg("SetupActiveInterfaces ERROR! n->InterfaceID %p != alias %p", n->InterfaceID, alias);
-                               n->InterfaceID = mDNSNULL;
-                               }
-               
-                       if (!n->InterfaceID)
-                               {
-                               n->InterfaceID = (mDNSInterfaceID)alias;
-                               mDNS_RegisterInterface(m, n);
-                               debugf("SetupActiveInterfaces: Registered  %s(%lu) InterfaceID %p %#a%s",
-                                       i->ifa_name, i->scope_id, alias, &n->ip, n->InterfaceActive ? " (Primary)" : "");
-                               }
-               
-                       if (!n->TxAndRx)
-                               debugf("SetupActiveInterfaces: No TX/Rx on %s(%lu) InterfaceID %p %#a", i->ifa_name, i->scope_id, alias, &n->ip);
-                       else
-                               {
-                               if (i->sa_family == AF_INET && alias->sktv4 == -1)
-                                       {
-                                       #if mDNS_AllowPort53
-                                       err = SetupSocket(i, UnicastDNSPort, &alias->skt53, &alias->cfs53);
-                                       #endif
-                                       if (!err) err = SetupSocket(i, MulticastDNSPort, &alias->sktv4, &alias->cfsv4);
-                                       if (err == 0) debugf("SetupActiveInterfaces: v4 socket%2d %s(%lu) InterfaceID %p %#a", alias->sktv4, i->ifa_name, i->scope_id, n->InterfaceID, &n->ip);
-                                       else LogMsg("SetupActiveInterfaces: v4 socket%2d %s(%lu) InterfaceID %p %#a FAILED",   alias->sktv4, i->ifa_name, i->scope_id, n->InterfaceID, &n->ip);
-                                       }
-                       
-                               if (i->sa_family == AF_INET6 && alias->sktv6 == -1)
-                                       {
-                                       err = SetupSocket(i, MulticastDNSPort, &alias->sktv6, &alias->cfsv6);
-                                       if (err == 0) debugf("SetupActiveInterfaces: v6 socket%2d %s(%lu) InterfaceID %p %#a", alias->sktv6, i->ifa_name, i->scope_id, n->InterfaceID, &n->ip);
-                                       else LogMsg("SetupActiveInterfaces: v6 socket%2d %s(%lu) InterfaceID %p %#a FAILED",   alias->sktv6, i->ifa_name, i->scope_id, n->InterfaceID, &n->ip);
-                                       }
-                               }
-                       }
-       }
-
-mDNSlocal void MarkAllInterfacesInactive(mDNS *const m)
-       {
-       NetworkInterfaceInfoOSX *i;
-       for (i = m->p->InterfaceList; i; i = i->next)
-               i->CurrentlyActive = mDNSfalse;
-       }
-
-mDNSlocal mDNSu32 NumCacheRecordsForInterfaceID(mDNS *const m, mDNSInterfaceID id)
-       {
-       mDNSu32 slot, used = 0;
-       CacheRecord *rr;
-       for (slot = 0; slot < CACHE_HASH_SLOTS; slot++)
-               for (rr = m->rrcache_hash[slot]; rr; rr=rr->next)
-                       if (rr->resrec.InterfaceID == id) used++;
-       return(used);
-       }
-
-mDNSlocal void ClearInactiveInterfaces(mDNS *const m)
-       {
-       // First pass:
-       // If an interface is going away, then deregister this from the mDNSCore.
-       // We also have to deregister it if the alias 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: 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.)
-       NetworkInterfaceInfoOSX *i;
-       for (i = m->p->InterfaceList; i; i = i->next)
-               {
-               // 1. If this interface is no longer active, or its InterfaceID is changing, deregister it
-               NetworkInterfaceInfoOSX *alias = (NetworkInterfaceInfoOSX *)(i->ifinfo.InterfaceID);
-               NetworkInterfaceInfoOSX *newalias = SearchForInterfaceByName(m, i->ifa_name, i->sa_family);
-               if (!newalias) newalias = i;
-               if (i->ifinfo.InterfaceID && (!i->CurrentlyActive || (alias && !alias->CurrentlyActive) || i->CurrentlyActive == 2 || newalias != alias))
-                       {
-                       debugf("ClearInactiveInterfaces: Deregistering %#a", &i->ifinfo.ip);
-                       mDNS_DeregisterInterface(m, &i->ifinfo);
-                       i->ifinfo.InterfaceID = mDNSNULL;
-                       }
-               }
-
-       // Second pass:
-       // Now that everything that's going to deregister has done so, we can close sockets and free the memory
-       NetworkInterfaceInfoOSX **p = &m->p->InterfaceList;
-       while (*p)
-               {
-               i = *p;
-               // 2. Close all our CFSockets. We'll recreate them later as necessary.
-               // (We may have previously had both v4 and v6, and we may not need both any more.)
-               // Note: MUST NOT close the underlying native BSD sockets.
-               // CFSocketInvalidate() will do that for us, in its own good time, which may not necessarily be immediately,
-               // because it first has to unhook the sockets from its select() call, before it can safely close them.
-               #if mDNS_AllowPort53
-               if (i->cfs53) { CFSocketInvalidate(i->cfs53); CFRelease(i->cfs53); }
-               i->skt53 = -1;
-               i->cfs53 = NULL;
-               #endif
-               if (i->cfsv4) { CFSocketInvalidate(i->cfsv4); CFRelease(i->cfsv4); }
-               if (i->cfsv6) { CFSocketInvalidate(i->cfsv6); CFRelease(i->cfsv6); }
-               i->sktv4 = i->sktv6 = -1;
-               i->cfsv4 = i->cfsv6 = NULL;
-
-               // 3. If no longer active, delete interface from list and free memory
-               if (!i->CurrentlyActive && NumCacheRecordsForInterfaceID(m, (mDNSInterfaceID)i) == 0)
-                       {
-                       debugf("ClearInactiveInterfaces: Deleting      %#a", &i->ifinfo.ip);
-                       *p = i->next;
-                       if (i->ifa_name) freeL("NetworkInterfaceInfoOSX name", i->ifa_name);
-                       freeL("NetworkInterfaceInfoOSX", i);
-                       }
-               else
-                       p = &i->next;
-               }
-       }
-
-mDNSlocal void NetworkChanged(SCDynamicStoreRef store, CFArrayRef changedKeys, void *context)
-       {
-       (void)store;            // Parameter not used
-       (void)changedKeys;      // Parameter not used
-       debugf("***   Network Configuration Change   ***");
-
-       mDNS *const m = (mDNS *const)context;
-       MarkAllInterfacesInactive(m);
-       UpdateInterfaceList(m);
-       ClearInactiveInterfaces(m);
-       SetupActiveInterfaces(m);
-       
-       if (m->MainCallback)
-               m->MainCallback(m, mStatus_ConfigChanged);
-       }
-
-mDNSlocal mStatus WatchForNetworkChanges(mDNS *const m)
-       {
-       mStatus err = -1;
-       SCDynamicStoreContext context = { 0, m, NULL, NULL, NULL };
-       SCDynamicStoreRef     store    = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder"), NetworkChanged, &context);
-       CFStringRef           key1     = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv4);
-       CFStringRef           key2     = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv6);
-       CFStringRef           key3     = SCDynamicStoreKeyCreateComputerName(NULL);
-       CFStringRef           key4     = SCDynamicStoreKeyCreateHostNames(NULL);
-       CFStringRef           pattern1 = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv4);
-       CFStringRef           pattern2 = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv6);
-
-       CFMutableArrayRef     keys     = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
-       CFMutableArrayRef     patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
-
-       if (!store) { LogMsg("SCDynamicStoreCreate failed: %s\n", SCErrorString(SCError())); goto error; }
-       if (!key1 || !key2 || !key3 || !key4 || !keys || !pattern1 || !pattern2 || !patterns) goto error;
-
-       CFArrayAppendValue(keys, key1);
-       CFArrayAppendValue(keys, key2);
-       CFArrayAppendValue(keys, key3);
-       CFArrayAppendValue(keys, key4);
-       CFArrayAppendValue(patterns, pattern1);
-       CFArrayAppendValue(patterns, pattern2);
-       if (!SCDynamicStoreSetNotificationKeys(store, keys, patterns))
-               { LogMsg("SCDynamicStoreSetNotificationKeys failed: %s\n", SCErrorString(SCError())); goto error; }
-
-       m->p->StoreRLS = SCDynamicStoreCreateRunLoopSource(NULL, store, 0);
-       if (!m->p->StoreRLS) { LogMsg("SCDynamicStoreCreateRunLoopSource failed: %s\n", SCErrorString(SCError())); goto error; }
-
-       CFRunLoopAddSource(CFRunLoopGetCurrent(), m->p->StoreRLS, kCFRunLoopDefaultMode);
-       m->p->Store = store;
-       err = 0;
-       goto exit;
-
-error:
-       if (store)    CFRelease(store);
-
-exit:
-       if (key1)     CFRelease(key1);
-       if (key2)     CFRelease(key2);
-       if (key3)     CFRelease(key3);
-       if (key4)     CFRelease(key4);
-       if (pattern1) CFRelease(pattern1);
-       if (pattern2) CFRelease(pattern2);
-       if (keys)     CFRelease(keys);
-       if (patterns) CFRelease(patterns);
-       
-       return(err);
-       }
-
-mDNSlocal void PowerChanged(void *refcon, io_service_t service, natural_t messageType, void *messageArgument)
-       {
-       mDNS *const m = (mDNS *const)refcon;
-       (void)service;          // Parameter not used
-       switch(messageType)
-               {
-               case kIOMessageCanSystemPowerOff:     debugf("PowerChanged kIOMessageCanSystemPowerOff (no action)");                      break; // E0000240
-               case kIOMessageSystemWillPowerOff:    debugf("PowerChanged kIOMessageSystemWillPowerOff"); mDNSCoreMachineSleep(m, true);  break; // E0000250
-               case kIOMessageSystemWillNotPowerOff: debugf("PowerChanged kIOMessageSystemWillNotPowerOff (no action)");                  break; // E0000260
-               case kIOMessageCanSystemSleep:        debugf("PowerChanged kIOMessageCanSystemSleep (no action)");                         break; // E0000270
-               case kIOMessageSystemWillSleep:       debugf("PowerChanged kIOMessageSystemWillSleep");    mDNSCoreMachineSleep(m, true);  break; // E0000280
-               case kIOMessageSystemWillNotSleep:    debugf("PowerChanged kIOMessageSystemWillNotSleep (no action)");                     break; // E0000290
-               case kIOMessageSystemHasPoweredOn:    debugf("PowerChanged kIOMessageSystemHasPoweredOn"); mDNSCoreMachineSleep(m, false); break; // E0000300
-               default:                              debugf("PowerChanged unknown message %X", messageType);                              break;
-               }
-       IOAllowPowerChange(m->p->PowerConnection, (long)messageArgument);
-       }
-
-mDNSlocal mStatus WatchForPowerChanges(mDNS *const m)
-       {
-       IONotificationPortRef thePortRef;
-       m->p->PowerConnection = IORegisterForSystemPower(m, &thePortRef, PowerChanged, &m->p->PowerNotifier);
-       if (m->p->PowerConnection)
-               {
-               m->p->PowerRLS = IONotificationPortGetRunLoopSource(thePortRef);
-               CFRunLoopAddSource(CFRunLoopGetCurrent(), m->p->PowerRLS, kCFRunLoopDefaultMode);
-               return(mStatus_NoError);
-               }
-       return(-1);
-       }
-
-CF_EXPORT CFDictionaryRef _CFCopySystemVersionDictionary(void);
-CF_EXPORT const CFStringRef _kCFSystemVersionProductNameKey;
-CF_EXPORT const CFStringRef _kCFSystemVersionProductVersionKey;
-CF_EXPORT const CFStringRef _kCFSystemVersionBuildVersionKey;          
-
-mDNSexport mDNSBool mDNSMacOSXSystemBuildNumber(char *HINFO_SWstring)
-       {
-       int major = 0, minor = 0;
-       char letter = 0, prodname[256]="Mac OS X", prodvers[256]="", buildver[256]="?";
-       CFDictionaryRef vers = _CFCopySystemVersionDictionary();
-       if (vers)
-               {
-               CFStringRef cfprodname = CFDictionaryGetValue(vers, _kCFSystemVersionProductNameKey);
-               CFStringRef cfprodvers = CFDictionaryGetValue(vers, _kCFSystemVersionProductVersionKey);
-               CFStringRef cfbuildver = CFDictionaryGetValue(vers, _kCFSystemVersionBuildVersionKey);
-               if (cfprodname) CFStringGetCString(cfprodname, prodname, sizeof(prodname), kCFStringEncodingUTF8);
-               if (cfprodvers) CFStringGetCString(cfprodvers, prodvers, sizeof(prodvers), kCFStringEncodingUTF8);
-               if (cfbuildver) CFStringGetCString(cfbuildver, buildver, sizeof(buildver), kCFStringEncodingUTF8);
-               sscanf(buildver, "%d%c%d", &major, &letter, &minor);
-               CFRelease(vers);
-               }
-       if (HINFO_SWstring) mDNS_snprintf(HINFO_SWstring, 256, "%s %s (%s), %s", prodname, prodvers, buildver, mDNSResponderVersionString);
-       return(major);
-       }
-
-mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m)
-       {
-       mStatus err;
-
-       m->hostlabel.c[0]        = 0;
-
-       char *HINFO_HWstring = "Macintosh";
-       char HINFO_HWstring_buffer[256];
-       int    get_model[2] = { CTL_HW, HW_MODEL };
-       size_t len_model = sizeof(HINFO_HWstring_buffer);
-       if (sysctl(get_model, 2, HINFO_HWstring_buffer, &len_model, NULL, 0) == 0)
-               HINFO_HWstring = HINFO_HWstring_buffer;
-
-       char HINFO_SWstring[256] = "";
-       if (mDNSMacOSXSystemBuildNumber(HINFO_SWstring) < 7) m->KnownBugs = mDNS_KnownBug_PhantomInterfaces;
-
-       mDNSu32 hlen = mDNSPlatformStrLen(HINFO_HWstring);
-       mDNSu32 slen = mDNSPlatformStrLen(HINFO_SWstring);
-       if (hlen + slen < 254)
-               {
-               m->HIHardware.c[0] = hlen;
-               m->HISoftware.c[0] = slen;
-               mDNSPlatformMemCopy(HINFO_HWstring, &m->HIHardware.c[1], hlen);
-               mDNSPlatformMemCopy(HINFO_SWstring, &m->HISoftware.c[1], slen);
-               }
-
-       m->p->InterfaceList      = mDNSNULL;
-       m->p->userhostlabel.c[0] = 0;
-       UpdateInterfaceList(m);
-       SetupActiveInterfaces(m);
-
-       err = WatchForNetworkChanges(m);
-       if (err) return(err);
-       
-       err = WatchForPowerChanges(m);
-       return(err);
-       }
-
-mDNSexport mStatus mDNSPlatformInit(mDNS *const m)
-       {
-       mStatus result = mDNSPlatformInit_setup(m);
-       // We don't do asynchronous initialization on OS X, so by the time we get here the setup will already
-       // have succeeded or failed -- so if it succeeded, we should just call mDNSCoreInitComplete() immediately
-       if (result == mStatus_NoError) mDNSCoreInitComplete(m, mStatus_NoError);
-       return(result);
-       }
-
-mDNSexport void mDNSPlatformClose(mDNS *const m)
-       {
-       if (m->p->PowerConnection)
-               {
-               CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m->p->PowerRLS, kCFRunLoopDefaultMode);
-               CFRunLoopSourceInvalidate(m->p->PowerRLS);
-               CFRelease(m->p->PowerRLS);
-               IODeregisterForSystemPower(&m->p->PowerNotifier);
-               m->p->PowerConnection = NULL;
-               m->p->PowerNotifier   = NULL;
-               m->p->PowerRLS        = NULL;
-               }
-       
-       if (m->p->Store)
-               {
-               CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m->p->StoreRLS, kCFRunLoopDefaultMode);
-               CFRunLoopSourceInvalidate(m->p->StoreRLS);
-               CFRelease(m->p->StoreRLS);
-               CFRelease(m->p->Store);
-               m->p->Store    = NULL;
-               m->p->StoreRLS = NULL;
-               }
-       
-       MarkAllInterfacesInactive(m);
-       ClearInactiveInterfaces(m);
-       }
-
-mDNSexport mDNSs32  mDNSPlatformOneSecond = 1000;
-
-mDNSexport mStatus mDNSPlatformTimeInit(mDNSs32 *timenow)
-       {
-       // Notes: Typical values for mach_timebase_info:
-       // tbi.numer = 1000 million
-       // tbi.denom =   33 million
-       // These are set such that (mach_absolute_time() * numer/denom) gives us nanoseconds;
-       //          numer  / denom = nanoseconds per hardware clock tick (e.g. 30);
-       //          denom  / numer = hardware clock ticks per nanosecond (e.g. 0.033)
-       // (denom*1000000) / numer = hardware clock ticks per millisecond (e.g. 33333)
-       // So: mach_absolute_time() / ((denom*1000000)/numer) = milliseconds
-       //
-       // Arithmetic notes:
-       // tbi.denom is at least 1, and not more than 2^32-1.
-       // Therefore (tbi.denom * 1000000) is at least one million, but cannot overflow a uint64_t.
-       // tbi.denom is at least 1, and not more than 2^32-1.
-       // Therefore clockdivisor should end up being a number roughly in the range 10^3 - 10^9.
-       // If clockdivisor is less than 10^3 then that means that the native clock frequency is less than 1MHz,
-       // which is unlikely on any current or future Macintosh.
-       // If clockdivisor is greater than 10^9 then that means the native clock frequency is greater than 1000GHz.
-       // When we ship Macs with clock frequencies above 1000GHz, we may have to update this code.
-       struct mach_timebase_info tbi;
-       kern_return_t result = mach_timebase_info(&tbi);
-       if (result != KERN_SUCCESS) return(result);
-       clockdivisor = ((uint64_t)tbi.denom * 1000000) / tbi.numer;
-       *timenow = mDNSPlatformTimeNow();
-       return(mStatus_NoError);
-       }
-
-mDNSexport mDNSs32  mDNSPlatformTimeNow(void)
-       {
-       if (clockdivisor == 0) { LogMsg("mDNSPlatformTimeNow called before mDNSPlatformTimeInit"); return(0); }
-       return((mDNSs32)(mach_absolute_time() / clockdivisor));
-       }
-
-// Locking is a no-op here, because we're single-threaded with a CFRunLoop, so we can never interrupt ourselves
-mDNSexport void     mDNSPlatformLock   (const mDNS *const m) { (void)m; }
-mDNSexport void     mDNSPlatformUnlock (const mDNS *const m) { (void)m; }
-mDNSexport void     mDNSPlatformStrCopy(const void *src,       void *dst)              { strcpy((char *)dst, (char *)src); }
-mDNSexport mDNSu32  mDNSPlatformStrLen (const void *src)                               { return(strlen((char*)src)); }
-mDNSexport void     mDNSPlatformMemCopy(const void *src,       void *dst, mDNSu32 len) { memcpy(dst, src, len); }
-mDNSexport mDNSBool mDNSPlatformMemSame(const void *src, const void *dst, mDNSu32 len) { return(memcmp(dst, src, len) == 0); }
-mDNSexport void     mDNSPlatformMemZero(                       void *dst, mDNSu32 len) { bzero(dst, len); }
-mDNSexport void *   mDNSPlatformMemAllocate(mDNSu32 len) { return(mallocL("mDNSPlatformMemAllocate", len)); }
-mDNSexport void     mDNSPlatformMemFree    (void *mem)   { freeL("mDNSPlatformMemFree", mem); }
index b255cd0166c66b75bcc5271e878c3e38c6163833..ba07125a80feb776d4b2625fc9f0a6e4f1ec7caf 100644 (file)
@@ -3,6 +3,8 @@
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
     Change History (most recent first):
 
 $Log: mDNSMacOSX.h,v $
+Revision 1.37  2004/06/04 08:58:30  ksekar
+<rdar://problem/3668624>: Keychain integration for secure dynamic update
+
+Revision 1.36  2004/05/26 17:06:33  cheshire
+<rdar://problem/3668515>: Don't rely on CFSocketInvalidate() to remove RunLoopSource
+
+Revision 1.35  2004/05/18 23:51:26  cheshire
+Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
+
+Revision 1.34  2004/05/12 22:03:09  ksekar
+Made GetSearchDomainList a true platform-layer call (declaration moved
+from mDNSMacOSX.h to mDNSClientAPI.h), impelemted to return "local"
+only on non-OSX platforms.  Changed call to return a copy of the list
+to avoid shared memory issues.  Added a routine to free the list.
+
+Revision 1.33  2004/05/12 02:03:25  ksekar
+Non-local domains will only be browsed by default, and show up in
+_browse domain enumeration, if they contain an _browse._dns-sd ptr record.
+
+Revision 1.32  2004/04/21 02:20:47  cheshire
+Rename interface field 'CurrentlyActive' to more descriptive 'Exists'
+
+Revision 1.31  2004/04/09 17:40:26  cheshire
+Remove unnecessary "Multicast" field -- it duplicates the semantics of the existing TxAndRx field
+
+Revision 1.30  2004/01/28 02:30:08  ksekar
+Added default Search Domains to unicast browsing, controlled via
+Networking sharing prefs pane.  Stopped sending unicast messages on
+every interface.  Fixed unicast resolving via mach-port API.
+
+Revision 1.29  2004/01/27 22:57:48  cheshire
+<rdar://problem/3534352>: Need separate socket for issuing unicast queries
+
+Revision 1.28  2004/01/27 20:15:23  cheshire
+<rdar://problem/3541288>: Time to prune obsolete code for listening on port 53
+
+Revision 1.27  2004/01/24 08:46:26  bradley
+Added InterfaceID<->Index platform interfaces since they are now used by all platforms for the DNS-SD APIs.
+
+Revision 1.26  2003/12/08 21:00:46  rpantos
+Changes to support mDNSResponder on Linux.
+
+Revision 1.25  2003/11/08 22:18:29  cheshire
+<rdar://problem/3477870>: Don't need to show process ID in *every* mDNSResponder syslog message
+
+Revision 1.24  2003/11/08 22:13:00  cheshire
+Move extern declarations inside '#ifdef __cplusplus extern "C" {' section
+
+Revision 1.23  2003/09/23 16:38:25  cheshire
+When LogAllOperations is false, treat LogOperation() like debugf()
+(i.e. show in debug builds), rather than unconditionally ignoring
+
+Revision 1.22  2003/09/23 02:12:43  cheshire
+Also include port number in list of services registered via new UDS API
+
 Revision 1.21  2003/08/19 22:20:00  cheshire
 <rdar://problem/3376721> Don't use IPv6 on interfaces that have a routable IPv4 address configured
 More minor refinements
@@ -46,8 +103,7 @@ Revision 1.15  2003/08/05 00:32:28  cheshire
 <rdar://problem/3326712> Time to turn off MACOSX_MDNS_MALLOC_DEBUGGING
 
 Revision 1.14  2003/07/20 03:38:51  ksekar
-Bug #: 3320722
-Completed support for Unix-domain socket based API.
+<rdar://problem/3320722> Completed support for Unix-domain socket based API.
 
 Revision 1.13  2003/07/18 00:30:00  cheshire
 <rdar://problem/3268878> Remove mDNSResponder version from packet header and use HINFO record instead
@@ -60,7 +116,7 @@ Revision 1.11  2003/07/02 21:19:51  cheshire
 <rdar://problem/3313413> Update copyright notices, etc., in source code comments
 
 Revision 1.10  2003/06/25 23:42:19  ksekar
-Bug #: <rdar://problem/3249292>: Feature: New Rendezvous APIs (#7875)
+<rdar://problem/3249292>: Feature: New Rendezvous APIs (#7875)
 Reviewed by: Stuart Cheshire
 Added files necessary to implement Unix domain sockets based enhanced
 Rendezvous APIs, and integrated with existing Mach-port based daemon.
@@ -80,13 +136,13 @@ Revision 1.7  2003/04/26 02:39:24  cheshire
 Remove extern void LogMsg(const char *format, ...);
 
 Revision 1.6  2003/03/05 21:59:56  cheshire
-Bug #: 3189097 Additional debugging code in mDNSResponder
+<rdar://problem/3189097> Additional debugging code in mDNSResponder
 
 Revision 1.5  2003/03/05 01:50:38  cheshire
-Bug #: 3189097 Additional debugging code in mDNSResponder
+<rdar://problem/3189097> Additional debugging code in mDNSResponder
 
 Revision 1.4  2003/02/21 01:54:10  cheshire
-Bug #: 3099194 mDNSResponder needs performance improvements
+<rdar://problem/3099194> mDNSResponder needs performance improvements
 Switched to using new "mDNS_Execute" model (see "Implementer Notes.txt")
 
 Revision 1.3  2002/09/21 20:44:51  zarzycki
@@ -111,30 +167,40 @@ Defines mDNS_PlatformSupport_struct for OS X
 #include <IOKit/pwr_mgt/IOPMLib.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
+#include "mDNSClientAPI.h"  // for domain name structure
+       
 
 typedef struct NetworkInterfaceInfoOSX_struct NetworkInterfaceInfoOSX;
+
+typedef struct
+       {
+       mDNS                    *m;
+       NetworkInterfaceInfoOSX *info;
+       int                      sktv4;
+       CFSocketRef              cfsv4;
+       CFRunLoopSourceRef       rlsv4;
+       int                      sktv6;
+       CFSocketRef                  cfsv6;
+       CFRunLoopSourceRef       rlsv6;
+       } CFSocketSet;
+
 struct NetworkInterfaceInfoOSX_struct
        {
        NetworkInterfaceInfo     ifinfo;                        // MUST be the first element in this structure
        NetworkInterfaceInfoOSX *next;
-       mDNS                    *m;
-       mDNSu32                  CurrentlyActive;       // 0 not active; 1 active; 2 active but TxRx state changed
+       mDNSu32                  Exists;                        // 1 = currently exists in getifaddrs list; 0 = doesn't
+                                                                                               // 2 = exists, but McastTxRx state changed
        char                    *ifa_name;                      // Memory for this is allocated using malloc
        mDNSu32                  scope_id;                      // interface index / IPv6 scope ID
        u_short                  sa_family;
-#if mDNS_AllowPort53
-       int                      skt53;
-       CFSocketRef              cfs53;
-#endif
-       int                      sktv4;
-       CFSocketRef              cfsv4;
-       int                      sktv6;
-       CFSocketRef                  cfsv6;
+       mDNSBool                 Multicast;
+       CFSocketSet              ss;
        };
 
 struct mDNS_PlatformSupport_struct
     {
     NetworkInterfaceInfoOSX *InterfaceList;
+    CFSocketSet              unicastsockets;
     domainlabel              userhostlabel;
     SCDynamicStoreRef        Store;
     CFRunLoopSourceRef       StoreRLS;
@@ -143,50 +209,12 @@ struct mDNS_PlatformSupport_struct
     CFRunLoopSourceRef       PowerRLS;
     };
 
-extern mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(const mDNS *const m, mDNSu32 index);
-extern mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(const mDNS *const m, mDNSInterfaceID id);
 extern mDNSBool mDNSMacOSXSystemBuildNumber(char *HINFO_SWstring);
 
 extern const char mDNSResponderVersionString[];
 
-// Set this symbol to 1 to do extra debug checks on malloc() and free()
-// Set this symbol to 2 to write a log message for every malloc() and free()
-#define MACOSX_MDNS_MALLOC_DEBUGGING 0
-
-#if MACOSX_MDNS_MALLOC_DEBUGGING >= 1
-extern void *mallocL(char *msg, unsigned int size);
-extern void freeL(char *msg, void *x);
-#else
-#define mallocL(X,Y) malloc(Y)
-#define freeL(X,Y) free(Y)
-#endif
-
-#if MACOSX_MDNS_MALLOC_DEBUGGING >= 2
-#define LogMalloc LogMsg
-#else
-#define        LogMalloc(ARGS...) ((void)0)
-#endif
-
-#define LogAllOperations 0
-
-#if LogAllOperations
-#define LogOperation LogMsg
-#else
-#define        LogOperation(ARGS...) ((void)0)
-#endif
-
 #ifdef  __cplusplus
     }
 #endif
 
-// UDS Server <-> daemon crossover routines/globals
-extern mDNS mDNSStorage;            
-extern int udsserver_init(void);
-extern int udsserver_add_rl_source(void);
-extern mDNSs32 udsserver_idle(mDNSs32 nextevent);  // takes the next scheduled event time, does idle work,
-                                                   // and returns the updated nextevent time
-extern void udsserver_info(void);
-extern void udsserver_handle_configchange(void);
-extern int udsserver_exit(void);
-
 #endif
diff --git a/mDNSMacOSX/mDNSMacOSXPuma.c b/mDNSMacOSX/mDNSMacOSXPuma.c
deleted file mode 100644 (file)
index a23179d..0000000
+++ /dev/null
@@ -1,238 +0,0 @@
-/*
- * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- * 
- * @APPLE_LICENSE_HEADER_END@
- *
- * This file is not normally used.
- * It can be conditionally compiled in by defining RUN_ON_PUMA_WITHOUT_IFADDRS
- * in CFSocket.c. It is included mainly as sample code for people building
- * for other platforms that (like Puma) lack the getifaddrs() call.
- * NOTE: YOU CANNOT use this code to build an mDNSResponder daemon for Puma
- * that works just like the Jaguar one, because Puma lacks other necessary
- * functionality (like the LibInfo support to receive MIG messages from clients).
-
-    Change History (most recent first):
-
-$Log: mDNSMacOSXPuma.c,v $
-Revision 1.4  2003/08/12 19:56:25  cheshire
-Update to APSL 2.0
-
-Revision 1.3  2003/07/02 21:19:51  cheshire
-<rdar://problem/3313413> Update copyright notices, etc., in source code comments
-
-Revision 1.2  2002/09/21 20:44:51  zarzycki
-Added APSL info
-
-Revision 1.1  2002/09/17 01:36:23  cheshire
-Move Puma support to CFSocketPuma.c
-
- */
-
-#include <sys/ioctl.h>
-#include <sys/sockio.h>
-#define ifaddrs ifa_info
-#ifndef        ifa_broadaddr
-#define        ifa_broadaddr   ifa_dstaddr     /* broadcast address interface */
-#endif
-#include <sys/cdefs.h>
-
-/* Our own header for the programs that need interface configuration info.
-   Include this file, instead of "unp.h". */
-
-#define        IFA_NAME        16                      /* same as IFNAMSIZ in <net/if.h> */
-#define        IFA_HADDR        8                      /* allow for 64-bit EUI-64 in future */
-
-struct ifa_info {
-  char    ifa_name[IFA_NAME];  /* interface name, null terminated */
-  u_char  ifa_haddr[IFA_HADDR];        /* hardware address */
-  u_short ifa_hlen;                            /* #bytes in hardware address: 0, 6, 8 */
-  short   ifa_flags;                   /* IFF_xxx constants from <net/if.h> */
-  short   ifa_myflags;                 /* our own IFI_xxx flags */
-  struct sockaddr  *ifa_addr;  /* primary address */
-  struct sockaddr  *ifa_brdaddr;/* broadcast address */
-  struct sockaddr  *ifa_dstaddr;/* destination address */
-  struct ifa_info  *ifa_next;  /* next of these structures */
-};
-
-#define        IFI_ALIAS       1                       /* ifa_addr is an alias */
-
-                                       /* function prototypes */
-struct ifa_info        *get_ifa_info(int, int);
-struct ifa_info        *Get_ifa_info(int, int);
-void                    free_ifa_info(struct ifa_info *);
-
-#define HAVE_SOCKADDR_SA_LEN   1
-
-struct ifa_info *
-get_ifa_info(int family, int doaliases)
-{
-       struct ifa_info         *ifi, *ifihead, **ifipnext;
-       int                                     sockfd, len, lastlen, flags, myflags;
-       char                            *ptr, *buf, lastname[IFNAMSIZ], *cptr;
-       struct ifconf           ifc;
-       struct ifreq            *ifr, ifrcopy;
-       struct sockaddr_in      *sinptr;
-
-       sockfd = socket(AF_INET, SOCK_DGRAM, 0);
-
-       lastlen = 0;
-       len = 100 * sizeof(struct ifreq);       /* initial buffer size guess */
-       for ( ; ; ) {
-               buf = (char *) malloc(len);
-               ifc.ifc_len = len;
-               ifc.ifc_buf = buf;
-               if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) {
-                       if (errno != EINVAL || lastlen != 0)
-                               debugf("ioctl error");
-               } else {
-                       if (ifc.ifc_len == lastlen)
-                               break;          /* success, len has not changed */
-                       lastlen = ifc.ifc_len;
-               }
-               len += 10 * sizeof(struct ifreq);       /* increment */
-               free(buf);
-       }
-       ifihead = NULL;
-       ifipnext = &ifihead;
-       lastname[0] = 0;
-/* end get_ifa_info1 */
-
-/* include get_ifa_info2 */
-       for (ptr = buf; ptr < buf + ifc.ifc_len; ) {
-               ifr = (struct ifreq *) ptr;
-
-#ifdef HAVE_SOCKADDR_SA_LEN
-               len = MAX(sizeof(struct sockaddr), ifr->ifr_addr.sa_len);
-#else
-               switch (ifr->ifr_addr.sa_family) {
-#ifdef IPV6
-               case AF_INET6:  
-                       len = sizeof(struct sockaddr_in6);
-                       break;
-#endif
-               case AF_INET:   
-               default:        
-                       len = sizeof(struct sockaddr);
-                       break;
-               }
-#endif /* HAVE_SOCKADDR_SA_LEN */
-               ptr += sizeof(ifr->ifr_name) + len;     /* for next one in buffer */
-
-               if (ifr->ifr_addr.sa_family != family)
-                       continue;       /* ignore if not desired address family */
-
-               myflags = 0;
-               if ( (cptr = strchr(ifr->ifr_name, ':')) != NULL)
-                       *cptr = 0;              /* replace colon will null */
-               if (strncmp(lastname, ifr->ifr_name, IFNAMSIZ) == 0) {
-                       if (doaliases == 0)
-                               continue;       /* already processed this interface */
-                       myflags = IFI_ALIAS;
-               }
-               memcpy(lastname, ifr->ifr_name, IFNAMSIZ);
-
-               ifrcopy = *ifr;
-               ioctl(sockfd, SIOCGIFFLAGS, &ifrcopy);
-               flags = ifrcopy.ifr_flags;
-               if ((flags & IFF_UP) == 0)
-                       continue;       /* ignore if interface not up */
-
-               ifi = (struct ifa_info *) calloc(1, sizeof(struct ifa_info));
-               *ifipnext = ifi;                        /* prev points to this new one */
-               ifipnext = &ifi->ifa_next;      /* pointer to next one goes here */
-
-               ifi->ifa_flags = flags;         /* IFF_xxx values */
-               ifi->ifa_myflags = myflags;     /* IFI_xxx values */
-               memcpy(ifi->ifa_name, ifr->ifr_name, IFA_NAME);
-               ifi->ifa_name[IFA_NAME-1] = '\0';
-/* end get_ifa_info2 */
-/* include get_ifa_info3 */
-               switch (ifr->ifr_addr.sa_family) {
-               case AF_INET:
-                       sinptr = (struct sockaddr_in *) &ifr->ifr_addr;
-                       if (ifi->ifa_addr == NULL) {
-                               ifi->ifa_addr = (struct sockaddr *) calloc(1, sizeof(struct sockaddr_in));
-                               memcpy(ifi->ifa_addr, sinptr, sizeof(struct sockaddr_in));
-
-#ifdef SIOCGIFBRDADDR
-                               if (flags & IFF_BROADCAST) {
-                                       ioctl(sockfd, SIOCGIFBRDADDR, &ifrcopy);
-                                       sinptr = (struct sockaddr_in *) &ifrcopy.ifr_broadaddr;
-                                       ifi->ifa_brdaddr = (struct sockaddr *) calloc(1, sizeof(struct sockaddr_in));
-                                       memcpy(ifi->ifa_brdaddr, sinptr, sizeof(struct sockaddr_in));
-                               }
-#endif
-
-#ifdef SIOCGIFDSTADDR
-                               if (flags & IFF_POINTOPOINT) {
-                                       ioctl(sockfd, SIOCGIFDSTADDR, &ifrcopy);
-                                       sinptr = (struct sockaddr_in *) &ifrcopy.ifr_dstaddr;
-                                       ifi->ifa_dstaddr = (struct sockaddr *) calloc(1, sizeof(struct sockaddr_in));
-                                       memcpy(ifi->ifa_dstaddr, sinptr, sizeof(struct sockaddr_in));
-                               }
-#endif
-                       }
-                       break;
-
-               default:
-                       break;
-               }
-       }
-       free(buf);
-       return(ifihead);        /* pointer to first structure in linked list */
-}
-/* end get_ifa_info3 */
-
-/* include free_ifa_info */
-mDNSlocal void freeifaddrs(struct ifa_info *ifihead)
-{
-       struct ifa_info *ifi, *ifinext;
-
-       for (ifi = ifihead; ifi != NULL; ifi = ifinext) {
-               if (ifi->ifa_addr != NULL)
-                       free(ifi->ifa_addr);
-               if (ifi->ifa_brdaddr != NULL)
-                       free(ifi->ifa_brdaddr);
-               if (ifi->ifa_dstaddr != NULL)
-                       free(ifi->ifa_dstaddr);
-               ifinext = ifi->ifa_next;        /* can't fetch ifa_next after free() */
-               free(ifi);                                      /* the ifa_info{} itself */
-       }
-}
-/* end free_ifa_info */
-
-struct ifa_info *
-Get_ifa_info(int family, int doaliases)
-{
-       struct ifa_info *ifi;
-
-       if ( (ifi = get_ifa_info(family, doaliases)) == NULL)
-               debugf("get_ifa_info error");
-       return(ifi);
-}
-
-mDNSlocal int getifaddrs(struct ifa_info **ifalist)
-       {
-       *ifalist = get_ifa_info(PF_INET, false);
-       if( ifalist == nil )
-               return -1;
-       else
-               return(0);
-       }
index aa4ee90c98d245b53ddeb4d770d47ce40c0fb71b..1a2786ac09a43f65c23abd98a8827828565417b0 100644 (file)
                        path = mDNSMacOSX.h;
                        refType = 4;
                };
-               0017390704CC75C30CCA2C71 = {
-                       fileEncoding = 4;
-                       isa = PBXFileReference;
-                       path = SampleUDSClient.c;
-                       refType = 2;
-               };
-               0017390804CC75C30CCA2C71 = {
-                       fileRef = 0017390704CC75C30CCA2C71;
-                       isa = PBXBuildFile;
-                       settings = {
-                       };
-               };
-               0044D34804CC73600CCA2C71 = {
-                       buildPhases = (
-                               0044D34904CC73600CCA2C71,
-                               0044D34A04CC73600CCA2C71,
-                               0044D34C04CC73600CCA2C71,
-                               0044D34E04CC73600CCA2C71,
-                       );
-                       buildSettings = {
-                               GCC_TREAT_WARNINGS_AS_ERRORS = YES;
-                               MACOSX_DEPLOYMENT_TARGET = 10.2;
-                               OTHER_CFLAGS = "-no-cpp-precomp -DmDNSResponderVersion=$(MVERS)";
-                               OTHER_LDFLAGS = "";
-                               OTHER_REZFLAGS = "";
-                               PRODUCT_NAME = uds_test;
-                               REZ_EXECUTABLE = YES;
-                               SECTORDER_FLAGS = "";
-                               STRIPFLAGS = "-S";
-                               WARNING_CFLAGS = "-W -Wall -Wmissing-prototypes -Wno-four-char-constants -Wno-unknown-pragmas";
-                       };
-                       dependencies = (
-                       );
-                       isa = PBXToolTarget;
-                       name = "UDS API Test Tool";
-                       productName = "UDS API Test Tool";
-                       productReference = 0044D34F04CC73600CCA2C71;
-               };
-               0044D34904CC73600CCA2C71 = {
-                       buildActionMask = 2147483647;
-                       files = (
-                       );
-                       isa = PBXHeadersBuildPhase;
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               0044D34A04CC73600CCA2C71 = {
-                       buildActionMask = 2147483647;
-                       files = (
-                               0017390804CC75C30CCA2C71,
-                               00DD152B04CC79700CCA2C71,
-                               00DD152C04CC79A50CCA2C71,
-                       );
-                       isa = PBXSourcesBuildPhase;
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               0044D34C04CC73600CCA2C71 = {
-                       buildActionMask = 2147483647;
-                       files = (
-                       );
-                       isa = PBXFrameworksBuildPhase;
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               0044D34E04CC73600CCA2C71 = {
-                       buildActionMask = 2147483647;
-                       files = (
-                       );
-                       isa = PBXRezBuildPhase;
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               0044D34F04CC73600CCA2C71 = {
-                       isa = PBXExecutableFileReference;
-                       path = uds_test;
-                       refType = 3;
-               };
                004EFB9604CC78130CCA2C71 = {
                        fileEncoding = 4;
                        isa = PBXFileReference;
-                       path = dnssd_clientstub.c;
+                       name = dnssd_clientstub.c;
+                       path = ../mDNSShared/dnssd_clientstub.c;
                        refType = 2;
                };
                00AD62A3032D799A0CCA2C71 = {
                        buildSettings = {
                                FRAMEWORK_SEARCH_PATHS = "";
                                GCC_TREAT_WARNINGS_AS_ERRORS = YES;
-                               HEADER_SEARCH_PATHS = "../mDNSShared \"$(APPLE_INTERNAL_DEVELOPER_DIR)/Headers\"";
+                               HEADER_SEARCH_PATHS = "\"$(APPLE_INTERNAL_DEVELOPER_DIR)/Headers\"";
                                LIBRARY_SEARCH_PATHS = "";
                                MACOSX_DEPLOYMENT_TARGET = 10.2;
                                OPTIMIZATION_CFLAGS = "-O0";
-                               OTHER_CFLAGS = "-no-cpp-precomp -D__MACOSX__ -DMDNS_DEBUGMSGS=1 -DmDNSResponderVersion=$(MVERS) -DkDNSServiceFlagsRemove=0 -DkDNSServiceFlagsFinished=0";
+                               OTHER_CFLAGS = "-no-cpp-precomp -D__MACOSX__ -DMDNS_DEBUGMSGS=1 -DmDNSResponderVersion=$(MVERS)";
                                OTHER_LDFLAGS = "";
                                OTHER_REZFLAGS = "";
                                PRODUCT_NAME = mDNSResponder.debug;
                                F5E11B5F04A28126019798ED,
                                F515E29604A37BB701CA296C,
                                F515E29704A37BB801CA296C,
-                               F515E29804A37BBB01CA296C,
                                F515E29904A37BBB01CA296C,
                        );
                        isa = PBXHeadersBuildPhase;
                                00AD62B0032D799A0CCA2C71,
                                F5E11B5E04A28126019798ED,
                                F525E72B04AA167A01F1CF4D,
+                               DBAAFE2B057E8F4D0085CAD0,
+                               DBAAFE2E057E8F660085CAD0,
+                               7F18A9FA0587CEF6001880B3,
+                               7F18A9FB0587CEF6001880B3,
+                               7F461DB7062DBF2900672BF3,
                                00AD62B1032D799A0CCA2C71,
                        );
                        isa = PBXSourcesBuildPhase;
                                00AD62B4032D799A0CCA2C71,
                                00AD62B5032D799A0CCA2C71,
                                00AD62B6032D799A0CCA2C71,
+                               7F869687066EE02400D2A2DC,
                        );
                        isa = PBXFrameworksBuildPhase;
                        runOnlyForDeploymentPostprocessing = 0;
                                00AD62BC032D7A160CCA2C71,
                                00AD62BD032D7A1B0CCA2C71,
                                00AD62BE032D7A1D0CCA2C71,
-                               FF1B80C507AA1567000768F0,
-                               FF1B80C607AA1569000768F0,
+                               FFD41DDB0664169900F0C438,
+                               FFD41DDC0664169B00F0C438,
                        );
                        isa = PBXAggregateTarget;
                        name = "Build All";
                        path = /System/Library/Frameworks/IOKit.framework;
                        refType = 0;
                };
-               00DD152B04CC79700CCA2C71 = {
-                       fileRef = 004EFB9604CC78130CCA2C71;
-                       isa = PBXBuildFile;
-                       settings = {
-                       };
-               };
-               00DD152C04CC79A50CCA2C71 = {
-                       fileRef = F5E11B5A04A28126019798ED;
-                       isa = PBXBuildFile;
-                       settings = {
-                       };
-               };
 //000
 //001
 //002
                                08FB779FFE84155DC02AAC07,
                                00AD62A3032D799A0CCA2C71,
                                6575FC1C022EB76000000109,
-                               0044D34804CC73600CCA2C71,
-                               FF518DC907AA0BA60096AE13,
-                               FFEF84D207AA10DF00171646,
+                               DB2CC4530662DD6800335AB3,
+                               DB2CC4660662DF5C00335AB3,
                        );
                };
                08FB7794FE84155DC02AAC07 = {
                        children = (
-                               FF518DCB07AA0C330096AE13,
                                08FB7795FE84155DC02AAC07,
                                6575FC1F022EB78C00000109,
                                6575FBFE022EAFA800000109,
+                               DB2CC4420662DCE500335AB3,
                                08FB779DFE84155DC02AAC07,
                                19C28FBDFE9D53C911CA2CBB,
                        );
                };
                08FB7795FE84155DC02AAC07 = {
                        children = (
+                               7F461DB5062DBF2900672BF3,
                                F525E72804AA167501F1CF4D,
                                F5E11B5A04A28126019798ED,
                                F5E11B5B04A28126019798ED,
                                6575FBEB022EAF7200000109,
                                654BE64F02B63B93000001D1,
                                654BE65002B63B93000001D1,
-                               654BE65202B63B93000001D1,
+                               DBAAFE29057E8F4D0085CAD0,
                                000753D303367C1C0CCA2C71,
+                               DBAAFE2C057E8F660085CAD0,
+                               FF0E0B5D065ADC7600FE4D9C,
+                               FF485D5105632E0000130380,
+                               7F18A9F60587CEF6001880B3,
+                               7F18A9F70587CEF6001880B3,
                        );
                        isa = PBXGroup;
                        name = "mDNS Server Sources";
                };
                08FB779DFE84155DC02AAC07 = {
                        children = (
+                               7F869685066EE02400D2A2DC,
                                09AB6884FE841BABC02AAC07,
                                65713D46025A293200000109,
                                00CA213D02786FC30CCA2C71,
-                               FFEF84D607AA115900171646,
+                               DB2CC4680662DFF500335AB3,
                        );
                        isa = PBXGroup;
                        name = "External Frameworks and Libraries";
                                08FB77A1FE84155DC02AAC07,
                                08FB77A3FE84155DC02AAC07,
                                08FB77A5FE84155DC02AAC07,
+                               FF5A0AE705632EA600743C27,
+                               FF0E0B5C065ADC3800FE4D9C,
                        );
                        buildSettings = {
                                FRAMEWORK_SEARCH_PATHS = "";
                                GCC_TREAT_WARNINGS_AS_ERRORS = YES;
-                               HEADER_SEARCH_PATHS = "../mDNSShared \"$(APPLE_INTERNAL_DEVELOPER_DIR)/Headers\"";
+                               HEADER_SEARCH_PATHS = "\"$(APPLE_INTERNAL_DEVELOPER_DIR)/Headers\"";
                                INSTALL_PATH = /usr/sbin;
                                LIBRARY_SEARCH_PATHS = "";
                                MACOSX_DEPLOYMENT_TARGET = 10.2;
-                               OTHER_CFLAGS = "-no-cpp-precomp -D__MACOSX__ -DmDNSResponderVersion=$(MVERS) -DkDNSServiceFlagsRemove=0 -DkDNSServiceFlagsFinished=0";
+                               OTHER_CFLAGS = "-no-cpp-precomp -D__MACOSX__ -DmDNSResponderVersion=$(MVERS)";
                                OTHER_LDFLAGS = "";
                                OTHER_REZFLAGS = "";
                                PRODUCT_NAME = mDNSResponder;
                                REZ_EXECUTABLE = YES;
                                SECTORDER_FLAGS = "";
                                STRIPFLAGS = "-S";
-                               USE_GCC3_PFE_SUPPORT = NO;
                                WARNING_CFLAGS = "-W -Wall -Wmissing-prototypes -Wno-four-char-constants -Wno-unknown-pragmas";
                        };
                        dependencies = (
                                6575FBED022EAF7200000109,
                                F5E11B5C04A28126019798ED,
                                F525E72904AA167501F1CF4D,
+                               DBAAFE2A057E8F4D0085CAD0,
+                               DBAAFE2D057E8F660085CAD0,
+                               7F18A9F80587CEF6001880B3,
+                               7F18A9F90587CEF6001880B3,
+                               7F461DB6062DBF2900672BF3,
                                6575FBEE022EAF7200000109,
                        );
                        isa = PBXSourcesBuildPhase;
                                09AB6885FE841BABC02AAC07,
                                65713D66025A293200000109,
                                6585DD640279A3B7000001D1,
+                               7F869686066EE02400D2A2DC,
                        );
                        isa = PBXFrameworksBuildPhase;
                        runOnlyForDeploymentPostprocessing = 0;
                                034768E2FF38A6DC11DB9C8B,
                                6575FC1D022EB76000000109,
                                00AD62B8032D799A0CCA2C71,
-                               0044D34F04CC73600CCA2C71,
-                               FF72324E07AA0CB30012EE6F,
-                               FFEF84D307AA10DF00171646,
+                               DB2CC4670662DF5C00335AB3,
+                               FFD41DDA0664157900F0C438,
                        );
                        isa = PBXGroup;
                        name = Products;
                        path = ../mDNSCore/mDNSDebug.h;
                        refType = 4;
                };
-               654BE65202B63B93000001D1 = {
-                       fileEncoding = 4;
-                       isa = PBXFileReference;
-                       name = mDNSPlatformFunctions.h;
-                       path = ../mDNSCore/mDNSPlatformFunctions.h;
-                       refType = 4;
-               };
                65713D46025A293200000109 = {
                        isa = PBXFrameworkReference;
                        name = SystemConfiguration.framework;
                                GCC_TREAT_WARNINGS_AS_ERRORS = YES;
                                INSTALL_PATH = /usr/bin;
                                MACOSX_DEPLOYMENT_TARGET = 10.2;
-                               OTHER_CFLAGS = "-no-cpp-precomp -DmDNSResponderVersion=$(MVERS) -DkDNSServiceFlagsRemove=0";
+                               OTHER_CFLAGS = "-no-cpp-precomp -D__MACOSX__ -DmDNSResponderVersion=$(MVERS)";
                                OTHER_LDFLAGS = "";
                                OTHER_REZFLAGS = "";
                                PRODUCT_NAME = mDNS;
                6575FC1F022EB78C00000109 = {
                        children = (
                                6575FC20022EB7AA00000109,
-                               0017390704CC75C30CCA2C71,
                                004EFB9604CC78130CCA2C71,
                        );
                        isa = PBXGroup;
 //652
 //653
 //654
-//F50
-//F51
-//F52
-//F53
-//F54
-               F515E29604A37BB701CA296C = {
-                       fileRef = 654BE64F02B63B93000001D1;
-                       isa = PBXBuildFile;
-                       settings = {
-                       };
+//7F0
+//7F1
+//7F2
+//7F3
+//7F4
+               7F18A9F60587CEF6001880B3 = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       name = DNSCommon.c;
+                       path = ../mDNSCore/DNSCommon.c;
+                       refType = 2;
                };
-               F515E29704A37BB801CA296C = {
-                       fileRef = 654BE65002B63B93000001D1;
-                       isa = PBXBuildFile;
-                       settings = {
-                       };
+               7F18A9F70587CEF6001880B3 = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       name = uDNS.c;
+                       path = ../mDNSCore/uDNS.c;
+                       refType = 2;
                };
-               F515E29804A37BBB01CA296C = {
-                       fileRef = 654BE65202B63B93000001D1;
+               7F18A9F80587CEF6001880B3 = {
+                       fileRef = 7F18A9F60587CEF6001880B3;
                        isa = PBXBuildFile;
                        settings = {
                        };
                };
-               F515E29904A37BBB01CA296C = {
-                       fileRef = 000753D303367C1C0CCA2C71;
+               7F18A9F90587CEF6001880B3 = {
+                       fileRef = 7F18A9F70587CEF6001880B3;
                        isa = PBXBuildFile;
                        settings = {
                        };
                };
-               F525E72804AA167501F1CF4D = {
-                       fileEncoding = 4;
-                       indentWidth = 4;
-                       isa = PBXFileReference;
-                       path = uds_daemon.c;
-                       refType = 4;
-                       tabWidth = 4;
-                       usesTabs = 0;
-               };
-               F525E72904AA167501F1CF4D = {
-                       fileRef = F525E72804AA167501F1CF4D;
+               7F18A9FA0587CEF6001880B3 = {
+                       fileRef = 7F18A9F60587CEF6001880B3;
                        isa = PBXBuildFile;
                        settings = {
                        };
                };
-               F525E72B04AA167A01F1CF4D = {
-                       fileRef = F525E72804AA167501F1CF4D;
+               7F18A9FB0587CEF6001880B3 = {
+                       fileRef = 7F18A9F70587CEF6001880B3;
                        isa = PBXBuildFile;
                        settings = {
                        };
                };
-               F5E11B5A04A28126019798ED = {
-                       fileEncoding = 4;
-                       isa = PBXFileReference;
-                       path = dnssd_ipc.c;
-                       refType = 4;
-               };
-               F5E11B5B04A28126019798ED = {
-                       fileEncoding = 4;
+               7F461DB5062DBF2900672BF3 = {
+                       fileEncoding = 30;
                        isa = PBXFileReference;
-                       path = dnssd_ipc.h;
-                       refType = 4;
+                       name = DNSDigest.c;
+                       path = ../mDNSCore/DNSDigest.c;
+                       refType = 2;
                };
-               F5E11B5C04A28126019798ED = {
-                       fileRef = F5E11B5A04A28126019798ED;
+               7F461DB6062DBF2900672BF3 = {
+                       fileRef = 7F461DB5062DBF2900672BF3;
                        isa = PBXBuildFile;
                        settings = {
                        };
                };
-               F5E11B5D04A28126019798ED = {
-                       fileRef = F5E11B5B04A28126019798ED;
+               7F461DB7062DBF2900672BF3 = {
+                       fileRef = 7F461DB5062DBF2900672BF3;
                        isa = PBXBuildFile;
                        settings = {
                        };
                };
-               F5E11B5E04A28126019798ED = {
-                       fileRef = F5E11B5A04A28126019798ED;
+               7F869685066EE02400D2A2DC = {
+                       isa = PBXFrameworkReference;
+                       name = Security.framework;
+                       path = /System/Library/Frameworks/Security.framework;
+                       refType = 0;
+               };
+               7F869686066EE02400D2A2DC = {
+                       fileRef = 7F869685066EE02400D2A2DC;
                        isa = PBXBuildFile;
                        settings = {
                        };
                };
-               F5E11B5F04A28126019798ED = {
-                       fileRef = F5E11B5B04A28126019798ED;
+               7F869687066EE02400D2A2DC = {
+                       fileRef = 7F869685066EE02400D2A2DC;
                        isa = PBXBuildFile;
                        settings = {
                        };
                };
-//F50
-//F51
-//F52
-//F53
-//F54
-//FF0
-//FF1
-//FF2
-//FF3
-//FF4
-               FF1B80C507AA1567000768F0 = {
-                       isa = PBXTargetDependency;
-                       target = FF518DC907AA0BA60096AE13;
-               };
-               FF1B80C607AA1569000768F0 = {
-                       isa = PBXTargetDependency;
-                       target = FFEF84D207AA10DF00171646;
-               };
-               FF518DC607AA0BA60096AE13 = {
-                       buildActionMask = 2147483647;
-                       files = (
-                               FF518DD907AA0C330096AE13,
-                               FF518DDA07AA0C330096AE13,
-                               FF518DDB07AA0C330096AE13,
-                               FF518DDC07AA0C330096AE13,
-                               FF518DDD07AA0C330096AE13,
-                               FF518DDE07AA0C330096AE13,
-                               FF518DDF07AA0C330096AE13,
-                               FF518DE007AA0C330096AE13,
-                               FF518DE207AA0C330096AE13,
-                               FF518DE307AA0C330096AE13,
-                               FF518DE407AA0C330096AE13,
-                               FF518DE507AA0C330096AE13,
-                       );
-                       isa = PBXSourcesBuildPhase;
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               FF518DC707AA0BA60096AE13 = {
-                       buildActionMask = 2147483647;
-                       files = (
-                       );
-                       isa = PBXFrameworksBuildPhase;
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               FF518DC807AA0BA60096AE13 = {
-                       buildActionMask = 2147483647;
-                       files = (
-                       );
-                       isa = PBXRezBuildPhase;
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               FF518DC907AA0BA60096AE13 = {
-                       buildPhases = (
-                               FF518DC607AA0BA60096AE13,
-                               FF518DC707AA0BA60096AE13,
-                               FF518DC807AA0BA60096AE13,
-                               FF72324F07AA0CC20012EE6F,
-                               FF72325007AA0CCA0012EE6F,
-                       );
-                       buildSettings = {
-                               DYLIB_COMPATIBILITY_VERSION = 1;
-                               DYLIB_CURRENT_VERSION = 1;
-                               INSTALL_PATH = System/Library/Java/Extensions;
-                               JAVA_ARCHIVE_CLASSES = YES;
-                               JAVA_ARCHIVE_COMPRESSION = YES;
-                               JAVA_ARCHIVE_TYPE = JAR;
-                               JAVA_COMPILER_DEBUGGING_SYMBOLS = NO;
-                               JAVA_COMPILER_TARGET_VM_VERSION = 1.2;
-                               JAVA_SOURCE_SUBDIR = .;
-                               LIBRARY_STYLE = STATIC;
-                               OTHER_CFLAGS = "";
-                               OTHER_LDFLAGS = "";
-                               OTHER_LIBTOOL_FLAGS = "";
-                               OTHER_REZFLAGS = "";
-                               PRODUCT_NAME = dns_sd;
-                               REZ_EXECUTABLE = YES;
-                               SECTORDER_FLAGS = "";
-                               WARNING_CFLAGS = "-Wmost -Wno-four-char-constants -Wno-unknown-pragmas";
-                       };
-                       dependencies = (
-                       );
-                       isa = PBXLibraryTarget;
-                       name = dns_sd.jar;
-                       productInstallPath = System/Library/Java/Extensions;
-                       productName = dns_sd.jar;
-                       productReference = FF72324E07AA0CB30012EE6F;
-               };
-               FF518DCB07AA0C330096AE13 = {
+//7F0
+//7F1
+//7F2
+//7F3
+//7F4
+//DB0
+//DB1
+//DB2
+//DB3
+//DB4
+               DB2CC4420662DCE500335AB3 = {
                        children = (
-                               FF518DCC07AA0C330096AE13,
-                               FF518DCD07AA0C330096AE13,
-                               FF518DCE07AA0C330096AE13,
-                               FF518DCF07AA0C330096AE13,
-                               FF518DD007AA0C330096AE13,
-                               FF518DD107AA0C330096AE13,
-                               FF518DD207AA0C330096AE13,
-                               FF518DD307AA0C330096AE13,
-                               FF518DD407AA0C330096AE13,
-                               FF518DD507AA0C330096AE13,
-                               FF518DD607AA0C330096AE13,
-                               FF518DD707AA0C330096AE13,
-                               FF518DD807AA0C330096AE13,
+                               DB2CC4430662DD1100335AB3,
+                               DB2CC4440662DD1100335AB3,
+                               DB2CC4450662DD1100335AB3,
+                               DB2CC4460662DD1100335AB3,
+                               DB2CC4470662DD1100335AB3,
+                               DB2CC4480662DD1100335AB3,
+                               DB2CC4490662DD1100335AB3,
+                               DB2CC44A0662DD1100335AB3,
+                               DB2CC44B0662DD1100335AB3,
+                               DB2CC44C0662DD1100335AB3,
+                               DB2CC44D0662DD1100335AB3,
+                               DB2CC44E0662DD1100335AB3,
+                               DB2CC44F0662DD1100335AB3,
                        );
                        isa = PBXGroup;
-                       name = Java;
-                       path = ../mDNSShared/Java;
-                       refType = 2;
+                       name = "Java Support";
+                       refType = 4;
                };
-               FF518DCC07AA0C330096AE13 = {
+               DB2CC4430662DD1100335AB3 = {
                        fileEncoding = 30;
                        isa = PBXFileReference;
                        name = BaseListener.java;
                        path = ../mDNSShared/Java/BaseListener.java;
                        refType = 2;
                };
-               FF518DCD07AA0C330096AE13 = {
+               DB2CC4440662DD1100335AB3 = {
                        fileEncoding = 30;
                        isa = PBXFileReference;
                        name = BrowseListener.java;
                        path = ../mDNSShared/Java/BrowseListener.java;
                        refType = 2;
                };
-               FF518DCE07AA0C330096AE13 = {
+               DB2CC4450662DD1100335AB3 = {
                        fileEncoding = 30;
                        isa = PBXFileReference;
                        name = DNSRecord.java;
                        path = ../mDNSShared/Java/DNSRecord.java;
                        refType = 2;
                };
-               FF518DCF07AA0C330096AE13 = {
+               DB2CC4460662DD1100335AB3 = {
                        fileEncoding = 30;
                        isa = PBXFileReference;
                        name = DNSSD.java;
                        path = ../mDNSShared/Java/DNSSD.java;
                        refType = 2;
                };
-               FF518DD007AA0C330096AE13 = {
+               DB2CC4470662DD1100335AB3 = {
                        fileEncoding = 30;
                        isa = PBXFileReference;
                        name = DNSSDException.java;
                        path = ../mDNSShared/Java/DNSSDException.java;
                        refType = 2;
                };
-               FF518DD107AA0C330096AE13 = {
+               DB2CC4480662DD1100335AB3 = {
                        fileEncoding = 30;
                        isa = PBXFileReference;
                        name = DNSSDRegistration.java;
                        path = ../mDNSShared/Java/DNSSDRegistration.java;
                        refType = 2;
                };
-               FF518DD207AA0C330096AE13 = {
+               DB2CC4490662DD1100335AB3 = {
                        fileEncoding = 30;
                        isa = PBXFileReference;
                        name = DNSSDService.java;
                        path = ../mDNSShared/Java/DNSSDService.java;
                        refType = 2;
                };
-               FF518DD307AA0C330096AE13 = {
+               DB2CC44A0662DD1100335AB3 = {
                        fileEncoding = 30;
                        isa = PBXFileReference;
                        name = DomainListener.java;
                        path = ../mDNSShared/Java/DomainListener.java;
                        refType = 2;
                };
-               FF518DD407AA0C330096AE13 = {
+               DB2CC44B0662DD1100335AB3 = {
                        fileEncoding = 30;
                        isa = PBXFileReference;
                        name = JNISupport.c;
                        path = ../mDNSShared/Java/JNISupport.c;
                        refType = 2;
                };
-               FF518DD507AA0C330096AE13 = {
+               DB2CC44C0662DD1100335AB3 = {
                        fileEncoding = 30;
                        isa = PBXFileReference;
                        name = QueryListener.java;
                        path = ../mDNSShared/Java/QueryListener.java;
                        refType = 2;
                };
-               FF518DD607AA0C330096AE13 = {
+               DB2CC44D0662DD1100335AB3 = {
                        fileEncoding = 30;
                        isa = PBXFileReference;
                        name = RegisterListener.java;
                        path = ../mDNSShared/Java/RegisterListener.java;
                        refType = 2;
                };
-               FF518DD707AA0C330096AE13 = {
+               DB2CC44E0662DD1100335AB3 = {
                        fileEncoding = 30;
                        isa = PBXFileReference;
                        name = ResolveListener.java;
                        path = ../mDNSShared/Java/ResolveListener.java;
                        refType = 2;
                };
-               FF518DD807AA0C330096AE13 = {
+               DB2CC44F0662DD1100335AB3 = {
                        fileEncoding = 30;
                        isa = PBXFileReference;
                        name = TXTRecord.java;
                        path = ../mDNSShared/Java/TXTRecord.java;
                        refType = 2;
                };
-               FF518DD907AA0C330096AE13 = {
-                       fileRef = FF518DCC07AA0C330096AE13;
+               DB2CC4500662DD6800335AB3 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               DB2CC4560662DE4500335AB3,
+                               DB2CC4570662DE4600335AB3,
+                               DB2CC4580662DE4700335AB3,
+                               DB2CC4590662DE4700335AB3,
+                               DB2CC45A0662DE4800335AB3,
+                               DB2CC45B0662DE4900335AB3,
+                               DB2CC45C0662DE4900335AB3,
+                               DB2CC45D0662DE4A00335AB3,
+                               DB2CC45E0662DE4B00335AB3,
+                               DB2CC45F0662DE4C00335AB3,
+                               DB2CC4600662DE4C00335AB3,
+                               DB2CC4610662DE4D00335AB3,
+                       );
+                       isa = PBXSourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               DB2CC4510662DD6800335AB3 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       isa = PBXJavaArchiveBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               DB2CC4520662DD6800335AB3 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       isa = PBXFrameworksBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               DB2CC4530662DD6800335AB3 = {
+                       buildPhases = (
+                               DB2CC4500662DD6800335AB3,
+                               DB2CC4510662DD6800335AB3,
+                               DB2CC4520662DD6800335AB3,
+                               DB2CC4550662DE1700335AB3,
+                               FFD41DDD06641B4200F0C438,
+                       );
+                       buildSettings = {
+                               DYLIB_COMPATIBILITY_VERSION = 1;
+                               DYLIB_CURRENT_VERSION = 1;
+                               INSTALL_PATH = /System/Library/Java/Extensions;
+                               JAVA_ARCHIVE_CLASSES = YES;
+                               JAVA_ARCHIVE_COMPRESSION = YES;
+                               JAVA_ARCHIVE_TYPE = JAR;
+                               JAVA_COMPILER_DEBUGGING_SYMBOLS = NO;
+                               JAVA_COMPILER_TARGET_VM_VERSION = 1.2;
+                               JAVA_SOURCE_SUBDIR = .;
+                               LIBRARY_STYLE = STATIC;
+                               OTHER_CFLAGS = "";
+                               OTHER_LDFLAGS = "";
+                               OTHER_LIBTOOL_FLAGS = "";
+                               OTHER_REZFLAGS = "";
+                               PRODUCT_NAME = dns_sd;
+                               PURE_JAVA = YES;
+                               REZ_EXECUTABLE = YES;
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = "-Wmost -Wno-four-char-constants -Wno-unknown-pragmas";
+                       };
+                       comments = "Multiplatform .jar file that implements Java interface to DNS-SD";
+                       dependencies = (
+                       );
+                       isa = PBXLibraryTarget;
+                       name = dns_sd.jar;
+                       productInstallPath = /System/Library/Java/Extensions;
+                       productName = dns_sd.jar;
+                       productReference = FFD41DDA0664157900F0C438;
+               };
+               DB2CC4550662DE1700335AB3 = {
+                       buildActionMask = 12;
+                       files = (
+                       );
+                       generatedFileNames = (
+                       );
+                       isa = PBXShellScriptBuildPhase;
+                       neededFileNames = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+                       shellPath = /bin/sh;
+                       shellScript = "javah -force -classpath ${OBJROOT}/mDNSResponder.build/dns_sd.jar.build/JavaClasses/ -o ${OBJROOT}/mDNSResponder.build/dns_sd.jar.build/DNSSD.java.h com.apple.dnssd.AppleDNSSD com.apple.dnssd.AppleBrowser com.apple.dnssd.AppleResolver com.apple.dnssd.AppleRegistration com.apple.dnssd.AppleQuery com.apple.dnssd.AppleDomainEnum com.apple.dnssd.AppleService";
+               };
+               DB2CC4560662DE4500335AB3 = {
+                       fileRef = DB2CC4430662DD1100335AB3;
                        isa = PBXBuildFile;
                        settings = {
                        };
                };
-               FF518DDA07AA0C330096AE13 = {
-                       fileRef = FF518DCD07AA0C330096AE13;
+               DB2CC4570662DE4600335AB3 = {
+                       fileRef = DB2CC4440662DD1100335AB3;
                        isa = PBXBuildFile;
                        settings = {
                        };
                };
-               FF518DDB07AA0C330096AE13 = {
-                       fileRef = FF518DCE07AA0C330096AE13;
+               DB2CC4580662DE4700335AB3 = {
+                       fileRef = DB2CC4450662DD1100335AB3;
                        isa = PBXBuildFile;
                        settings = {
                        };
                };
-               FF518DDC07AA0C330096AE13 = {
-                       fileRef = FF518DCF07AA0C330096AE13;
+               DB2CC4590662DE4700335AB3 = {
+                       fileRef = DB2CC4460662DD1100335AB3;
                        isa = PBXBuildFile;
                        settings = {
                        };
                };
-               FF518DDD07AA0C330096AE13 = {
-                       fileRef = FF518DD007AA0C330096AE13;
+               DB2CC45A0662DE4800335AB3 = {
+                       fileRef = DB2CC4470662DD1100335AB3;
                        isa = PBXBuildFile;
                        settings = {
                        };
                };
-               FF518DDE07AA0C330096AE13 = {
-                       fileRef = FF518DD107AA0C330096AE13;
+               DB2CC45B0662DE4900335AB3 = {
+                       fileRef = DB2CC4480662DD1100335AB3;
                        isa = PBXBuildFile;
                        settings = {
                        };
                };
-               FF518DDF07AA0C330096AE13 = {
-                       fileRef = FF518DD207AA0C330096AE13;
+               DB2CC45C0662DE4900335AB3 = {
+                       fileRef = DB2CC4490662DD1100335AB3;
                        isa = PBXBuildFile;
                        settings = {
                        };
                };
-               FF518DE007AA0C330096AE13 = {
-                       fileRef = FF518DD307AA0C330096AE13;
+               DB2CC45D0662DE4A00335AB3 = {
+                       fileRef = DB2CC44A0662DD1100335AB3;
                        isa = PBXBuildFile;
                        settings = {
                        };
                };
-               FF518DE207AA0C330096AE13 = {
-                       fileRef = FF518DD507AA0C330096AE13;
+               DB2CC45E0662DE4B00335AB3 = {
+                       fileRef = DB2CC44C0662DD1100335AB3;
                        isa = PBXBuildFile;
                        settings = {
                        };
                };
-               FF518DE307AA0C330096AE13 = {
-                       fileRef = FF518DD607AA0C330096AE13;
+               DB2CC45F0662DE4C00335AB3 = {
+                       fileRef = DB2CC44D0662DD1100335AB3;
                        isa = PBXBuildFile;
                        settings = {
                        };
                };
-               FF518DE407AA0C330096AE13 = {
-                       fileRef = FF518DD707AA0C330096AE13;
+               DB2CC4600662DE4C00335AB3 = {
+                       fileRef = DB2CC44E0662DD1100335AB3;
                        isa = PBXBuildFile;
                        settings = {
                        };
                };
-               FF518DE507AA0C330096AE13 = {
-                       fileRef = FF518DD807AA0C330096AE13;
+               DB2CC4610662DE4D00335AB3 = {
+                       fileRef = DB2CC44F0662DD1100335AB3;
                        isa = PBXBuildFile;
                        settings = {
                        };
                };
-               FF72324E07AA0CB30012EE6F = {
-                       includeInIndex = 0;
-                       isa = PBXZipArchiveReference;
-                       path = dns_sd.jar;
-                       refType = 3;
-               };
-               FF72324F07AA0CC20012EE6F = {
-                       buildActionMask = 2147483647;
-                       files = (
-                       );
-                       generatedFileNames = (
-                       );
-                       isa = PBXShellScriptBuildPhase;
-                       neededFileNames = (
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-                       shellPath = /bin/sh;
-                       shellScript = "javah -force -classpath ${OBJROOT}/mDNSResponder.build/dns_sd.jar.build/JavaClasses/ -o ${OBJROOT}/mDNSResponder.build/dns_sd.jar.build/DNSSD.java.h com.apple.dnssd.AppleDNSSD com.apple.dnssd.AppleBrowser com.apple.dnssd.AppleResolver com.apple.dnssd.AppleRegistration com.apple.dnssd.AppleQuery com.apple.dnssd.AppleDomainEnum com.apple.dnssd.AppleService";
-               };
-               FF72325007AA0CCA0012EE6F = {
-                       buildActionMask = 2147483647;
-                       files = (
-                       );
-                       generatedFileNames = (
-                       );
-                       isa = PBXShellScriptBuildPhase;
-                       neededFileNames = (
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-                       shellPath = /bin/sh;
-                       shellScript = "rm -f ${BUILD_DIR}/dns_sd";
-               };
-               FFEF84CE07AA10DF00171646 = {
+               DB2CC4620662DF5C00335AB3 = {
                        buildActionMask = 2147483647;
                        files = (
                        );
                        isa = PBXHeadersBuildPhase;
                        runOnlyForDeploymentPostprocessing = 0;
                };
-               FFEF84CF07AA10DF00171646 = {
+               DB2CC4630662DF5C00335AB3 = {
                        buildActionMask = 2147483647;
                        files = (
-                               FFEF84D407AA113100171646,
+                               DB2CC46A0662E00700335AB3,
                        );
                        isa = PBXSourcesBuildPhase;
                        runOnlyForDeploymentPostprocessing = 0;
                };
-               FFEF84D007AA10DF00171646 = {
+               DB2CC4640662DF5C00335AB3 = {
                        buildActionMask = 2147483647;
                        files = (
-                               FFEF84D707AA115900171646,
+                               DB2CC4690662DFF500335AB3,
                        );
                        isa = PBXFrameworksBuildPhase;
                        runOnlyForDeploymentPostprocessing = 0;
                };
-               FFEF84D107AA10DF00171646 = {
+               DB2CC4650662DF5C00335AB3 = {
                        buildActionMask = 2147483647;
                        files = (
                        );
                        isa = PBXRezBuildPhase;
                        runOnlyForDeploymentPostprocessing = 0;
                };
-               FFEF84D207AA10DF00171646 = {
+               DB2CC4660662DF5C00335AB3 = {
                        buildPhases = (
-                               FFEF84CE07AA10DF00171646,
-                               FFEF84CF07AA10DF00171646,
-                               FFEF84D007AA10DF00171646,
-                               FFEF84D107AA10DF00171646,
+                               DB2CC4620662DF5C00335AB3,
+                               DB2CC4630662DF5C00335AB3,
+                               DB2CC4640662DF5C00335AB3,
+                               DB2CC4650662DF5C00335AB3,
                        );
                        buildSettings = {
+                               DEBUGGING_SYMBOLS = NO;
                                DYLIB_COMPATIBILITY_VERSION = 1;
                                DYLIB_CURRENT_VERSION = 1;
-                               HEADER_SEARCH_PATHS = "../mDNSShared \"$(SYSTEM_LIBRARY_DIR)/Frameworks/JavaVM.framework/Versions/A/Headers\" \"$(SYSTEM_LIBRARY_DIR)/Frameworks/JavaVM.framework/Versions/1.3.1/Headers\" \"$(OBJROOT)/mDNSResponder.build/dns_sd.jar.build\"";
+                               HEADER_SEARCH_PATHS = "\"$(SYSTEM_LIBRARY_DIR)/Frameworks/JavaVM.framework/Versions/A/Headers\" \"$(SYSTEM_LIBRARY_DIR)/Frameworks/JavaVM.framework/Versions/1.3.1/Headers\" \"$(OBJROOT)/mDNSResponder.build/dns_sd.jar.build\"";
                                INSTALL_PATH = /usr/lib/java;
                                LIBRARY_STYLE = DYNAMIC;
                                OTHER_CFLAGS = "";
-                               OTHER_LDFLAGS = "";
                                OTHER_LIBTOOL_FLAGS = "";
                                OTHER_REZFLAGS = "";
                                PRODUCT_NAME = libjdns_sd.jnilib;
                        };
                        comments = "Platform-specific JNI library that bridges dns_sd.jar to <dns_sd.h>.";
                        dependencies = (
-                               FFEF84D807AA116400171646,
+                               FFD41DDF06641BBB00F0C438,
                        );
                        isa = PBXLibraryTarget;
                        name = libjdns_sd.jnilib;
                        productInstallPath = /usr/lib/java;
                        productName = libjdns_sd.jnilib;
-                       productReference = FFEF84D307AA10DF00171646;
+                       productReference = DB2CC4670662DF5C00335AB3;
                };
-               FFEF84D307AA10DF00171646 = {
+               DB2CC4670662DF5C00335AB3 = {
                        isa = PBXLibraryReference;
                        path = libjdns_sd.jnilib;
                        refType = 3;
                };
-               FFEF84D407AA113100171646 = {
-                       fileRef = FF518DD407AA0C330096AE13;
-                       isa = PBXBuildFile;
-                       settings = {
-                       };
-               };
-               FFEF84D607AA115900171646 = {
+               DB2CC4680662DFF500335AB3 = {
                        isa = PBXFrameworkReference;
                        name = JavaVM.framework;
                        path = /System/Library/Frameworks/JavaVM.framework;
                        refType = 0;
                };
-               FFEF84D707AA115900171646 = {
-                       fileRef = FFEF84D607AA115900171646;
+               DB2CC4690662DFF500335AB3 = {
+                       fileRef = DB2CC4680662DFF500335AB3;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               DB2CC46A0662E00700335AB3 = {
+                       fileRef = DB2CC44B0662DD1100335AB3;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               DBAAFE29057E8F4D0085CAD0 = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       name = mDNSDebug.c;
+                       path = ../mDNSShared/mDNSDebug.c;
+                       refType = 2;
+               };
+               DBAAFE2A057E8F4D0085CAD0 = {
+                       fileRef = DBAAFE29057E8F4D0085CAD0;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               DBAAFE2B057E8F4D0085CAD0 = {
+                       fileRef = DBAAFE29057E8F4D0085CAD0;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               DBAAFE2C057E8F660085CAD0 = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       name = GenLinkedList.c;
+                       path = ../mDNSShared/GenLinkedList.c;
+                       refType = 2;
+               };
+               DBAAFE2D057E8F660085CAD0 = {
+                       fileRef = DBAAFE2C057E8F660085CAD0;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               DBAAFE2E057E8F660085CAD0 = {
+                       fileRef = DBAAFE2C057E8F660085CAD0;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+//DB0
+//DB1
+//DB2
+//DB3
+//DB4
+//F50
+//F51
+//F52
+//F53
+//F54
+               F515E29604A37BB701CA296C = {
+                       fileRef = 654BE64F02B63B93000001D1;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               F515E29704A37BB801CA296C = {
+                       fileRef = 654BE65002B63B93000001D1;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               F515E29904A37BBB01CA296C = {
+                       fileRef = 000753D303367C1C0CCA2C71;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               F525E72804AA167501F1CF4D = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       name = uds_daemon.c;
+                       path = ../mDNSShared/uds_daemon.c;
+                       refType = 2;
+               };
+               F525E72904AA167501F1CF4D = {
+                       fileRef = F525E72804AA167501F1CF4D;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               F525E72B04AA167A01F1CF4D = {
+                       fileRef = F525E72804AA167501F1CF4D;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               F5E11B5A04A28126019798ED = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       name = dnssd_ipc.c;
+                       path = ../mDNSShared/dnssd_ipc.c;
+                       refType = 2;
+               };
+               F5E11B5B04A28126019798ED = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       name = dnssd_ipc.h;
+                       path = ../mDNSShared/dnssd_ipc.h;
+                       refType = 2;
+               };
+               F5E11B5C04A28126019798ED = {
+                       fileRef = F5E11B5A04A28126019798ED;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               F5E11B5D04A28126019798ED = {
+                       fileRef = F5E11B5B04A28126019798ED;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               F5E11B5E04A28126019798ED = {
+                       fileRef = F5E11B5A04A28126019798ED;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               F5E11B5F04A28126019798ED = {
+                       fileRef = F5E11B5B04A28126019798ED;
                        isa = PBXBuildFile;
                        settings = {
                        };
                };
-               FFEF84D807AA116400171646 = {
+//F50
+//F51
+//F52
+//F53
+//F54
+//FF0
+//FF1
+//FF2
+//FF3
+//FF4
+               FF0E0B5C065ADC3800FE4D9C = {
+                       buildActionMask = 8;
+                       dstPath = /usr/share/man/man1;
+                       dstSubfolderSpec = 0;
+                       files = (
+                               FF0E0B5E065ADCA400FE4D9C,
+                       );
+                       isa = PBXCopyFilesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 1;
+               };
+               FF0E0B5D065ADC7600FE4D9C = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       name = mDNS.1;
+                       path = ../mDNSShared/mDNS.1;
+                       refType = 2;
+               };
+               FF0E0B5E065ADCA400FE4D9C = {
+                       fileRef = FF0E0B5D065ADC7600FE4D9C;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               FF485D5105632E0000130380 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       name = mDNSResponder.8;
+                       path = ../mDNSShared/mDNSResponder.8;
+                       refType = 2;
+               };
+               FF5A0AE705632EA600743C27 = {
+                       buildActionMask = 8;
+                       dstPath = /usr/share/man/man8;
+                       dstSubfolderSpec = 0;
+                       files = (
+                               FF5A0AE805632EAE00743C27,
+                       );
+                       isa = PBXCopyFilesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 1;
+               };
+               FF5A0AE805632EAE00743C27 = {
+                       fileRef = FF485D5105632E0000130380;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               FFD41DDA0664157900F0C438 = {
+                       includeInIndex = 0;
+                       isa = PBXZipArchiveReference;
+                       path = dns_sd.jar;
+                       refType = 3;
+               };
+               FFD41DDB0664169900F0C438 = {
+                       isa = PBXTargetDependency;
+                       target = DB2CC4530662DD6800335AB3;
+               };
+               FFD41DDC0664169B00F0C438 = {
+                       isa = PBXTargetDependency;
+                       target = DB2CC4660662DF5C00335AB3;
+               };
+               FFD41DDD06641B4200F0C438 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       generatedFileNames = (
+                       );
+                       isa = PBXShellScriptBuildPhase;
+                       neededFileNames = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+                       shellPath = /bin/sh;
+                       shellScript = "rm -f ${BUILD_DIR}/dns_sd";
+               };
+               FFD41DDF06641BBB00F0C438 = {
                        isa = PBXTargetDependency;
-                       target = FF518DC907AA0BA60096AE13;
+                       target = DB2CC4530662DD6800335AB3;
                };
        };
        rootObject = 08FB7793FE84155DC02AAC07;
diff --git a/mDNSMacOSX/uds_daemon.c b/mDNSMacOSX/uds_daemon.c
deleted file mode 100644 (file)
index b1d9eba..0000000
+++ /dev/null
@@ -1,2282 +0,0 @@
-/*
- * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- * 
- * @APPLE_LICENSE_HEADER_END@
-
-    Change History (most recent first):
-
-$Log: uds_daemon.c,v $
-Revision 1.22.2.4  2005/01/28 05:41:45  cheshire
-<rdar://problem/3924278> SUPan: Service advertisement in qmaster can yield zombie ads
-
-Revision 1.22.2.3  2005/01/28 04:03:24  cheshire
-<rdar://problem/3759302> SUPan: Current method of doing subtypes causes name collisions
-Summary: Pulled in ConstructServiceName, CountSubTypes and AllocateSubTypes from Tiger version.
-
-Revision 1.22.2.2  2004/06/18 17:28:19  cheshire
-<rdar://problem/3588761> Current method of doing subtypes causes name collisions
-
-Revision 1.22.2.1  2003/12/05 00:03:35  cheshire
-<rdar://problem/3487869> Use buffer size MAX_ESCAPED_DOMAIN_NAME instead of 256
-
-Revision 1.22  2003/08/19 16:03:55  ksekar
-Bug #: <rdar://problem/3380097>: ER: SIGINFO dump should include resolves started by DNSServiceQueryRecord
-Check termination_context for NULL before dereferencing.
-
-Revision 1.21  2003/08/19 05:39:43  cheshire
-<rdar://problem/3380097> SIGINFO dump should include resolves started by DNSServiceQueryRecord
-
-Revision 1.20  2003/08/16 03:39:01  cheshire
-<rdar://problem/3338440> InterfaceID -1 indicates "local only"
-
-Revision 1.19  2003/08/15 20:16:03  cheshire
-<rdar://problem/3366590> mDNSResponder takes too much RPRVT
-We want to avoid touching the rdata pages, so we don't page them in.
-1. RDLength was stored with the rdata, which meant touching the page just to find the length.
-   Moved this from the RData to the ResourceRecord object.
-2. To avoid unnecessarily touching the rdata just to compare it,
-   compute a hash of the rdata and store the hash in the ResourceRecord object.
-
-Revision 1.18  2003/08/15 00:38:00  ksekar
-Bug #: <rdar://problem/3377005>: Bug: buffer overrun when reading long rdata from client
-
-Revision 1.17  2003/08/14 02:18:21  cheshire
-<rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
-
-Revision 1.16  2003/08/13 23:58:52  ksekar
-Bug #: <rdar://problem/3374911>: Bug: UDS Sub-type browsing works, but not sub-type registration
-Fixed pointer increment error, moved subtype reading for-loop for easier error bailout.
-
-Revision 1.15  2003/08/13 17:30:33  ksekar
-Bug #: <rdar://problem/3374671>: DNSServiceAddRecord doesn't work
-Fixed various problems with handling the AddRecord request and freeing the ExtraResourceRecords.
-
-Revision 1.14  2003/08/12 19:56:25  cheshire
-Update to APSL 2.0
-
- */
-
-#include "mDNSClientAPI.h"
-#include "mDNSMacOSX.h"
-#include "dns_sd.h"
-#include "dnssd_ipc.h"
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <sys/types.h>
-#include <sys/time.h>
-#include <sys/resource.h>
-
-// Types and Data Structures
-// ----------------------------------------------------------------------
-
-typedef enum
-    {
-    t_uninitialized,
-    t_morecoming,
-    t_complete,
-    t_error,
-    t_terminated
-    } transfer_state;
-
-typedef void (*req_termination_fn)(void *);
-
-
-typedef struct registered_record_entry
-    {
-    int key;
-    AuthRecord *rr;
-    struct registered_record_entry *next;
-    } registered_record_entry;
-
-typedef struct registered_service
-    {
-    //struct registered_service *next;
-    int autoname;
-    int renameonconflict;
-    int rename_on_memfree;     // set flag on config change when we deregister original name
-    domainlabel name;
-    ServiceRecordSet *srs;
-    struct request_state *request;
-    AuthRecord *subtypes;
-    } registered_service;
-    
-typedef struct 
-    {
-    mStatus err;
-    int nwritten;
-    int sd;
-    } undelivered_error_t;
-
-typedef struct request_state
-    {
-    // connection structures
-    CFRunLoopSourceRef rls;
-    CFSocketRef sr;            
-    int sd;    
-                                
-    // state of read (in case message is read over several recv() calls)                            
-    transfer_state ts;
-    uint32_t hdr_bytes;                // bytes of header already read
-    ipc_msg_hdr hdr;
-    uint32_t data_bytes;       // bytes of message data already read
-    char *msgbuf;              // pointer to data storage to pass to free()
-    char *msgdata;             // pointer to data to be read from (may be modified)
-    int bufsize;               // size of data storage
-
-    // reply, termination, error, and client context info
-    int no_reply;              // don't send asynchronous replies to client
-    void *client_context;      // don't touch this - pointer only valid in client's addr space
-    struct reply_state *replies;  // corresponding (active) reply list
-    undelivered_error_t *u_err;
-    void *termination_context;
-    req_termination_fn terminate;
-    
-    //!!!KRS toss these pointers in a union
-    // registration context associated with this request (null if not applicable)
-    registered_record_entry *reg_recs;  // muliple registrations for a connection-oriented request
-    registered_service *service;  // service record set and flags
-    struct resolve_result_t *resolve_results;
-    
-    struct request_state *next;
-    } request_state;
-
-// struct physically sits between ipc message header and call-specific fields in the message buffer
-typedef struct
-    {
-    DNSServiceFlags flags;
-    uint32_t ifi;
-    DNSServiceErrorType error;
-    } reply_hdr;
-    
-
-typedef struct reply_state
-    {
-    // state of the transmission
-    int sd;
-    transfer_state ts;
-    uint32_t nwriten;
-    uint32_t len;
-    // context of the reply
-    struct request_state *request;  // the request that this answers
-    struct reply_state *next;   // if there are multiple unsent replies
-    // pointer into message buffer - allows fields to be changed after message is formatted
-    ipc_msg_hdr *mhdr;
-    reply_hdr *rhdr;
-    char *sdata;  // pointer to start of call-specific data
-    // pointer to malloc'd buffer
-    char *msgbuf;      
-    } reply_state;
-
-
-// domain enumeration and resolv calls require 2 mDNSCore calls, so we need separate interconnected
-// structures to handle callbacks
-typedef struct
-    {
-    DNSQuestion question;
-    mDNS_DomainType type;
-    request_state *rstate;
-    } domain_enum_t;
-
-typedef struct
-    {
-    domain_enum_t *all;
-    domain_enum_t *def;
-    request_state *rstate;
-    } enum_termination_t;
-
-typedef struct
-    {
-    DNSQuestion question;
-    uint16_t   qtype;
-    request_state *rstate;
-    } resolve_t;
-    
-typedef struct
-    {
-    resolve_t *txt;
-    resolve_t *srv;
-    request_state *rstate;
-    } resolve_termination_t;
-    
-typedef struct resolve_result_t
-    {
-    const ResourceRecord *txt;
-    const ResourceRecord *srv;
-    } resolve_result_t;
-
-typedef struct
-    {
-    request_state *rstate;
-    client_context_t client_context;
-    } regrecord_callback_context;
-
-
-
-
-// globals
-static int listenfd = -1;  
-static request_state *all_requests = NULL;  
-//!!!KRS we should keep a separate list containing only the requests that need to be examined
-//in the idle() routine.
-
-
-#define MAX_OPENFILES 1024
-
-// private function prototypes
-static void connect_callback(CFSocketRef sr, CFSocketCallBackType t, CFDataRef dr, const void *c, void *i);
-static int read_msg(request_state *rs);
-static int send_msg(reply_state *rs);
-static void abort_request(request_state *rs);
-static void request_callback(CFSocketRef sr, CFSocketCallBackType t, CFDataRef dr, const void *c, void *i);
-static void handle_resolve_request(request_state *rstate);
-static void question_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord);
-static void question_termination_callback(void *context);
-static void handle_browse_request(request_state *request);
-static void browse_termination_callback(void *context);
-static void browse_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord);
-static void handle_regservice_request(request_state *request);
-static void regservice_termination_callback(void *context);
-static void process_service_registration(ServiceRecordSet *const srs);
-static void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, mStatus result);
-static mStatus handle_add_request(request_state *rstate);
-static mStatus handle_update_request(request_state *rstate);
-static mStatus gen_rr_response(domainname *servicename, mDNSInterfaceID id, request_state *request, reply_state **rep);
-static void append_reply(request_state *req, reply_state *rep);
-static int build_domainname_from_strings(domainname *srv, char *name, char *regtype, char *domain);
-static void enum_termination_callback(void *context);
-static void enum_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord);
-static void handle_query_request(request_state *rstate);
-static mStatus do_question(request_state *rstate, domainname *name, uint32_t ifi, uint16_t rrtype, int16_t rrclass);
-static reply_state *format_enumeration_reply(request_state *rstate, char *domain,                                              DNSServiceFlags flags, uint32_t ifi, DNSServiceErrorType err);
-static void handle_enum_request(request_state *rstate);
-static mStatus handle_regrecord_request(request_state *rstate);
-static void regrecord_callback(mDNS *const m, AuthRecord *const rr, mStatus result);
-static void connected_registration_termination(void *context);
-static void handle_reconfirm_request(request_state *rstate);
-static AuthRecord *read_rr_from_ipc_msg(char *msgbuf, int ttl);
-static mStatus handle_removerecord_request(request_state *rstate);
-static void reset_connected_rstate(request_state *rstate);
-static int deliver_error(request_state *rstate, mStatus err);
-static int deliver_async_error(request_state *rs, reply_op_t op, mStatus err);
-static transfer_state send_undelivered_error(request_state *rs);
-static reply_state *create_reply(reply_op_t op, int datalen, request_state *request);
-static void update_callback(mDNS *const m, AuthRecord *const rr, RData *oldrd);
-static void my_perror(char *errmsg);
-static void unlink_request(request_state *rs);
-static void resolve_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord);
-static void resolve_termination_callback(void *context);
-
-// initialization, setup/teardown functions
-
-int udsserver_init(void)  
-    {
-    mode_t mask;
-    struct sockaddr_un laddr;
-    struct rlimit maxfds;
-
-    if ((listenfd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0) 
-            goto error;
-    unlink(MDNS_UDS_SERVERPATH);  //OK if this fails
-    bzero(&laddr, sizeof(laddr));
-    laddr.sun_family = AF_LOCAL;
-    laddr.sun_len = sizeof(struct sockaddr_un);
-    strcpy(laddr.sun_path, MDNS_UDS_SERVERPATH);
-    mask = umask(0);
-    if (bind(listenfd, (struct sockaddr *)&laddr, sizeof(laddr)) < 0)
-        goto error;
-    umask(mask);
-
-    if (fcntl(listenfd, F_SETFL, O_NONBLOCK) < 0)
-        {
-        my_perror("ERROR: could not set listen socket to non-blocking mode");
-        goto error;
-        }
-    listen(listenfd, LISTENQ);
-    
-    
-    // set maximum file descriptor to 1024
-    if (getrlimit(RLIMIT_NOFILE, &maxfds) < 0)
-        {
-        my_perror("ERROR: Unable to get file descriptor limit");
-        return 0;
-        }
-    if (maxfds.rlim_max >= MAX_OPENFILES && maxfds.rlim_cur == maxfds.rlim_max)
-        {
-        // proper values already set
-        return 0;
-        }
-    maxfds.rlim_max = MAX_OPENFILES;
-    maxfds.rlim_cur = MAX_OPENFILES;   
-    if (setrlimit(RLIMIT_NOFILE, &maxfds) < 0)
-        my_perror("ERROR: Unable to set maximum file descriptor limit");
-    return 0;
-       
-error:
-    my_perror("ERROR: udsserver_init");
-    return -1;
-    }
-
-int udsserver_exit(void)
-    {
-    close(listenfd);
-    unlink(MDNS_UDS_SERVERPATH);
-    return 0;
-    }
-
-
-// add the named socket as a runloop source
-int udsserver_add_rl_source(void)
-    {
-    CFSocketContext context =  { 0, NULL, NULL, NULL, NULL };
-    CFSocketRef sr = CFSocketCreateWithNative(kCFAllocatorDefault, listenfd, kCFSocketReadCallBack, connect_callback, &context);
-    if (!sr)
-        {
-        debugf("ERROR: udsserver_add_rl_source - CFSocketCreateWithNative");
-        return -1;
-       }
-    CFRunLoopSourceRef rls = CFSocketCreateRunLoopSource(kCFAllocatorDefault, sr, 0);
-  
-    if (!rls)
-       {
-        debugf("ERROR: udsserver_add_rl_source - CFSocketCreateRunLoopSource");
-        return -1;
-       }
-    CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
-    return 0;
-    }
-
-mDNSs32 udsserver_idle(mDNSs32 nextevent)
-    {
-    request_state *req = all_requests, *tmp, *prev = NULL;
-    reply_state *fptr;
-    transfer_state result; 
-    mDNSs32 now = mDNSPlatformTimeNow();
-
-
-    while(req)
-        {
-        result = t_uninitialized;
-        if (req->u_err) 
-            result = send_undelivered_error(req);
-        if (result != t_error && result != t_morecoming &&             // don't try to send msg if send_error failed
-            (req->ts == t_complete || req->ts == t_morecoming))
-            {
-            while(req->replies)
-                {
-                if (req->replies->next) req->replies->rhdr->flags |= kDNSServiceFlagsMoreComing;
-                else req->replies->rhdr->flags |= kDNSServiceFlagsFinished;
-                result = send_msg(req->replies);
-                if (result == t_complete)
-                    {
-                    fptr = req->replies;
-                    req->replies = req->replies->next;
-                    freeL("udsserver_idle", fptr);
-                    }
-                else if (result == t_terminated || result == t_error)
-                    {
-                    abort_request(req);
-                    break;
-                    }
-                else if (result == t_morecoming)                       // client's queues are full, move to next
-                    {
-                    if (nextevent - now > mDNSPlatformOneSecond)
-                        nextevent = now + mDNSPlatformOneSecond;
-                    break;                                     // start where we left off in a second
-                    }
-                }
-            }
-        if (result == t_terminated || result == t_error)  
-        //since we're already doing a list traversal, we unlink the request manunally instead of calling unlink_request()
-            {
-            tmp = req;
-            if (prev) prev->next = req->next;
-            if (req == all_requests) all_requests = all_requests->next;
-            req = req->next;
-            freeL("udsserver_idle", tmp);
-            }
-        else 
-            {
-            prev = req;
-            req = req->next;
-            }
-        }
-    return nextevent;
-    }
-
-void udsserver_info(void)
-    {
-    request_state *req;
-    for (req = all_requests; req; req=req->next)
-        {
-        void *t = req->termination_context;
-        if (!t) continue;
-        if (req->terminate == regservice_termination_callback)
-            LogMsg("DNSServiceRegister         %##s", ((registered_service *)   t)->srs->RR_SRV.resrec.name.c);
-        else if (req->terminate == browse_termination_callback)
-            LogMsg("DNSServiceBrowse           %##s", ((DNSQuestion *)          t)->qname.c);
-        else if (req->terminate == resolve_termination_callback)
-            LogMsg("DNSServiceResolve          %##s", ((resolve_termination_t *)t)->srv->question.qname.c);
-        else if (req->terminate == question_termination_callback)
-            LogMsg("DNSServiceQueryRecord      %##s", ((DNSQuestion *)          t)->qname.c);
-        else if (req->terminate == enum_termination_callback)
-            LogMsg("DNSServiceEnumerateDomains %##s", ((enum_termination_t *)   t)->all->question.qname.c);
-        }
-    }
-
-void udsserver_handle_configchange(void)
-    {
-    registered_service *srv;
-    request_state *req;
-    mStatus err;
-    
-    for (req = all_requests; req; req = req->next)
-        {
-        srv = req->service;
-        if (srv && srv->autoname && !SameDomainLabel(srv->name.c, mDNSStorage.nicelabel.c))
-            {
-            srv->rename_on_memfree = 1;
-            err = mDNS_DeregisterService(&mDNSStorage, srv->srs);
-            if (err) LogMsg("ERROR: udsserver_handle_configchange: DeregisterService returned error %d.  Continuing.", err);
-            // error should never occur - safest to log and continue
-            }
-        }
-    }
-    
-    
-    
-
-// accept a connection on the named socket, adding the new descriptor to the runloop and passing the error
-// descriptor to the client
-static void connect_callback(CFSocketRef s, CFSocketCallBackType t, CFDataRef dr, const void *c, void *i)
-    {
-    int sd, clilen, optval;
-    struct sockaddr_un cliaddr;
-    CFSocketContext context =  { 0, NULL, NULL, NULL, NULL     };
-    request_state *rstate;
-//    int errpipe[2];
-    
-    #pragma unused(s, t, dr, c, i)
-
-    clilen = sizeof(cliaddr);
-    sd = accept(listenfd, (struct sockaddr *)&cliaddr, &clilen);
-
-    if (sd < 0)
-        {
-        if (errno == EWOULDBLOCK) return; 
-        my_perror("ERROR: accept");
-        return;
-       }
-    optval = 1;
-    if (setsockopt(sd, SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)) < 0)
-       {
-        my_perror("ERROR: setsockopt - SOL_NOSIGPIPE - aborting client");  
-        close(sd);
-        return;
-       }
-
-    if (fcntl(sd, F_SETFL, O_NONBLOCK) < 0)
-       {
-        my_perror("ERROR: could not set connected socket to non-blocking mode - aborting client");
-        close(sd);     
-        return;
-        }
-
-/*
-    // open a pipe to deliver error messages, pass descriptor to client
-    if (pipe(errpipe) < 0)
-        {
-        my_perror("ERROR: could not create pipe");
-        exit(1);
-        }
-    
-    if (ioctl(sd, I_SENDFD, errpipe[0]) < 0)
-        {
-        my_perror("ERROR: could not pass pipe descriptor to client.  Aborting client.\n");
-        close(sd);
-        return;
-        }
-    if (fcntl(errpipe[1], F_SETFL, O_NONBLOCK) < 0)
-       {
-        my_perror("ERROR: could not set error pipe to non-blocking mode - aborting client");
-        close(sd);     
-        close(errpipe[1]);
-        return;
-        }
-  */
-  
-      // allocate a request_state struct that will live with the socket
-    rstate = mallocL("connect_callback", sizeof(request_state));
-    if (!rstate)
-       {
-        my_perror("ERROR: malloc");
-        exit(1);
-       }
-    bzero(rstate, sizeof(request_state));
-    rstate->ts = t_morecoming;
-    rstate->sd = sd;
-    //rstate->errfd = errpipe[1];
-    
-    //now create CFSocket wrapper and add to run loop
-    context.info = rstate;
-    rstate->sr = CFSocketCreateWithNative(kCFAllocatorDefault, sd, kCFSocketReadCallBack, request_callback, &context);
-    if (!rstate->sr)
-       {
-        debugf("ERROR: connect_callback - CFSocketCreateWithNative");
-        freeL("connect_callback", rstate);
-        close(sd);
-        return;
-       }
-    rstate->rls = CFSocketCreateRunLoopSource(kCFAllocatorDefault, rstate->sr, 0);
-    if (!rstate->rls)
-       {
-        debugf("ERROR: connect_callback - CFSocketCreateRunLoopSource");
-        CFSocketInvalidate(rstate->sr);  // automatically closes socket
-        CFRelease(rstate->sr);
-        freeL("connect_callback", rstate);
-        return;
-       }
-    CFRunLoopAddSource(CFRunLoopGetCurrent(), rstate->rls, kCFRunLoopDefaultMode);
-    if (!CFRunLoopContainsSource(CFRunLoopGetCurrent(), rstate->rls, kCFRunLoopDefaultMode))
-        {
-        LogMsg("ERROR: connect_callback, CFRunLoopAddSource");
-        abort_request(rstate);
-        return;
-        }
-    rstate->next = all_requests;
-    all_requests = rstate;
-    }
-
-
-// main client request handling routine.  reads request and calls the appropriate request-specific
-// handler
-static void request_callback(CFSocketRef sr, CFSocketCallBackType t, CFDataRef dr, const void *context, void *info)
-    {
-    request_state *rstate = info;
-    transfer_state result;
-    struct sockaddr_un cliaddr;
-    char ctrl_path[MAX_CTLPATH];
-    
-    #pragma unused(sr, t, dr, context)
-
-    int native = CFSocketGetNative(sr);
-    if (native != rstate->sd)
-        {
-        LogMsg("ERROR: request_callback - CFSocket's native descriptor does not match rstate member descriptor.");
-        abort_request(rstate);
-        unlink_request(rstate);
-        return;
-        }
-
-    result = read_msg(rstate);
-    if (result == t_morecoming)
-       {
-        return;
-       }
-    if (result == t_terminated)
-       {
-        abort_request(rstate);
-        unlink_request(rstate);
-        return;
-       }
-    if (result == t_error)
-       {
-        abort_request(rstate);
-        unlink_request(rstate);
-        return;
-       }
-
-    if (rstate->hdr.version != VERSION)
-    {
-        LogMsg("ERROR: client incompatible with daemon (client version = %d, "
-                "daemon version = %d)\n", rstate->hdr.version, VERSION);
-        abort_request(rstate);
-        unlink_request(rstate);
-        return;
-    }
-    
-    // check if client wants silent operation
-    if (rstate->hdr.flags & IPC_FLAGS_NOREPLY) rstate->no_reply = 1;
-
-    // check if primary socket is to be used for synchronous errors, else open new socket
-    if ((rstate->hdr.flags & IPC_FLAGS_REUSE_SOCKET) == 0)
-               {
-               mStatus err = 0;
-               int nwritten;
-               int errfd = socket(AF_LOCAL, SOCK_STREAM, 0);
-        if (errfd < 0)
-            {
-            my_perror("ERROR: socket");        
-            abort_request(rstate);
-            unlink_request(rstate);
-            return;
-            }
-        if (fcntl(errfd, F_SETFL, O_NONBLOCK) < 0)
-            {
-            my_perror("ERROR: could not set control socket to non-blocking mode");
-            abort_request(rstate);
-            unlink_request(rstate);
-            return;
-            }        
-        get_string(&rstate->msgdata, ctrl_path, 256);  // path is first element in message buffer
-        bzero(&cliaddr, sizeof(cliaddr));
-        cliaddr.sun_family = AF_LOCAL;
-        strcpy(cliaddr.sun_path, ctrl_path);
-        if (connect(errfd, (struct sockaddr *)&cliaddr, sizeof(cliaddr)) < 0)
-            {
-            my_perror("ERROR: connect");
-            abort_request(rstate);
-            unlink_request(rstate);
-            }
-
-               switch (rstate->hdr.op.request_op)
-                       {
-                       case reg_record_request:    err = handle_regrecord_request   (rstate); break;
-                       case add_record_request:    err = handle_add_request         (rstate); break;
-                       case update_record_request: err = handle_update_request      (rstate); break;
-                       case remove_record_request: err = handle_removerecord_request(rstate); break;
-                       default: LogMsg("%3d: ERROR: udsserver_recv_request - unsupported request type: %d", rstate->sd, rstate->hdr.op);
-                       }
-
-               nwritten = send(errfd, &err, sizeof(err), 0);
-               // On a freshly-created Unix Domain Socket, the kernel should *never* fail to buffer a four-byte write for us.
-               // If not, we don't attempt to handle this failure, but we do log it.
-               if (nwritten < (int)sizeof(err))
-                       LogMsg("ERROR: failed to write error response back to caller: %d %d %s", nwritten, errno, strerror(errno));
-               close(errfd);
-               reset_connected_rstate(rstate);         // Reset ready to accept the next request on this pipe
-               }
-       else
-               {
-               switch (rstate->hdr.op.request_op)
-                       {
-                       case resolve_request:          handle_resolve_request   (rstate); break;
-                       case query_request:            handle_query_request     (rstate); break;
-                       case browse_request:           handle_browse_request    (rstate); break;
-                       case reg_service_request:      handle_regservice_request(rstate); break;
-                       case enumeration_request:      handle_enum_request      (rstate); break;
-                       case reconfirm_record_request: handle_reconfirm_request (rstate); break;
-                       default: LogMsg("%3d: ERROR: udsserver_recv_request - unsupported request type: %d", rstate->sd, rstate->hdr.op);
-                       }
-               }
-    }
-
-// 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.
-
-
-// query and resolve calls have separate request handlers that parse the arguments from the client and
-// massage the name parameters appropriately, but the rest of the operations (making the query call,
-// delivering the result to the client, and termination) are identical.
-
-static void handle_query_request(request_state *rstate)
-    {
-    DNSServiceFlags flags;
-    uint32_t interfaceIndex;
-    char name[256];
-    uint16_t rrtype, rrclass;
-    char *ptr;
-    domainname dname;
-    mStatus result;
-    
-    if (rstate->ts != t_complete)
-        {
-        LogMsg("ERROR: handle_query_request - transfer state != t_complete");
-        goto error;
-        }
-    ptr = rstate->msgdata;
-    if (!ptr)
-        {
-        LogMsg("ERROR: handle_query_request - NULL msgdata");
-        goto error;
-        }
-    flags = get_flags(&ptr);
-    interfaceIndex = get_long(&ptr);
-    if (get_string(&ptr, name, 256) < 0) goto bad_param;
-    rrtype = get_short(&ptr);
-    rrclass = get_short(&ptr);
-    if (!MakeDomainNameFromDNSNameString(&dname, name)) goto bad_param;
-    result = do_question(rstate, &dname, interfaceIndex, rrtype, rrclass);
-    if (result) rstate->terminate = NULL;
-    if (deliver_error(rstate, result) < 0) goto error;
-    return;
-    
-bad_param:
-    deliver_error(rstate, mStatus_BadParamErr);
-    rstate->terminate = NULL;  // don't try to terminate insuccessful Core calls
-error:
-    abort_request(rstate);
-    unlink_request(rstate);
-    return;
-    }
-
-static void handle_resolve_request(request_state *rstate)
-    {
-    DNSServiceFlags flags;
-    uint32_t interfaceIndex;
-    char name[256], regtype[MAX_ESCAPED_DOMAIN_NAME], domain[MAX_ESCAPED_DOMAIN_NAME];  
-    char *ptr;  // message data pointer
-    domainname fqdn;
-    resolve_t *srv, *txt;
-    resolve_termination_t *term;
-    mStatus err;
-    
-    if (rstate->ts != t_complete)
-        {
-        LogMsg("ERROR: handle_resolve_request - transfer state != t_complete");
-        abort_request(rstate);
-        unlink_request(rstate);
-        return;
-        }
-        
-    // extract the data from the message
-    ptr = rstate->msgdata;
-    if (!ptr)
-        {
-        LogMsg("ERROR: handle_resolve_request - NULL msgdata");
-        abort_request(rstate);
-        unlink_request(rstate);
-        return;
-        }
-    flags = get_flags(&ptr);
-    interfaceIndex = get_long(&ptr);
-    mDNSInterfaceID InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex);
-    if (interfaceIndex && !InterfaceID) goto bad_param;
-    if (get_string(&ptr, name, 256) < 0 ||
-        get_string(&ptr, regtype, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
-        get_string(&ptr, domain, MAX_ESCAPED_DOMAIN_NAME) < 0)
-        goto bad_param;
-
-    // free memory in rstate since we don't need it anymore
-    freeL("handle_resolve_request", rstate->msgbuf);
-    rstate->msgbuf = NULL;
-        
-    if (build_domainname_from_strings(&fqdn, name, regtype, domain) < 0)
-        goto bad_param;
-
-    // allocate question wrapper structs
-    srv = mallocL("handle_resolve_request", sizeof(resolve_t));
-    txt = mallocL("handle_resolve_request", sizeof(resolve_t));
-    if (!srv || !txt) goto malloc_error;
-    srv->qtype = kDNSType_SRV;
-    txt->qtype = kDNSType_TXT;
-    srv->rstate = rstate;
-    txt->rstate = rstate;
-    
-    // format questions
-    srv->question.QuestionContext = rstate;
-    srv->question.QuestionCallback = resolve_result_callback;
-    memcpy(&srv->question.qname, &fqdn, MAX_DOMAIN_NAME);
-    srv->question.qtype = kDNSType_SRV;
-    srv->question.qclass = kDNSClass_IN;
-    srv->question.InterfaceID = InterfaceID;
-
-    txt->question.QuestionContext = rstate;
-    txt->question.QuestionCallback = resolve_result_callback;
-    memcpy(&txt->question.qname, &fqdn, MAX_DOMAIN_NAME);
-    txt->question.qtype = kDNSType_TXT;
-    txt->question.qclass = kDNSClass_IN;
-    txt->question.InterfaceID = InterfaceID;
-
-    // set up termination info
-    term = mallocL("handle_resolve_request", sizeof(resolve_termination_t));
-    if (!term) goto malloc_error;
-    term->srv = srv;
-    term->txt = txt;
-    term->rstate = rstate;
-    rstate->termination_context = term;
-    rstate->terminate = resolve_termination_callback;
-    
-    // set up reply wrapper struct (since answer will come via 2 callbacks)
-    rstate->resolve_results = mallocL("handle_resolve_response", sizeof(resolve_result_t));
-    if (!rstate->resolve_results) goto malloc_error;
-    bzero(rstate->resolve_results, sizeof(resolve_result_t));
-
-    // ask the questions
-    err = mDNS_StartQuery(&mDNSStorage, &srv->question);
-    if (!err) err = mDNS_StartQuery(&mDNSStorage, &txt->question);
-
-    if (err)
-        {
-        freeL("handle_resolve_request", txt);
-        freeL("handle_resolve_request", srv);
-        freeL("handle_resolve_request", term);
-        freeL("handle_resolve_request", rstate->resolve_results);
-        rstate->terminate = NULL;  // prevent abort_request() from invoking termination callback
-        }
-    if (deliver_error(rstate, err) < 0 || err) 
-        {
-        abort_request(rstate);
-        unlink_request(rstate);
-        }
-    return;
-
-bad_param:
-    deliver_error(rstate, mStatus_BadParamErr);
-    abort_request(rstate);
-    unlink_request(rstate);
-    return;
-    
-malloc_error:
-    my_perror("ERROR: malloc");
-    exit(1);
-    }
-    
-static void resolve_termination_callback(void *context)
-    {
-    resolve_termination_t *term = context;
-    request_state *rs;
-    
-    if (!term) 
-        {
-        LogMsg("ERROR: resolve_termination_callback: double termination");
-        return;
-        }
-    rs = term->rstate;
-    
-    mDNS_StopQuery(&mDNSStorage, &term->txt->question);
-    mDNS_StopQuery(&mDNSStorage, &term->srv->question);
-    
-    freeL("resolve_termination_callback", term->txt);
-    freeL("resolve_termination_callback", term->srv);
-    freeL("resolve_termination_callback", term);
-    rs->termination_context = NULL;
-    freeL("resolve_termination_callback", rs->resolve_results);
-    rs->resolve_results = NULL;
-    }
-    
-    
-
-static void resolve_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
-{
-    int len = 0;
-    char fullname[MAX_ESCAPED_DOMAIN_NAME], target[MAX_ESCAPED_DOMAIN_NAME];
-    char *data;
-    transfer_state result;
-    reply_state *rep;
-    request_state *rs = question->QuestionContext;
-    resolve_result_t *res = rs->resolve_results;
-    #pragma unused(m)
-    
-       if (!AddRecord)
-               {
-               if (answer->rrtype == kDNSType_TXT && res->txt == answer) res->txt = mDNSNULL;
-               if (answer->rrtype == kDNSType_SRV && res->srv == answer) res->srv = mDNSNULL;
-               return;
-               }
-
-    if (answer->rrtype == kDNSType_TXT) res->txt = answer;
-    if (answer->rrtype == kDNSType_SRV) res->srv = answer;
-
-    if (!res->txt || !res->srv) return;                // only deliver result to client if we have both answers
-    
-    ConvertDomainNameToCString(&answer->name, fullname);
-    ConvertDomainNameToCString(&res->srv->rdata->u.srv.target, target);
-
-    // calculate reply length
-    len += sizeof(DNSServiceFlags);
-    len += sizeof(uint32_t);  // interface index
-    len += sizeof(DNSServiceErrorType);
-    len += strlen(fullname) + 1;
-    len += strlen(target) + 1;
-    len += 2 * sizeof(uint16_t);  // port, txtLen
-    len += res->txt->rdlength;
-    
-    // allocate/init reply header
-    rep =  create_reply(resolve_reply, len, rs);
-    rep->rhdr->flags = 0;
-    rep->rhdr->ifi =  mDNSPlatformInterfaceIndexfromInterfaceID(&mDNSStorage, answer->InterfaceID);
-    rep->rhdr->error = kDNSServiceErr_NoError;
-    data = rep->sdata;
-    
-    // write reply data to message
-    put_string(fullname, &data);
-    put_string(target, &data);
-    put_short(res->srv->rdata->u.srv.port.NotAnInteger, &data);
-    put_short(res->txt->rdlength, &data);
-    put_rdata(res->txt->rdlength, res->txt->rdata->u.txt.c, &data);
-    
-    result = send_msg(rep);
-    if (result == t_error || result == t_terminated) 
-        {  
-        abort_request(rs);  
-        unlink_request(rs);
-        freeL("resolve_result_callback", rep);  
-        }
-    else if (result == t_complete) freeL("resolve_result_callback", rep);
-    else append_reply(rs, rep);
-    }
-
-
-
-
-// common query issuing routine for resolve and query requests
-static mStatus do_question(request_state *rstate, domainname *name, uint32_t ifi, uint16_t rrtype, int16_t rrclass)
-    {
-    DNSQuestion *q;
-    mStatus result;
-    mDNSInterfaceID InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, ifi);
-    if (ifi && !InterfaceID) return(mStatus_BadParamErr);
-
-    q = mallocL("do_question", sizeof(DNSQuestion));
-    if (!q)
-       {
-        my_perror("ERROR: do_question - malloc");
-        exit(1);
-       }
-    bzero(q, sizeof(DNSQuestion));     
-
-    q->QuestionContext = rstate;
-    q->QuestionCallback = question_result_callback;
-    memcpy(&q->qname, name, MAX_DOMAIN_NAME);
-    q->qtype = rrtype;
-    q->qclass = rrclass;
-    q->InterfaceID = InterfaceID;
-
-
-    rstate->termination_context = q;
-    rstate->terminate = question_termination_callback;
-
-    result = mDNS_StartQuery(&mDNSStorage, q);
-    if (result != mStatus_NoError) LogMsg("ERROR: mDNS_StartQuery: %d", (int)result);
-    return result;
-    }
-    
-// what gets called when a resolve is completed and we need to send the data back to the client
-static void question_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
-    {
-    char *data;
-    char name[MAX_ESCAPED_DOMAIN_NAME];
-    request_state *req;
-    reply_state *rep;
-    int len;
-
-    #pragma unused(m)
-    //mDNS_StopQuery(m, question);
-    req = question->QuestionContext;
-    
-    // calculate reply data length
-    len = sizeof(DNSServiceFlags);
-    len += 2 * sizeof(uint32_t);  // if index + ttl
-    len += sizeof(DNSServiceErrorType);
-    len += 3 * sizeof(uint16_t); // type, class, rdlen
-    len += answer->rdlength;
-    ConvertDomainNameToCString(&answer->name, name);
-    len += strlen(name) + 1;
-    
-    rep =  create_reply(query_reply, len, req);
-    rep->rhdr->flags = AddRecord ? kDNSServiceFlagsAdd : kDNSServiceFlagsRemove;
-    rep->rhdr->ifi =  mDNSPlatformInterfaceIndexfromInterfaceID(&mDNSStorage, answer->InterfaceID);
-    rep->rhdr->error = kDNSServiceErr_NoError;
-    data = rep->sdata;
-    
-    put_string(name, &data);
-    put_short(answer->rrtype, &data);
-    put_short(answer->rrclass, &data);
-    put_short(answer->rdlength, &data);
-    put_rdata(answer->rdlength, (char *)&answer->rdata->u, &data);
-    put_long(AddRecord ? answer->rroriginalttl : 0, &data);
-
-    append_reply(req, rep);
-    return;
-    }
-
-static void question_termination_callback(void *context)
-    {
-    DNSQuestion *q = context;
-
-
-    mDNS_StopQuery(&mDNSStorage, q);  // no need to error check
-    freeL("question_termination_callback", q);
-    }
-
-// 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
-static char *FindFirstSubType(char *p)
-       {
-       while (*p)
-               {
-               if (p[0] == '\\' && p[1]) p += 2;
-               else if (p[0] == ',' && p[1]) { *p++ = 0; return(p); }
-               else p++;
-               }
-       return(p);
-       }
-
-// If there's a comma followed by another character,
-// FindNextSubType overwrites the comma with a nul and returns the pointer to the next character.
-// If it finds an illegal unescaped dot in the subtype name, it returns mDNSNULL
-// Otherwise, it returns a pointer to the final nul at the end of the string
-static char *FindNextSubType(char *p)
-       {
-       while (*p)
-               {
-               if (p[0] == '\\' && p[1])               // If escape character
-                       p += 2;                                         // ignore following character
-               else if (p[0] == ',')                   // If we found a comma
-                       {
-                       if (p[1]) *p++ = 0;
-                       return(p);
-                       }
-               else if (p[0] == '.')
-                       return(mDNSNULL);
-               else p++;
-               }
-       return(p);
-       }
-
-// Returns -1 if illegal subtype found
-extern mDNSs32 CountSubTypes(char *regtype);
-mDNSexport mDNSs32 CountSubTypes(char *regtype)
-       {
-       mDNSs32 NumSubTypes = 0;
-       char *stp = FindFirstSubType(regtype);
-       while (stp && *stp)                                     // If we found a comma...
-               {
-               if (*stp == ',') return(-1);
-               NumSubTypes++;
-               stp = FindNextSubType(stp);
-               }
-       if (!stp) return(-1);
-       return(NumSubTypes);
-       }
-
-extern AuthRecord *AllocateSubTypes(mDNSs32 NumSubTypes, char *p);
-mDNSexport AuthRecord *AllocateSubTypes(mDNSs32 NumSubTypes, char *p)
-       {
-       AuthRecord *st = mDNSNULL;
-       if (NumSubTypes)
-               {
-               mDNSs32 i;
-               st = mallocL("ServiceSubTypes", NumSubTypes * sizeof(AuthRecord));
-               if (!st) return(mDNSNULL);
-               for (i = 0; i < NumSubTypes; i++)
-                       {
-                       while (*p) p++;
-                       p++;
-                       if (!MakeDomainNameFromDNSNameString(&st[i].resrec.name, p))
-                               { freeL("ServiceSubTypes", st); return(mDNSNULL); }
-                       }
-               }
-       return(st);
-       }
-
-static void handle_browse_request(request_state *request)
-    {
-    DNSServiceFlags flags;
-    uint32_t interfaceIndex;
-    char regtype[MAX_ESCAPED_DOMAIN_NAME], domain[MAX_ESCAPED_DOMAIN_NAME];
-    DNSQuestion *q;
-    domainname typedn, domdn;
-    mDNSs32 NumSubTypes;
-    char *ptr;
-    mStatus result;
-
-    if (request->ts != t_complete)
-        {
-        LogMsg("ERROR: handle_browse_request - transfer state != t_complete");
-        abort_request(request);
-        unlink_request(request);
-        return;
-        }
-    q = mallocL("handle_browse_request", sizeof(DNSQuestion));
-    if (!q)
-       {
-        my_perror("ERROR: handle_browse_request - malloc");
-        exit(1);
-       }
-    bzero(q, sizeof(DNSQuestion));
-
-    // extract data from message
-    ptr = request->msgdata;
-    flags = get_flags(&ptr);
-    interfaceIndex = get_long(&ptr);
-    if (get_string(&ptr, regtype, MAX_ESCAPED_DOMAIN_NAME) < 0 || 
-        get_string(&ptr, domain, MAX_ESCAPED_DOMAIN_NAME) < 0)
-        goto bad_param;
-        
-    freeL("handle_browse_request", request->msgbuf);
-    request->msgbuf = NULL;
-
-    mDNSInterfaceID InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex);
-    if (interfaceIndex && !InterfaceID) goto bad_param;
-    q->QuestionContext = request;
-    q->QuestionCallback = browse_result_callback;
-    
-       typedn.c[0] = 0;
-       NumSubTypes = CountSubTypes(regtype);
-       if (NumSubTypes < 0 || NumSubTypes > 1) goto bad_param;
-       if (NumSubTypes == 1 && !AppendDNSNameString(&typedn, regtype + strlen(regtype) + 1)) goto bad_param;
-
-    if (!AppendDNSNameString(&typedn, regtype) ||
-        !MakeDomainNameFromDNSNameString(&domdn, domain[0] ? domain : "local."))
-        goto bad_param;
-    request->termination_context = q;
-    request->terminate = browse_termination_callback;
-    result = mDNS_StartBrowse(&mDNSStorage, q, &typedn, &domdn, InterfaceID, browse_result_callback, request);
-    deliver_error(request, result);
-    return;
-    
-bad_param:
-    deliver_error(request, mStatus_BadParamErr);
-    abort_request(request);
-    unlink_request(request);
-    }
-
-static void browse_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
-    {
-    request_state *req;
-    reply_state *rep;
-    mStatus err;
-        
-    #pragma unused(m)
-    req = question->QuestionContext;
-
-    err = gen_rr_response(&answer->rdata->u.name, answer->InterfaceID, req, &rep);
-    if (err)
-        {
-        if (deliver_async_error(req, browse_reply, err) < 0) 
-            {
-            abort_request(req);
-            unlink_request(req);
-            }
-        return;
-        }
-    if (AddRecord) rep->rhdr->flags |= kDNSServiceFlagsAdd;  // non-zero TTL indicates add
-    append_reply(req, rep);
-    return;
-    }
-
-static void browse_termination_callback(void *context)
-    {
-    DNSQuestion *q = context;
-
-    mDNS_StopBrowse(&mDNSStorage, q);  // no need to error-check result
-    freeL("browse_termination_callback", q);
-    }
-
-// service registration
-static void handle_regservice_request(request_state *request)
-    {
-    DNSServiceFlags flags;
-    uint32_t ifi;
-    char name[256], regtype[MAX_ESCAPED_DOMAIN_NAME], domain[MAX_ESCAPED_DOMAIN_NAME], host[MAX_ESCAPED_DOMAIN_NAME];
-    uint16_t txtlen;
-    mDNSIPPort port;
-    void *txtdata;
-    char *ptr;
-    domainlabel n;
-    domainname t, d, h, srv;
-    registered_service *r_srv;
-    int srs_size;
-    mStatus result;
-    mDNSs32 num_subtypes;
-
-    if (request->ts != t_complete)
-        {
-        LogMsg("ERROR: handle_regservice_request - transfer state != t_complete");
-        abort_request(request);
-        unlink_request(request);
-        return;
-        }
-
-    // extract data from message
-    ptr = request->msgdata;
-    flags = get_flags(&ptr);
-    ifi = get_long(&ptr);
-    mDNSInterfaceID InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, ifi);
-    if (ifi && !InterfaceID) goto bad_param;
-    if (get_string(&ptr, name, 256) < 0 ||
-        get_string(&ptr, regtype, MAX_ESCAPED_DOMAIN_NAME) < 0 || 
-        get_string(&ptr, domain, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
-        get_string(&ptr, host, MAX_ESCAPED_DOMAIN_NAME) < 0)
-        goto bad_param;
-        
-    port.NotAnInteger = get_short(&ptr);
-    txtlen = get_short(&ptr);
-    txtdata = get_rdata(&ptr, txtlen);
-
-       // Check for sub-types after the service type
-       num_subtypes = CountSubTypes(regtype);
-       if (num_subtypes < 0) goto bad_param;
-       
-    if (!name[0]) n = (&mDNSStorage)->nicelabel;
-    else if (!MakeDomainLabelFromLiteralString(&n, name))  
-        goto bad_param;
-    if ((!regtype[0] || !MakeDomainNameFromDNSNameString(&t, regtype)) ||
-    (!MakeDomainNameFromDNSNameString(&d, *domain ? domain : "local.")) ||
-    (!ConstructServiceName(&srv, &n, &t, &d)))
-        goto bad_param;
-    if (host[0] && !MakeDomainNameFromDNSNameString(&h, host)) goto bad_param;
-
-    r_srv = mallocL("handle_regservice_request", sizeof(registered_service));
-    if (!r_srv) goto malloc_error;
-    srs_size = sizeof(ServiceRecordSet) + (sizeof(RDataBody) > txtlen ? 0 : txtlen - sizeof(RDataBody));
-    r_srv->srs = mallocL("handle_regservice_request", srs_size);
-    if (!r_srv->srs) goto malloc_error;
-
-       r_srv->subtypes = AllocateSubTypes(num_subtypes, regtype);
-       if (num_subtypes && !r_srv->subtypes)
-               { freeL("handle_regservice_request", r_srv); r_srv = NULL; goto malloc_error; }
-    r_srv->request = request;
-    
-    r_srv->autoname = (!name[0]);
-    r_srv->rename_on_memfree = 0;
-    r_srv->renameonconflict = !(flags & kDNSServiceFlagsNoAutoRename);
-    r_srv->name = n;
-    request->termination_context = r_srv;
-    request->terminate = regservice_termination_callback;
-    request->service = r_srv;
-    
-    result = mDNS_RegisterService(&mDNSStorage, r_srv->srs, &n, &t, &d, host[0] ? &h : NULL, port,
-       txtdata, txtlen, r_srv->subtypes, num_subtypes, InterfaceID, regservice_callback, r_srv);
-    deliver_error(request, result);
-    if (result != mStatus_NoError) 
-        {
-        abort_request(request);
-        unlink_request(request);
-        }
-    else 
-        {
-        reset_connected_rstate(request);  // reset to receive add/remove messages
-        }
-    return;
-
-bad_param:
-    deliver_error(request, mStatus_BadParamErr);
-    abort_request(request);
-    unlink_request(request);
-return;
-
-malloc_error:
-    my_perror("ERROR: malloc");
-    exit(1);
-    }
-    
-// service registration callback performs three duties - frees memory for deregistered services,
-// handles name conflicts, and delivers completed registration information to the client (via
-// process_service_registraion())
-
-static void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, mStatus result)
-    {
-    mStatus err;
-    ExtraResourceRecord *extra;
-    registered_service *r_srv = srs->ServiceContext;
-    request_state *rs = r_srv->request;
-
-    #pragma unused(m)
-    
-    if (!rs && (result != mStatus_MemFree && !r_srv->rename_on_memfree))
-        {     
-        // error should never happen - safest to log and continue
-        LogMsg("ERROR: regservice_callback: received result %d with a NULL request pointer\n");
-        return;
-        }
-
-    if (result == mStatus_NoError)
-        return process_service_registration(srs);
-    else if (result == mStatus_MemFree)
-        {
-        if (r_srv->rename_on_memfree)
-            {
-            r_srv->rename_on_memfree = 0;
-            r_srv->name = mDNSStorage.nicelabel;
-            err = mDNS_RenameAndReregisterService(&mDNSStorage, srs, &r_srv->name);
-            if (err) LogMsg("ERROR: regservice_callback - RenameAndReregisterService returned %d", err);
-            // error should never happen - safest to log and continue
-            }
-        else 
-            {
-            while (r_srv->srs->Extras)
-                {
-                extra = r_srv->srs->Extras;
-                r_srv->srs->Extras = r_srv->srs->Extras->next;
-                freeL("regservice_callback", extra);
-                }
-            freeL("regservice_callback", r_srv->srs);
-            if (r_srv->subtypes) freeL("regservice_callback", r_srv->subtypes);
-            if (r_srv->request) r_srv->request->service = NULL;
-            freeL("regservice_callback", r_srv);
-            return;
-            }
-        }
-    else if (result == mStatus_NameConflict)
-       {
-        if (r_srv->autoname || r_srv->renameonconflict)
-            {
-            mDNS_RenameAndReregisterService(&mDNSStorage, srs, mDNSNULL);
-            return;
-            }
-        else
-            {
-            freeL("regservice_callback", r_srv);
-            freeL("regservice_callback", r_srv->srs);
-            if (r_srv->subtypes) freeL("regservice_callback", r_srv->subtypes);
-            if (r_srv->request) r_srv->request->service = NULL;
-            freeL("regservice_callback", r_srv);
-             if (deliver_async_error(rs, reg_service_reply, result) < 0) 
-                {
-                abort_request(rs);
-                unlink_request(rs);
-                }
-            return;
-            }
-       } 
-    else 
-        {
-        LogMsg("ERROR: unknown result in regservice_callback");
-        if (deliver_async_error(rs, reg_service_reply, result) < 0) 
-            {
-            abort_request(rs);
-            unlink_request(rs);
-            }
-        return;
-        }
-    }
-        
-static mStatus handle_add_request(request_state *rstate)
-    {
-    registered_record_entry *re;
-    ExtraResourceRecord *extra;
-    uint32_t size, ttl;
-    uint16_t rrtype, rdlen;
-    char *ptr, *rdata;
-    mStatus result;
-    DNSServiceFlags flags;
-    ServiceRecordSet *srs = rstate->service->srs;
-    
-    if (!srs)
-        {
-        LogMsg("ERROR: handle_add_request - no service record set in request state");
-        deliver_error(rstate, mStatus_UnknownErr);
-        return(-1);
-        }
-        
-    ptr = rstate->msgdata;
-    flags = get_flags(&ptr);
-    rrtype = get_short(&ptr);
-    rdlen = get_short(&ptr);
-    rdata = get_rdata(&ptr, rdlen);
-    ttl = get_long(&ptr);
-    
-    if (rdlen > sizeof(RDataBody)) size = rdlen;
-    else size = sizeof(RDataBody);
-    
-    extra = mallocL("hanle_add_request", sizeof(ExtraResourceRecord) - sizeof(RDataBody) + size);
-    if (!extra)
-        {
-        my_perror("ERROR: malloc");
-        exit(1);
-        }
-        
-    bzero(extra, sizeof(ExtraResourceRecord));  // OK if oversized rdata not zero'd
-    extra->r.resrec.rrtype = rrtype;
-    extra->r.rdatastorage.MaxRDLength = size;
-    extra->r.resrec.rdlength = rdlen;
-    memcpy(&extra->r.rdatastorage.u.data, rdata, rdlen);
-    result =  mDNS_AddRecordToService(&mDNSStorage, srs , extra, &extra->r.rdatastorage, ttl);
-    if (result) 
-        {
-        freeL("handle_add_request", rstate->msgbuf);
-        rstate->msgbuf = NULL;
-        freeL("handle_add_request", extra);
-        return(result);
-        }
-    re = mallocL("handle_add_request", sizeof(registered_record_entry));
-    if (!re)
-        {
-        my_perror("ERROR: malloc");
-        exit(1);
-        }
-    re->key = rstate->hdr.reg_index;
-    re->rr = &extra->r;
-    re->next = rstate->reg_recs;
-    rstate->reg_recs = re;
-    return(result);
-    }
-    
-static mStatus handle_update_request(request_state *rstate)
-    {
-    registered_record_entry *reptr;
-    AuthRecord *rr;
-    RData *newrd;
-    uint16_t rdlen, rdsize;
-    char *ptr, *rdata;
-    uint32_t ttl;
-    mStatus result;
-    
-    if (rstate->hdr.reg_index == TXT_RECORD_INDEX)
-        {
-        if (!rstate->service)
-            {
-            deliver_error(rstate, mStatus_BadParamErr);
-            return(-1);
-            }
-        rr  = &rstate->service->srs->RR_TXT;
-        }
-    else
-        {
-        reptr = rstate->reg_recs;
-        while(reptr && reptr->key != rstate->hdr.reg_index) reptr = reptr->next;
-        if (!reptr) deliver_error(rstate, mStatus_BadReferenceErr); 
-        rr = reptr->rr;
-        }
-
-    ptr = rstate->msgdata;
-    get_flags(&ptr);   // flags unused
-    rdlen = get_short(&ptr);
-    rdata = get_rdata(&ptr, rdlen);
-    ttl = get_long(&ptr);
-
-    if (rdlen > sizeof(RDataBody)) rdsize = rdlen;
-    else rdsize = sizeof(RDataBody);
-    newrd = mallocL("handle_update_request", sizeof(RData) - sizeof(RDataBody) + rdsize);
-    if (!newrd)
-        {
-        my_perror("ERROR: malloc");
-        exit(1);
-        }
-    newrd->MaxRDLength = rdsize;
-    memcpy(&newrd->u, rdata, rdlen);
-    result = mDNS_Update(&mDNSStorage, rr, ttl, rdlen, newrd, update_callback);
-    return(result);
-    }
-    
-static void update_callback(mDNS *const m, AuthRecord *const rr, RData *oldrd)
-    {
-    #pragma unused(m)
-    
-    if (oldrd != &rr->rdatastorage) freeL("update_callback", oldrd);
-    }
-    
-static void process_service_registration(ServiceRecordSet *const srs)
-    {
-    reply_state *rep;
-    transfer_state send_result;
-    mStatus err;
-    registered_service *r_srv = srs->ServiceContext;
-    request_state *req = r_srv->request;
-
-
-    err = gen_rr_response(&srs->RR_SRV.resrec.name, srs->RR_SRV.resrec.InterfaceID, req, &rep);
-    if (err) 
-        {
-        if (deliver_async_error(req, reg_service_reply, err) < 0)
-            {
-            abort_request(req);
-            unlink_request(req);
-            }
-        return;
-        }
-    send_result = send_msg(rep);
-    if (send_result == t_error || send_result == t_terminated) 
-        {  
-        abort_request(req);  
-        unlink_request(req);
-        freeL("process_service_registration", rep);  
-        }
-    else if (send_result == t_complete) freeL("process_service_registration", rep);
-    else append_reply(req, rep);
-    }
-
-static void regservice_termination_callback(void *context)
-    {
-    registered_service *srv = context;
-
-    // only safe to free memory if registration is not valid, ie deregister fails
-    if (mDNS_DeregisterService(&mDNSStorage, srv->srs) != mStatus_NoError)
-        {
-        freeL("regservice_callback", srv->srs);
-        if (srv->subtypes) freeL("regservice_callback", srv->subtypes);
-        freeL("regservice_callback", srv);
-        freeL("regservice_termination_callback", srv);
-        }
-    }
-
-
-static mStatus handle_regrecord_request(request_state *rstate)
-    {
-    AuthRecord *rr;
-    regrecord_callback_context *rcc;
-    registered_record_entry *re;
-    mStatus result;
-    
-    if (rstate->ts != t_complete)
-        {
-        LogMsg("ERROR: handle_regrecord_request - transfer state != t_complete");
-        abort_request(rstate);
-        unlink_request(rstate);
-        return(-1);
-        }
-        
-    rr = read_rr_from_ipc_msg(rstate->msgdata, 1);
-    if (!rr) return(mStatus_BadParamErr);
-
-    rcc = mallocL("handle_regrecord_request", sizeof(regrecord_callback_context));
-    if (!rcc) goto malloc_error;
-    rcc->rstate = rstate;
-    rcc->client_context = rstate->hdr.client_context;
-    rr->RecordContext = rcc;
-    rr->RecordCallback = regrecord_callback;
-
-    // allocate registration entry, link into list
-    re = mallocL("handle_regrecord_request", sizeof(registered_record_entry));
-    if (!re) goto malloc_error;
-    re->key = rstate->hdr.reg_index;
-    re->rr = rr;
-    re->next = rstate->reg_recs;
-    rstate->reg_recs = re;
-
-    if (!rstate->terminate)
-       {
-        rstate->terminate = connected_registration_termination;
-        rstate->termination_context = rstate;
-       }
-    
-    result = mDNS_Register(&mDNSStorage, rr);
-    return(result);
-
-malloc_error:
-    my_perror("ERROR: malloc");
-    return(-1);
-    }
-
-static void regrecord_callback(mDNS *const m, AuthRecord *const rr, mStatus result)
-    {
-    regrecord_callback_context *rcc;
-    int len;
-    reply_state *reply;
-    transfer_state ts;
-
-    #pragma unused(m)
-
-    if (result == mStatus_MemFree)     { freeL("regrecord_callback", rr);  return; }
-    rcc = rr->RecordContext;
-
-    // format result, add to the list for the request, including the client context in the header
-    len = sizeof(DNSServiceFlags);
-    len += sizeof(uint32_t);                //interfaceIndex
-    len += sizeof(DNSServiceErrorType);
-    
-    reply = create_reply(reg_record_reply, len, rcc->rstate);
-    reply->mhdr->client_context = rcc->client_context;
-    reply->rhdr->flags = 0;
-    reply->rhdr->ifi = mDNSPlatformInterfaceIndexfromInterfaceID(&mDNSStorage, rr->resrec.InterfaceID);
-    reply->rhdr->error = result;
-
-    ts = send_msg(reply);
-    if (ts == t_error || ts == t_terminated) 
-        {
-        abort_request(rcc->rstate);
-        unlink_request(rcc->rstate);
-        }
-    else if (ts == t_complete) freeL("regrecord_callback", reply);
-    else if (ts == t_morecoming) append_reply(rcc->rstate, reply);   // client is blocked, link reply into list
-    }
-
-static void connected_registration_termination(void *context)
-    {
-    registered_record_entry *fptr, *ptr = ((request_state *)context)->reg_recs;
-    while(ptr)
-       {
-        mDNS_Deregister(&mDNSStorage, ptr->rr);
-        fptr = ptr;
-        ptr = ptr->next;
-        freeL("connected_registration_termination", fptr);
-       }
-    }
-    
-
-
-static mStatus handle_removerecord_request(request_state *rstate)
-    {
-    registered_record_entry *reptr, *prev = NULL;
-    mStatus err = mStatus_UnknownErr;
-    char *ptr;
-    reptr = rstate->reg_recs;
-
-    ptr = rstate->msgdata;
-    get_flags(&ptr);   // flags unused
-
-    while(reptr)
-       {
-        if (reptr->key == rstate->hdr.reg_index)  // found match
-            {
-            if (prev) prev->next = reptr->next;
-            else rstate->reg_recs = reptr->next;
-            err  = mDNS_Deregister(&mDNSStorage, reptr->rr);
-            freeL("handle_removerecord_request", reptr);  //rr gets freed by callback
-            break;
-            }
-        prev = reptr;
-        reptr = reptr->next;
-       }
-    return(err);
-    }
-
-
-// domain enumeration
-static void handle_enum_request(request_state *rstate)
-    {
-    DNSServiceFlags flags, add_default;
-    uint32_t ifi;
-    char *ptr = rstate->msgdata;
-    domain_enum_t *def, *all;
-    enum_termination_t *term;
-    reply_state *reply;  // initial default reply
-    transfer_state tr;
-    mStatus err;
-    int result;
-    
-    if (rstate->ts != t_complete)
-        {
-        LogMsg("ERROR: handle_enum_request - transfer state != t_complete");
-        abort_request(rstate);
-        unlink_request(rstate);
-        return;
-        }
-        
-    flags = get_flags(&ptr);
-    ifi = get_long(&ptr);
-    mDNSInterfaceID InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, ifi);
-    if (ifi && !InterfaceID)
-       {
-               deliver_error(rstate, mStatus_BadParamErr);
-               abort_request(rstate);
-               unlink_request(rstate);
-       }
-
-    // allocate context structures
-    def = mallocL("handle_enum_request", sizeof(domain_enum_t));
-    all = mallocL("handle_enum_request", sizeof(domain_enum_t));
-    term = mallocL("handle_enum_request", sizeof(enum_termination_t));
-    if (!def || !all || !term)
-       {
-        my_perror("ERROR: malloc");
-        exit(1);
-       }
-
-    // enumeration requires multiple questions, so we must link all the context pointers so that
-    // necessary context can be reached from the callbacks
-    def->rstate = rstate;
-    all->rstate = rstate;
-    term->def = def;
-    term->all = all;
-    term->rstate = rstate;
-    rstate->termination_context = term;
-    rstate->terminate = enum_termination_callback;
-    def->question.QuestionContext = def;
-    def->type = (flags & kDNSServiceFlagsRegistrationDomains) ? 
-        mDNS_DomainTypeRegistrationDefault: mDNS_DomainTypeBrowseDefault;
-    all->question.QuestionContext = all;
-    all->type = (flags & kDNSServiceFlagsRegistrationDomains) ? 
-        mDNS_DomainTypeRegistration : mDNS_DomainTypeBrowse;
-    
-    // make the calls
-    err = mDNS_GetDomains(&mDNSStorage, &all->question, all->type, InterfaceID, enum_result_callback, all);
-    if (err == mStatus_NoError)
-        err = mDNS_GetDomains(&mDNSStorage, &def->question, def->type, InterfaceID, enum_result_callback, def);
-    result = deliver_error(rstate, err);  // send error *before* returning local domain
-    
-    if (result < 0 || err)
-        {
-        abort_request(rstate);
-        unlink_request(rstate);
-        return;
-        }
-
-    // provide local. as the first domain automatically
-    add_default = kDNSServiceFlagsDefault | kDNSServiceFlagsAdd | kDNSServiceFlagsFinished;
-    reply = format_enumeration_reply(rstate, "local.", add_default, ifi, 0);
-    tr = send_msg(reply);
-    if (tr == t_error || tr == t_terminated) 
-        {
-        freeL("handle_enum_request", def);
-        freeL("handle_enum_request", all);
-        abort_request(rstate);
-        unlink_request(rstate);
-        return;
-        }
-    if (tr == t_complete) freeL("handle_enum_request", reply);
-    if (tr == t_morecoming) append_reply(rstate, reply); // couldn't send whole reply because client is blocked - link into list
-    }
-
-static void enum_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
-    {
-    char domain[MAX_ESCAPED_DOMAIN_NAME];
-    domain_enum_t *de = question->QuestionContext;
-    DNSServiceFlags flags = 0;
-    reply_state *reply;
-
-    #pragma unused(m)
-    if (answer->rrtype != kDNSType_PTR) return;
-    if (AddRecord)
-       {
-        flags |= kDNSServiceFlagsAdd;
-        if (de->type == mDNS_DomainTypeRegistrationDefault || de->type == mDNS_DomainTypeBrowseDefault)
-            flags |= kDNSServiceFlagsDefault;
-       }
-    else
-       {
-        flags |= kDNSServiceFlagsRemove;
-       }
-    ConvertDomainNameToCString(&answer->rdata->u.name, domain);
-    reply = format_enumeration_reply(de->rstate, domain, flags, mDNSPlatformInterfaceIndexfromInterfaceID(&mDNSStorage, answer->InterfaceID), kDNSServiceErr_NoError);
-    if (!reply)
-       {
-        LogMsg("ERROR: enum_result_callback, format_enumeration_reply");
-        return;
-       }
-    reply->next = NULL;
-    append_reply(de->rstate, reply);
-    return;
-    }
-
-static reply_state *format_enumeration_reply(request_state *rstate, char *domain, DNSServiceFlags flags, uint32_t ifi, DNSServiceErrorType err)
-    {
-    int len;
-    reply_state *reply;
-    char *data;
-    
-    
-    len = sizeof(DNSServiceFlags);
-    len += sizeof(uint32_t);
-    len += sizeof(DNSServiceErrorType);
-    len += strlen(domain) + 1;
-  
-    reply = create_reply(enumeration_reply, len, rstate);
-    reply->rhdr->flags = flags;
-    reply->rhdr->ifi = ifi;  
-    reply->rhdr->error = err;
-    data = reply->sdata;
-    put_string(domain, &data);
-    return reply;
-    }
-
-static void enum_termination_callback(void *context)
-    {
-    enum_termination_t *t = context;
-    mDNS *coredata = &mDNSStorage;
-
-    mDNS_StopGetDomains(coredata, &t->all->question);
-    mDNS_StopGetDomains(coredata, &t->def->question);
-    freeL("enum_termination_callback", t->all);
-    freeL("enum_termination_callback", t->def);
-    t->rstate->termination_context = NULL;
-    freeL("enum_termination_callback", t);
-    }
-
-static void handle_reconfirm_request(request_state *rstate)
-    {
-    AuthRecord *rr;
-
-    rr = read_rr_from_ipc_msg(rstate->msgdata, 0);
-    if (!rr) return;
-    mDNS_ReconfirmByValue(&mDNSStorage, &rr->resrec);
-    abort_request(rstate);
-    unlink_request(rstate);
-    freeL("handle_reconfirm_request", rr);
-    }
-
-
-// setup rstate to accept new reg/dereg requests
-static void reset_connected_rstate(request_state *rstate)
-    {
-    rstate->ts = t_morecoming;
-    rstate->hdr_bytes = 0;
-    rstate->data_bytes = 0;
-    if (rstate->msgbuf) freeL("reset_connected_rstate", rstate->msgbuf);
-    rstate->msgbuf = NULL;
-    rstate->bufsize = 0;
-    }
-
-
-
-// returns a resource record (allocated w/ malloc) containing the data found in an IPC message
-// data must be in format flags, interfaceIndex, name, rrtype, rrclass, rdlen, rdata, (optional)ttl
-// (ttl only extracted/set if ttl argument is non-zero).  returns NULL for a bad-parameter error
-static AuthRecord *read_rr_from_ipc_msg(char *msgbuf, int ttl)
-    {
-    char *rdata, name[256];
-    AuthRecord *rr;
-    DNSServiceFlags flags;
-    uint32_t interfaceIndex;
-    uint16_t type, class, rdlen;
-    int storage_size;
-
-    flags = get_flags(&msgbuf);
-    interfaceIndex = get_long(&msgbuf);
-    if (get_string(&msgbuf, name, 256) < 0)
-        {
-        LogMsg("ERROR: read_rr_from_ipc_msg - get_string");
-        return NULL;
-        }
-    type = get_short(&msgbuf);    
-    class = get_short(&msgbuf);
-    rdlen = get_short(&msgbuf);
-
-    if (rdlen > sizeof(RDataBody)) storage_size = rdlen;
-    else storage_size = sizeof(RDataBody);
-    
-    rr = mallocL("read_rr_from_ipc_msg", sizeof(AuthRecord) - sizeof(RDataBody) + storage_size);
-    if (!rr)   
-        { 
-        my_perror("ERROR: malloc");  
-        exit(1);
-        }
-    bzero(rr, sizeof(AuthRecord));  // ok if oversized rdata not zero'd
-    rr->resrec.rdata = &rr->rdatastorage;
-    rr->resrec.InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex);
-    if (!MakeDomainNameFromDNSNameString(&rr->resrec.name, name))
-       {
-        LogMsg("ERROR: bad name: %s", name);
-        freeL("read_rr_from_ipc_msg", rr);
-        return NULL;
-       }
-    rr->resrec.rrtype = type;
-    if ((flags & kDNSServiceFlagsShared) == kDNSServiceFlagsShared)
-        rr->resrec.RecordType = kDNSRecordTypeShared;
-    if ((flags & kDNSServiceFlagsUnique) == kDNSServiceFlagsUnique)
-        rr->resrec.RecordType = kDNSRecordTypeUnique;
-    rr->resrec.rrclass = class;
-    rr->resrec.rdlength = rdlen;
-    rr->resrec.rdata->MaxRDLength = rdlen;
-    rdata = get_rdata(&msgbuf, rdlen);
-    memcpy(rr->resrec.rdata->u.data, rdata, rdlen);
-    if (ttl)   
-       {
-        rr->resrec.rroriginalttl = get_long(&msgbuf);
-       }
-    return rr;
-    }
-
-
-// generate a response message for a browse result, service registration result, or any other call with the
-// identical callback signature.  on successful completion rep is set to point to a malloc'd reply_state struct,
-// and mStatus_NoError is returned.  otherwise the appropriate error is returned.
-
-static mStatus gen_rr_response(domainname *servicename, mDNSInterfaceID id, request_state *request, reply_state **rep)
-    {
-    char *data;
-    int len;
-    domainlabel name;
-    domainname type, dom;
-       char namestr[MAX_DOMAIN_LABEL+1];               // Unescaped name: up to 63 bytes plus C-string terminating NULL.
-       char typestr[MAX_ESCAPED_DOMAIN_NAME];
-       char domstr [MAX_ESCAPED_DOMAIN_NAME];
-
-    *rep = NULL;
-    
-    if (!DeconstructServiceName(servicename, &name, &type, &dom))
-        return kDNSServiceErr_Unknown;
-
-    ConvertDomainLabelToCString_unescaped(&name, namestr);
-    ConvertDomainNameToCString(&type, typestr);
-    ConvertDomainNameToCString(&dom, domstr);
-
-    // calculate reply data length
-    len = sizeof(DNSServiceFlags);
-    len += sizeof(uint32_t);  // if index
-    len += sizeof(DNSServiceErrorType);
-    len += strlen(namestr) + 1;
-    len += strlen(typestr) + 1;
-    len += strlen(domstr) + 1;
-    
-    *rep = create_reply(query_reply, len, request);
-    (*rep)->rhdr->flags = 0;
-    (*rep)->rhdr->ifi = mDNSPlatformInterfaceIndexfromInterfaceID(&mDNSStorage, id);
-    (*rep)->rhdr->error = kDNSServiceErr_NoError;    
-    data = (*rep)->sdata;
-    
-    put_string(namestr, &data);
-    put_string(typestr, &data);
-    put_string(domstr, &data);
-    return mStatus_NoError;
-    }
-
-
-static int build_domainname_from_strings(domainname *srv, char *name, char *regtype, char *domain)
-    {
-    domainlabel n;
-    domainname d, t;
-
-    if (!MakeDomainLabelFromLiteralString(&n, name)) return -1;
-    if (!MakeDomainNameFromDNSNameString(&t, regtype)) return -1;
-    if (!MakeDomainNameFromDNSNameString(&d, domain)) return -1;
-    if (!ConstructServiceName(srv, &n, &t, &d)) return -1;
-    return 0;
-    }
-
-
-// append a reply to the list in a request object
-static void append_reply(request_state *req, reply_state *rep)
-    {
-    reply_state *ptr;
-
-    if (!req->replies) req->replies = rep;
-    else
-       {
-        ptr = req->replies;
-        while (ptr->next) ptr = ptr->next;
-        ptr->next = rep;
-       }
-    rep->next = NULL;
-    }
-
-
-// read_msg may be called any time when the transfer state (rs->ts) is t_morecoming.
-// returns the current state of the request (morecoming, error, complete, terminated.)
-// if there is no data on the socket, the socket will be closed and t_terminated will be returned
-static int read_msg(request_state *rs)
-    {
-    uint32_t nleft;
-    int nread;
-    char buf[4];   // dummy for death notification 
-    
-    if (rs->ts == t_terminated || rs->ts == t_error)
-        {
-        LogMsg("ERROR: read_msg called with transfer state terminated or error");
-        rs->ts = t_error;
-        return t_error;
-        }
-        
-    if (rs->ts == t_complete)
-       {  // this must be death or something is wrong
-        nread = recv(rs->sd, buf, 4, 0);
-        if (!nread)    {  rs->ts = t_terminated;  return t_terminated;         }
-        if (nread < 0) goto rerror;
-        LogMsg("ERROR: read data from a completed request.");
-        rs->ts = t_error;
-        return t_error;
-       }
-
-    if (rs->ts != t_morecoming)
-        {
-        LogMsg("ERROR: read_msg called with invalid transfer state (%d)", rs->ts);
-        rs->ts = t_error;
-        return t_error;
-        }
-        
-    if (rs->hdr_bytes < sizeof(ipc_msg_hdr))
-       {
-        nleft = sizeof(ipc_msg_hdr) - rs->hdr_bytes;
-        nread = recv(rs->sd, (char *)&rs->hdr + rs->hdr_bytes, nleft, 0);
-        if (nread == 0)        { rs->ts = t_terminated;  return t_terminated;          }
-        if (nread < 0) goto rerror;
-        rs->hdr_bytes += nread;
-        if (rs->hdr_bytes > sizeof(ipc_msg_hdr))
-            {
-            LogMsg("ERROR: read_msg - read too many header bytes");
-            rs->ts = t_error;
-            return t_error;
-            }
-       }
-
-    // only read data if header is complete
-    if (rs->hdr_bytes == sizeof(ipc_msg_hdr))
-       {
-        if (rs->hdr.datalen == 0)  // ok in removerecord requests
-            {
-            rs->ts = t_complete;
-            rs->msgbuf = NULL;
-            return t_complete;
-            }
-        
-        if (!rs->msgbuf)  // allocate the buffer first time through
-            {
-            rs->msgbuf = mallocL("read_msg", rs->hdr.datalen);
-            if (!rs->msgbuf)
-               {
-                my_perror("ERROR: malloc");
-                rs->ts = t_error;
-                return t_error;
-               }
-            rs->msgdata = rs->msgbuf;
-            }
-        nleft = rs->hdr.datalen - rs->data_bytes;
-        nread = recv(rs->sd, rs->msgbuf + rs->data_bytes, nleft, 0);
-        if (nread == 0)        { rs->ts = t_terminated;  return t_terminated;  }
-        if (nread < 0) goto rerror;
-        rs->data_bytes += nread;
-        if (rs->data_bytes > rs->hdr.datalen)
-            {
-            LogMsg("ERROR: read_msg - read too many data bytes");
-            rs->ts = t_error;
-            return t_error;
-            }
-        }
-
-    if (rs->hdr_bytes == sizeof(ipc_msg_hdr) && rs->data_bytes == rs->hdr.datalen)
-        rs->ts = t_complete;
-    else rs->ts = t_morecoming;
-
-    return rs->ts;
-
-rerror:
-    if (errno == EAGAIN || errno == EINTR) return rs->ts;      
-    my_perror("ERROR: read_msg");
-    rs->ts = t_error;
-    return t_error;
-    }
-
-
-static int send_msg(reply_state *rs)
-    {
-    ssize_t nwriten;
-    
-    if (!rs->msgbuf)
-        {
-        LogMsg("ERROR: send_msg called with NULL message buffer");
-        return t_error;
-        }
-    
-    if (rs->request->no_reply) //!!!KRS this behavior should be optimized if it becomes more common
-        {
-        rs->ts = t_complete;
-        freeL("send_msg", rs->msgbuf);
-        return t_complete;
-        }
-
-    nwriten = send(rs->sd, rs->msgbuf + rs->nwriten, rs->len - rs->nwriten, 0);
-    if (nwriten < 0)
-       {
-        if (errno == EINTR || errno == EAGAIN) nwriten = 0;
-        else
-            {
-            if (errno == EPIPE)
-               {
-                LogMsg("broken pipe - cleanup should be handled by run-loop read wakeup");
-                rs->ts = t_terminated;
-                rs->request->ts = t_terminated;
-                return t_terminated;  
-               }
-            else
-               {
-                my_perror("ERROR: send\n");
-                rs->ts = t_error;
-                return t_error;
-               }
-            }
-        }
-    rs->nwriten += nwriten;
-
-    if (rs->nwriten == rs->len)
-       {
-        rs->ts = t_complete;
-        freeL("send_msg", rs->msgbuf);
-       }
-    return rs->ts;
-    }
-
-
-
-static reply_state *create_reply(reply_op_t op, int datalen, request_state *request)
-{
-    reply_state *reply;
-    int totallen;
-
-    
-    if ((unsigned)datalen < sizeof(reply_hdr))
-        {
-        LogMsg("ERROR: create_reply - data length less than lenght of required fields");
-        return NULL;
-        }
-    
-    totallen = datalen + sizeof(ipc_msg_hdr);
-    reply = mallocL("create_reply", sizeof(reply_state));
-    if (!reply) 
-        {
-        my_perror("ERROR: malloc");
-        exit(1);
-        }
-    bzero(reply, sizeof(reply_state));
-    reply->ts = t_morecoming;
-    reply->sd = request->sd;
-    reply->request = request;
-    reply->len = totallen;
-    reply->msgbuf = mallocL("create_reply", totallen);
-    if (!reply->msgbuf)
-        {
-        my_perror("ERROR: malloc");
-        exit(1);
-        }
-    bzero(reply->msgbuf, totallen);
-    reply->mhdr = (ipc_msg_hdr *)reply->msgbuf;
-    reply->rhdr = (reply_hdr *)(reply->msgbuf + sizeof(ipc_msg_hdr));
-    reply->sdata = reply->msgbuf + sizeof(ipc_msg_hdr) + sizeof(reply_hdr);
-    reply->mhdr->version = VERSION;
-    reply->mhdr->op.reply_op = op;
-    reply->mhdr->datalen = totallen - sizeof(ipc_msg_hdr);
-    return reply;
-    }
-
-
-static int deliver_error(request_state *rstate, mStatus err)
-    {
-    int nwritten = -1;
-    undelivered_error_t *undeliv;
-    
-    nwritten = send(rstate->sd, &err, sizeof(mStatus), 0);
-    if (nwritten < (int)sizeof(mStatus))
-        {
-        if (errno == EINTR || errno == EAGAIN)   
-            nwritten = 0;
-        if (nwritten < 0)
-            {
-            my_perror("ERROR: send - unable to deliver error to client");
-            goto error;
-            }
-        //client blocked - store result and come backr
-        undeliv = mallocL("deliver_error", sizeof(undelivered_error_t));
-        if (!undeliv)
-            {
-            my_perror("ERROR: malloc");
-            exit(1);
-            }
-        undeliv->err = err;
-        undeliv->nwritten = nwritten;
-        undeliv->sd = rstate->sd;
-        rstate->u_err = undeliv;
-        return 0;
-    }
-    return 0;
-    
-error:
-    return -1;
-    
-    }
-           
-
-// returns 0 on success, -1 if send is incomplete, or on terminal failre (request is aborted)
-static transfer_state send_undelivered_error(request_state *rs)
-    {
-    int nwritten;
-    
-    nwritten = send(rs->u_err->sd, (char *)(&rs->u_err) + rs->u_err->nwritten, sizeof(mStatus) - rs->u_err->nwritten, 0);
-    if (nwritten < 0)
-        {
-        if (errno == EINTR || errno == EAGAIN)
-            nwritten = 0;
-        else
-            {
-            my_perror("ERROR: send - unable to deliver error to client\n");
-            if (rs->u_err->sd == rs->sd) close (rs->u_err->sd);
-            return t_error;
-            }
-        }
-    if (nwritten + rs->u_err->nwritten == sizeof(mStatus))
-        {
-        if (rs->u_err->sd == rs->sd) close(rs->u_err->sd);
-        freeL("send_undelivered_error", rs->u_err);
-        rs->u_err = NULL;
-        return t_complete;
-        }
-    rs->u_err->nwritten += nwritten;
-    return t_morecoming;
-    }
-
-
-// send bogus data along with an error code to the app callback
-// returns 0 on success (linking reply into list of not fully delivered),
-// -1 on failure (request should be aborted)
-static int deliver_async_error(request_state *rs, reply_op_t op, mStatus err)
-    {
-    int len;
-    reply_state *reply;
-    transfer_state ts;
-    
-    if (rs->no_reply) return 0;
-    len = 256;         // long enough for any reply handler to read all args w/o buffer overrun
-    reply = create_reply(op, len, rs);
-    reply->rhdr->error = err;
-    ts = send_msg(reply);
-    if (ts == t_error || ts == t_terminated)
-        {
-        freeL("deliver_async_error", reply);
-        return -1;
-        }
-    else if (ts == t_complete) freeL("deliver_async_error", reply);
-    else if (ts == t_morecoming) append_reply(rs, reply);   // client is blocked, link reply into list
-    return 0;
-    }
-
-
-static void abort_request(request_state *rs)
-    {
-    reply_state *rep, *ptr;
-
-    if (rs->terminate) rs->terminate(rs->termination_context);  // terminate field may not be set yet
-    if (rs->msgbuf) freeL("abort_request", rs->msgbuf);
-    CFRunLoopRemoveSource(CFRunLoopGetCurrent(), rs->rls, kCFRunLoopDefaultMode);
-    CFRunLoopSourceInvalidate(rs->rls);
-    CFRelease(rs->rls);
-    CFSocketInvalidate(rs->sr);
-    CFRelease(rs->sr);
-    rs->sd = -1;
-
-    // free pending replies
-    rep = rs->replies;
-    while(rep)
-       {
-        if (rep->msgbuf) freeL("abort_request", rep->msgbuf);
-        ptr = rep;
-        rep = rep->next;
-        freeL("abort_request", ptr);
-       }
-    
-    if (rs->u_err)
-        {
-        freeL("abort_request", rs->u_err);
-        rs->u_err = NULL;
-        }
-    }
-
-
-static void unlink_request(request_state *rs)
-    {
-    request_state *ptr;
-    
-    if (rs == all_requests)
-        {
-        all_requests = all_requests->next;
-        freeL("unlink_request", rs);
-        return;
-        }
-    for(ptr = all_requests; ptr->next; ptr = ptr->next)
-        if (ptr->next == rs)
-            {
-            ptr->next = rs->next;
-            freeL("unlink_request", rs);
-            return;
-        }
-    }
-    
-
-
-//hack to search-replace perror's to LogMsg's
-static void my_perror(char *errmsg)
-    {
-    LogMsg("%s: %s", errmsg, strerror(errno));
-    }
-
-
index bf223d1eb4c256ef82474066cad77c7d1c1cd04f..193272d27237ed33d9a9bffc1b0f23e4f029b335 100755 (executable)
@@ -3,6 +3,8 @@
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
index a0531bccc67dbfc6ade814e04a0ca78be1373d3d..85613882e1d850979e8664c4f72a3ab43c0edf88 100644 (file)
@@ -3,6 +3,8 @@
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
index 4274a46cc37686dda140d49e46ccc9ada1052bad..d9b20c5bb569ae93f1c448c0aad0706ad964a3cb 100644 (file)
@@ -3,6 +3,8 @@
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
index 412f82932a1d88a79a0bd0bfe76a960e8921dbd7..ed9fd7d3f06515fefcac127fc079cf837a4b4713 100644 (file)
@@ -3,6 +3,8 @@
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
     Change History (most recent first):
 
 $Log: Identify.c,v $
+Revision 1.23  2004/05/18 23:51:26  cheshire
+Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
+
+Revision 1.22  2004/04/20 22:43:28  cheshire
+Use _services._dns-sd._udp query, as documented in
+<http://files.dns-sd.org/draft-cheshire-dnsext-dns-sd-02.txt>
+
+Revision 1.21  2004/01/28 21:38:57  cheshire
+Also ask target host for _services._mdns._udp.local. list
+
+Revision 1.20  2004/01/28 19:04:38  cheshire
+Fix Ctrl-C handling when multiple targets are specified
+
+Revision 1.19  2004/01/28 03:49:30  cheshire
+Enhanced mDNSIdentify to make use of new targeted-query capability
+
+Revision 1.18  2004/01/27 19:06:51  cheshire
+Remove workaround for WWDC 2003 bug; no one has run that buggy build for a long time
+
+Revision 1.17  2004/01/22 03:57:00  cheshire
+Use the new meta-interface mDNSInterface_ForceMCast. This restores mDNSIdentify's
+ability to use multicast queries with non-link-local target addresses, like 17.x.x.x.
+
+Revision 1.16  2004/01/22 00:03:32  cheshire
+Add while() loop so that a list of targets may be specified on the command line
+
+Revision 1.15  2004/01/21 21:55:06  cheshire
+Don't need to wait for timeout once we've got the information we wanted
+
+Revision 1.14  2003/12/17 00:51:22  cheshire
+Changed mDNSNetMonitor and mDNSIdentify to link the object files
+instead of #including the "DNSCommon.c" "uDNS.c" and source files
+
+Revision 1.13  2003/12/13 03:05:28  ksekar
+<rdar://problem/3192548>: DynDNS: Unicast query of service records
+
 Revision 1.12  2003/11/14 21:27:09  cheshire
 <rdar://problem/3484766>: Security: Crashing bug in mDNSResponder
 Fix code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1005) instead of 256-byte buffers.
@@ -114,6 +152,7 @@ static CacheRecord gRRCache[RR_CACHE_SIZE];
 static volatile int StopNow;   // 0 means running, 1 means stop because we got an answer, 2 means stop because of Ctrl-C
 static volatile int NumAnswers, NumAddr, NumAAAA, NumHINFO;
 static char hostname[MAX_ESCAPED_DOMAIN_NAME], hardware[256], software[256];
+static mDNSAddr lastsrc, hostaddr, target;
 static mDNSOpaque16 lastid, id;
 
 //*************************************************************************************************************
@@ -142,6 +181,11 @@ mDNSexport void mDNSCoreReceive(mDNS *const m, DNSMessage *const msg, const mDNS
        {
        // Snag copy of header ID, then call through
        lastid = msg->h.id;
+       lastsrc = *srcaddr;
+
+       // We *want* to allow off-net unicast responses here.
+       // For now, the simplest way to allow that is to smash the TTL to 255 so that mDNSCore doesn't reject the packet
+       ttl = 255;
        __MDNS__mDNSCoreReceive(m, msg, end, srcaddr, srcport, dstaddr, dstport, InterfaceID, ttl);
        }
 
@@ -151,9 +195,12 @@ static void NameCallback(mDNS *const m, DNSQuestion *question, const ResourceRec
        (void)question; // Unused
        (void)AddRecord;// Unused
        if (!id.NotAnInteger) id = lastid;
-       ConvertDomainNameToCString(&answer->rdata->u.name, hostname);
-       StopNow = 1;
-       mprintf("%##s %s %##s\n", answer->name.c, DNSTypeName(answer->rrtype), &answer->rdata->u.name.c);
+       if (answer->rrtype == kDNSType_PTR || answer->rrtype == kDNSType_CNAME)
+               {
+               ConvertDomainNameToCString(&answer->rdata->u.name, hostname);
+               StopNow = 1;
+               mprintf("%##s %s %##s\n", answer->name.c, DNSTypeName(answer->rrtype), &answer->rdata->u.name.c);
+               }
        }
 
 static void InfoCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
@@ -167,6 +214,8 @@ static void InfoCallback(mDNS *const m, DNSQuestion *question, const ResourceRec
                NumAnswers++;
                NumAddr++;
                mprintf("%##s %s %.4a\n", answer->name.c, DNSTypeName(answer->rrtype), &answer->rdata->u.ip);
+               hostaddr.type = mDNSAddrType_IPv4;      // Prefer v4 target to v6 target, for now
+               hostaddr.ip.v4 = answer->rdata->u.ip;
                }
        else if (answer->rrtype == kDNSType_AAAA)
                {
@@ -174,6 +223,11 @@ static void InfoCallback(mDNS *const m, DNSQuestion *question, const ResourceRec
                NumAnswers++;
                NumAAAA++;
                mprintf("%##s %s %.16a\n", answer->name.c, DNSTypeName(answer->rrtype), &answer->rdata->u.ipv6);
+               if (!hostaddr.type)     // Prefer v4 target to v6 target, for now
+                       {
+                       hostaddr.type = mDNSAddrType_IPv6;
+                       hostaddr.ip.v6 = answer->rdata->u.ipv6;
+                       }
                }
        else if (answer->rrtype == kDNSType_HINFO)
                {
@@ -186,6 +240,26 @@ static void InfoCallback(mDNS *const m, DNSQuestion *question, const ResourceRec
                NumAnswers++;
                NumHINFO++;
                }
+
+       // If we've got everything we're looking for, don't need to wait any more
+       if (NumHINFO && (NumAddr || NumAAAA)) StopNow = 1;
+       }
+
+static void ServicesCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
+       {
+       (void)m;                // Unused
+       (void)question; // Unused
+       (void)AddRecord;// Unused
+       // Right now the mDNSCore targeted-query code is incomplete --
+       // it issues targeted queries, but accepts answers from anywhere
+       // For now, we'll just filter responses here so we don't get confused by responses from someone else
+       if (answer->rrtype == kDNSType_PTR && mDNSSameAddress(&lastsrc, &target))
+               {
+               NumAnswers++;
+               NumAddr++;
+               mprintf("%##s %s %##s\n", answer->name.c, DNSTypeName(answer->rrtype), &answer->rdata->u.name.c);
+               StopNow = 1;
+               }
        }
 
 mDNSexport void WaitForAnswer(mDNS *const m, int seconds)
@@ -215,11 +289,13 @@ mDNSexport void WaitForAnswer(mDNS *const m, int seconds)
                }
        }
 
-mDNSlocal mStatus StartQuery(DNSQuestion *q, char *qname, mDNSu16 qtype, mDNSQuestionCallback callback)
+mDNSlocal mStatus StartQuery(DNSQuestion *q, char *qname, mDNSu16 qtype, const mDNSAddr *target, mDNSQuestionCallback callback)
        {
        if (qname) MakeDomainNameFromDNSNameString(&q->qname, qname);
-
-       q->InterfaceID      = mDNSInterface_Any;
+       q->Target           = target ? *target : zeroAddr;
+       q->TargetPort       = MulticastDNSPort;
+       q->TargetQID        = zeroID;
+       q->InterfaceID      = mDNSInterface_ForceMCast;
        q->qtype            = qtype;
        q->qclass           = kDNSClass_IN;
        q->QuestionCallback = callback;
@@ -229,18 +305,28 @@ mDNSlocal mStatus StartQuery(DNSQuestion *q, char *qname, mDNSu16 qtype, mDNSQue
        return(mDNS_StartQuery(&mDNSStorage, q));
        }
 
-mDNSlocal int DoQuery(DNSQuestion *q, char *qname, mDNSu16 qtype, mDNSQuestionCallback callback)
+mDNSlocal void DoOneQuery(DNSQuestion *q, char *qname, mDNSu16 qtype, const mDNSAddr *target, mDNSQuestionCallback callback)
        {
-       mStatus status = StartQuery(q, qname, qtype, callback);
+       mStatus status = StartQuery(q, qname, qtype, target, callback);
        if (status != mStatus_NoError)
                StopNow = 2;
        else
                {
                WaitForAnswer(&mDNSStorage, 4);
                mDNS_StopQuery(&mDNSStorage, q);
-               if (StopNow == 0 && NumAnswers == 0)
-                       printf("%s %s *** No Answer ***\n", qname, DNSTypeName(qtype));
                }
+       }
+
+mDNSlocal int DoQuery(DNSQuestion *q, char *qname, mDNSu16 qtype, const mDNSAddr *target, mDNSQuestionCallback callback)
+       {
+       DoOneQuery(q, qname, qtype, target, callback);
+       if (StopNow == 0 && target && target->type)
+               {
+               mprintf("%##s %s Trying multicast\n", q->qname.c, DNSTypeName(q->qtype));
+               DoOneQuery(q, qname, qtype, NULL, callback);
+               }
+       if (StopNow == 0 && NumAnswers == 0)
+               mprintf("%##s %s *** No Answer ***\n", q->qname.c, DNSTypeName(q->qtype));
        return(StopNow);
        }
 
@@ -254,6 +340,7 @@ mDNSlocal void HandleSIG(int signal)
 
 mDNSexport int main(int argc, char **argv)
        {
+       int this_arg = 1;
        mStatus status;
        struct in_addr s4;
        struct in6_addr s6;
@@ -262,6 +349,9 @@ mDNSexport int main(int argc, char **argv)
 
        if (argc < 2) goto usage;
        
+       // Since this is a special command-line tool, we want LogMsg() errors to go to stderr, not syslog
+       mDNS_DebugMode = mDNStrue;
+       
     // Initialise the mDNS core.
        status = mDNS_Init(&mDNSStorage, &PlatformStorage,
        gRRCache, RR_CACHE_SIZE,
@@ -272,63 +362,80 @@ mDNSexport int main(int argc, char **argv)
        signal(SIGINT, HandleSIG);      // SIGINT is what you get for a Ctrl-C
        signal(SIGTERM, HandleSIG);
 
-       if (inet_pton(AF_INET, argv[1], &s4) == 1)
+       while (this_arg < argc)
                {
-               mDNSu8 *p = (mDNSu8 *)&s4;
-               mDNS_snprintf(buffer, sizeof(buffer), "%d.%d.%d.%d.in-addr.arpa.", p[3], p[2], p[1], p[0]);
-               printf("%s\n", buffer);
-               if (DoQuery(&q, buffer, kDNSType_PTR, NameCallback) != 1) goto exit;
-               }
-       else if (inet_pton(AF_INET6, argv[1], &s6) == 1)
-               {
-               DNSQuestion q1, q2;
-               int i;
-               mDNSu8 *p = (mDNSu8 *)&s6;
-               for (i = 0; i < 16; i++)
-                       {
-                       static const char hexValues[] = "0123456789ABCDEF";
-                       buffer[i * 4    ] = hexValues[p[15-i] & 0x0F];
-                       buffer[i * 4 + 1] = '.';
-                       buffer[i * 4 + 2] = hexValues[p[15-i] >> 4];
-                       buffer[i * 4 + 3] = '.';
-                       }
-               mDNS_snprintf(&buffer[64], sizeof(buffer)-64, "ip6.arpa.");
-               MakeDomainNameFromDNSNameString(&q1.qname, buffer);
-               mDNS_snprintf(&buffer[32], sizeof(buffer)-32, "ip6.arpa.");     // Workaround for WWDC bug
-               MakeDomainNameFromDNSNameString(&q2.qname, buffer);
-               StartQuery(&q1, NULL, kDNSType_PTR, NameCallback);
-               StartQuery(&q2, NULL, kDNSType_PTR, NameCallback);
-               WaitForAnswer(&mDNSStorage, 4);
-               mDNS_StopQuery(&mDNSStorage, &q1);
-               mDNS_StopQuery(&mDNSStorage, &q2);
-               if (StopNow != 1) { mprintf("%##s %s *** No Answer ***\n", q1.qname.c, DNSTypeName(q1.qtype)); goto exit; }
-               }
-       else
-               strcpy(hostname, argv[1]);
+               char *arg = argv[this_arg++];
+               if (this_arg > 2) printf("\n");
 
-       // Now we have the host name; get its A, AAAA, and HINFO
-       if (DoQuery(&q, hostname, kDNSQType_ANY, InfoCallback) == 2) goto exit; // Interrupted with Ctrl-C
+               lastid = id = zeroID;
+               hostaddr = target = zeroAddr;
+               hostname[0] = hardware[0] = software[0] = 0;
+               NumAddr = NumAAAA = NumHINFO = 0;
 
-       if (hardware[0] || software[0])
-               {
-               printf("HINFO Hardware: %s\n", hardware);
-               printf("HINFO Software: %s\n", software);
-               }
-       else if (NumAnswers)
-               {
-               printf("Host has no HINFO record; Best guess is ");
-               if (id.b[1]) printf("mDNSResponder-%d\n", id.b[1]);
-               else if (NumAAAA) printf("very early Panther build (mDNSResponder-33 or earlier)\n");
-               else printf("Jaguar version of mDNSResponder with no IPv6 support\n");
+               if (inet_pton(AF_INET, arg, &s4) == 1)
+                       {
+                       mDNSu8 *p = (mDNSu8 *)&s4;
+                       mDNS_snprintf(buffer, sizeof(buffer), "%d.%d.%d.%d.in-addr.arpa.", p[3], p[2], p[1], p[0]);
+                       printf("%s\n", buffer);
+                       target.type = mDNSAddrType_IPv4;
+                       target.ip.v4.NotAnInteger = s4.s_addr;
+                       DoQuery(&q, buffer, kDNSType_PTR, &target, NameCallback);
+                       if (StopNow == 2) break;
+                       }
+               else if (inet_pton(AF_INET6, arg, &s6) == 1)
+                       {
+                       int i;
+                       mDNSu8 *p = (mDNSu8 *)&s6;
+                       for (i = 0; i < 16; i++)
+                               {
+                               static const char hexValues[] = "0123456789ABCDEF";
+                               buffer[i * 4    ] = hexValues[p[15-i] & 0x0F];
+                               buffer[i * 4 + 1] = '.';
+                               buffer[i * 4 + 2] = hexValues[p[15-i] >> 4];
+                               buffer[i * 4 + 3] = '.';
+                               }
+                       mDNS_snprintf(&buffer[64], sizeof(buffer)-64, "ip6.arpa.");
+                       target.type = mDNSAddrType_IPv6;
+                       bcopy(&s6, &target.ip.v6, sizeof(target.ip.v6));
+                       DoQuery(&q, buffer, kDNSType_PTR, &target, NameCallback);
+                       if (StopNow == 2) break;
+                       }
+               else
+                       strcpy(hostname, arg);
+       
+               // Now we have the host name; get its A, AAAA, and HINFO
+               if (hostname[0]) DoQuery(&q, hostname, kDNSQType_ANY, &target, InfoCallback);
+               if (StopNow == 2) break;
+       
+               if (hardware[0] || software[0])
+                       {
+                       DNSQuestion q1, q2;
+                       printf("HINFO Hardware: %s\n", hardware);
+                       printf("HINFO Software: %s\n", software);
+                       // We need to make sure the services query is targeted
+                       if (target.type == 0) target = hostaddr;
+                       StartQuery(&q1, "_services._mdns._udp.local.",   kDNSQType_ANY, &target, ServicesCallback);
+                       StartQuery(&q2, "_services._dns-sd._udp.local.", kDNSQType_ANY, &target, ServicesCallback);
+                       WaitForAnswer(&mDNSStorage, 4);
+                       mDNS_StopQuery(&mDNSStorage, &q1);
+                       mDNS_StopQuery(&mDNSStorage, &q2);
+                       if (StopNow == 2) break;
+                       }
+               else if (NumAnswers)
+                       {
+                       printf("Host has no HINFO record; Best guess is ");
+                       if (id.b[1]) printf("mDNSResponder-%d\n", id.b[1]);
+                       else if (NumAAAA) printf("very early Panther build (mDNSResponder-33 or earlier)\n");
+                       else printf("Jaguar version of mDNSResponder with no IPv6 support\n");
+                       }
+               else
+                       printf("Incorrect dot-local hostname, address, or no mDNSResponder running on that machine\n");
                }
-       else
-               printf("Incorrect dot-local hostname, address, or no mDNSResponder running on that machine\n");
 
-exit:
        mDNS_Close(&mDNSStorage);
        return(0);
 
 usage:
-       fprintf(stderr, "%s <dot-local hostname> or <IPv4 address> or <IPv6 address>\n", argv[0]);
+       fprintf(stderr, "%s <dot-local hostname> or <IPv4 address> or <IPv6 address> ...\n", argv[0]);
        return(-1);
        }
index 1801a937f9f391dc46bbbac715578ec19c434b3b..9d28ad5fc22c60f57a9aa0e32c4d8dfa53566060 100755 (executable)
@@ -1,4 +1,92 @@
+# Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+#
 # $Log: Makefile,v $
+# Revision 1.34  2004/05/25 18:29:33  cheshire
+# Move DNSServiceConstructFullName() from dnssd_clientstub.c to dnssd_clientlib.c,
+# so that it's also accessible to dnssd_clientshim.c (single address space) clients.
+#
+# Revision 1.33  2004/04/30 16:46:32  rpantos
+# Add support for building Java libraries.
+#
+# Revision 1.32  2004/04/14 23:09:29  ksekar
+# Support for TSIG signed dynamic updates.
+#
+# Revision 1.31  2004/03/15 19:07:06  cheshire
+# Fix error message
+#
+# Revision 1.30  2004/03/11 18:58:29  rpantos
+# Fix Kill /etc/rc scripts so they run at halt & reboot.
+#
+# Revision 1.29  2004/03/04 23:35:41  cheshire
+# Instead of using a dummy target to generate an error message, use "$(error text...)"
+#
+# Revision 1.28  2004/03/04 23:33:42  cheshire
+# Fixes from Alfred Perlstein for FreeBSD's benefit
+#
+# Revision 1.27  2004/02/11 21:00:21  cheshire
+# Update URL for GNU Make manual page
+#
+# Revision 1.26  2004/02/05 21:28:30  cheshire
+# Fixes so that "sudo make install" works on *BSD
+#
+# Revision 1.25  2004/02/05 20:00:22  cheshire
+# Define mdnsd's PID file to be /var/run/mdnsd.pid on Posix builds
+#
+# Revision 1.24  2004/02/05 01:00:01  rpantos
+# Fix some issues that turned up when building for FreeBSD.
+#
+# Revision 1.23  2004/02/04 01:50:54  cheshire
+# Make InstalledStartup conditional, so it automatically installs into
+# either /etc/init.d/ or /etc/rc.d/init.d/ as appropriate
+#
+# Revision 1.22  2004/01/20 01:41:21  rpantos
+# Define USES_NETLINK for Linux builds.
+#
+# Revision 1.21  2003/12/17 00:51:22  cheshire
+# Changed mDNSNetMonitor and mDNSIdentify to link the object files
+# instead of #including the "DNSCommon.c" "uDNS.c" and source files
+#
+# Revision 1.20  2003/12/13 03:05:28  ksekar
+# Bug #: <rdar://problem/3192548>: DynDNS: Unicast query of service records
+#
+# Revision 1.19  2003/12/11 19:42:13  cheshire
+# Change name "mDNSResponderd" to "mdnsd" for consistency with standard Linux (Unix) naming conventions
+#
+# Revision 1.18  2003/12/11 19:38:34  cheshire
+# Add APSL
+#
+# Revision 1.17  2003/12/11 03:16:49  rpantos
+# One more change for OS X build: make install work a little better.
+#
+# Revision 1.16  2003/12/11 03:03:51  rpantos
+# Clean up mDNSPosix so that it builds on OS X again.
+#
+# Revision 1.15  2003/12/08 20:47:02  rpantos
+# Add support for mDNSResponder on Linux.
+#
+# Revision 1.14  2003/11/14 20:59:09  cheshire
+# Clients can't use AssignDomainName macro because mDNSPlatformMemCopy is defined in mDNSPlatformFunctions.h.
+# Best solution is just to combine mDNSClientAPI.h and mDNSPlatformFunctions.h into a single file.
+#
 # Revision 1.13  2003/08/06 18:20:51  cheshire
 # Makefile cleanup
 #
 # Added NetMonitor.c
 #
 
-# I assume that cc will be in your path. If not, you have to change the following to point to it.
+# This Makefile builds an mDNSResponder daemon and a libmdns.so shared library 
+# for Linux. It also builds several example programs for embedded systems. 
+#
+# Make with no arguments to build all production targets.
+# 'make DEBUG=1' to build debugging targets.
+# 'make clean' or 'make clean DEBUG=1' to delete prod/debug objects & targets
+# 'sudo make install [DEBUG=1]' to install mdnsd daemon and libmdns.
+#
+# Notes:
+# $@ means "The file name of the target of the rule"
+# $< means "The name of the first prerequisite"
+# $+ means "The names of all the prerequisites, with spaces between them, exactly as given"
+# For more magic automatic variables, see
+# <http://www.gnu.org/software/make/manual/html_chapter/make_10.html#SEC111>
+
+#############################################################################
+
+LIBVERS = 1
+
+COREDIR = ../mDNSCore
+SHAREDDIR = ../mDNSShared
+JDK = /usr/jdk
+
 CC = cc
-CFLAGS_COMMON = -g -I../mDNSCore -I. -DMDNS_DEBUGMSGS=2
+LD = ld
+CP = cp
+RM = rm
+LN = ln -s -f
+CFLAGS_COMMON = -I. -I$(COREDIR) -I$(SHAREDDIR) -W -Wall -DPID_FILE=\"/var/run/mdnsd.pid\"
+LDFLAGS = -shared
+LDSUFFIX = so
+JAVACFLAGS_OS = -fPIC -shared -lmdns
 
+# Set up diverging paths for debug vs. prod builds
+DEBUG=0
+ifeq ($(DEBUG),1)
+CFLAGS_DEBUG = -g -DMDNS_DEBUGMSGS=2 
+OBJDIR = objects/debug
+BUILDDIR = build/debug
+STRIP = echo 
+else
+CFLAGS_DEBUG = -Os -DMDNS_DEBUGMSGS=0 
+OBJDIR = objects/prod
+BUILDDIR = build/prod
+STRIP = strip -S 
+endif
+
+# Configure per-OS peculiarities
 ifeq ($(os),solaris)
-CFLAGS_OS =  -DNOT_HAVE_DAEMON -DNOT_HAVE_SA_LEN -D_XPG4_2 -D__EXTENSIONS__ -DHAVE_BROKEN_RECVIF_NAME -lsocket -lnsl
+CFLAGS_OS = -DNOT_HAVE_DAEMON -DNOT_HAVE_SA_LEN -D_XPG4_2 -D__EXTENSIONS__ -DHAVE_BROKEN_RECVIF_NAME -lsocket -lnsl
 else
 ifeq ($(os),linux)
-CFLAGS_OS = -DNOT_HAVE_SA_LEN -W -Wall
+CFLAGS_OS = -DNOT_HAVE_SA_LEN -DUSES_NETLINK
+JAVACFLAGS_OS += -I$(JDK)/include/linux
 else
 ifeq ($(os),netbsd)
 CFLAGS_OS =
+LDCONFIG = ldconfig
 else
 ifeq ($(os),freebsd)
+# If not already defined, set LOCALBASE to /usr/local
+# FreeBSD requires the startup script to end in ".sh"
+LOCALBASE?=/usr/local
+INSTBASE=$(LOCALBASE)
+STARTUPSCRIPTNAME=mdns.sh
 CFLAGS_OS =
+LDCONFIG = ldconfig
 else
 ifeq ($(os),openbsd)
 CFLAGS_OS = -DHAVE_BROKEN_RECVDSTADDR
+LDCONFIG = ldconfig
 else
 ifeq ($(os),jaguar)
-CFLAGS_OS = -DHAVE_IPV6 -W -Wall -no-cpp-precomp -DNOT_HAVE_SOCKLEN_T
+CFLAGS_OS = -DHAVE_IPV6 -no-cpp-precomp -DNOT_HAVE_SOCKLEN_T
+LD = libtool
+LDFLAGS = -dynamic -lSystem
+LDSUFFIX = dylib
+JDK = /System/Library/Frameworks/JavaVM.framework/Home
+JAVACFLAGS_OS = -dynamiclib -I/System/Library/Frameworks/JavaVM.framework/Headers -framework JavaVM 
 else
 ifeq ($(os),panther)
-CFLAGS_OS = -DHAVE_IPV6 -W -Wall -no-cpp-precomp
+CFLAGS_OS = -DHAVE_IPV6 -no-cpp-precomp
+LD = libtool
+LDFLAGS = -dynamic -lSystem
+LDSUFFIX = dylib
+JDK = /System/Library/Frameworks/JavaVM.framework/Home
+JAVACFLAGS_OS = -dynamiclib -I/System/Library/Frameworks/JavaVM.framework/Headers -framework JavaVM 
 else
-cantbuild:
-       @echo "Error: Must specify target OS on command-line, e.g. \"make os=panther\" or \"make os=jaguar\" or \"make os=linux\""
+$(error ERROR: Must specify target OS on command-line: "make os={jaguar,panther,linux,netbsd,freebsd,openbsd,solaris} [target]") 
 endif
 endif
 endif
@@ -60,61 +210,219 @@ endif
 endif
 endif
 endif
-CFLAGS = $(CFLAGS_COMMON) $(CFLAGS_OS)
 
-COMMONOBJ = objects/mDNSPosix.c.o objects/mDNSUNP.c.o objects/ExampleClientApp.c.o
+# 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)
+INSTBASE?=/usr
+STARTUPSCRIPTNAME?=mdns
+
+ifeq ($(HAVE_IPV6),1)
+CFLAGS_OS += -DHAVE_IPV6=1
+else
+ifeq ($(HAVE_IPV6),0)
+CFLAGS_OS += -DHAVE_IPV6=0
+endif
+endif
 
-HEADERS = Makefile mDNSUNP.h mDNSPosix.h   \
-../mDNSCore/mDNSDebug.h                    \
-../mDNSCore/mDNSClientAPI.h                \
-../mDNSCore/mDNSPlatformFunctions.h
+# If directory /etc/rc.d/init.d/ exists, then we install into that (old Linux)
+ifeq ($(wildcard /etc/rc.d/init.d/), /etc/rc.d/init.d/)
+STARTUPSCRIPTDIR = /etc/rc.d/init.d
+RUNLEVELSCRIPTSDIR = /etc/rc.d
+else
+# else if directory /etc/init.d/ exists, then we install into that (new Linux)
+ifeq ($(wildcard /etc/init.d/), /etc/init.d/)
+STARTUPSCRIPTDIR = /etc/init.d
+RUNLEVELSCRIPTSDIR = /etc
+else
+# else install into /etc/rc.d/ (*BSD)
+STARTUPSCRIPTDIR = $(INSTBASE)/etc/rc.d
+endif
+endif
 
-all: setup Client Responder ProxyResponder Identify NetMonitor
+CFLAGS = $(CFLAGS_COMMON) $(CFLAGS_OS) $(CFLAGS_DEBUG)
 
+#############################################################################
+
+all: setup Daemon libmdns Client Responder ProxyResponder Identify NetMonitor
+
+install: setup InstalledDaemon InstalledLib InstalledStartup
+
+# 'setup' sets up the build directory structure the way we want
 setup:
-       if test ! -d objects ; then mkdir objects ; fi
-       if test ! -d build   ; then mkdir build   ; fi
+       @if test ! -d objects     ; then mkdir objects     ; fi
+       @if test ! -d build       ; then mkdir build       ; fi
+       @if test ! -d $(OBJDIR)   ; then mkdir $(OBJDIR)   ; fi
+       @if test ! -d $(BUILDDIR) ; then mkdir $(BUILDDIR) ; fi
+
+# clean removes targets and objects
+clean:
+       if test -d $(OBJDIR)   ; then rm -r $(OBJDIR)   ; fi
+       if test -d $(BUILDDIR) ; then rm -r $(BUILDDIR) ; fi
+
+#############################################################################
+
+# 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 
+
+Daemon: setup $(BUILDDIR)/mdnsd
+       @echo "Responder daemon done"
+
+$(BUILDDIR)/mdnsd: $(DAEMONOBJS)
+       $(CC) -o $@ $+
+       $(STRIP) $@
+
+# libmdns target builds the client library
+libmdns: setup $(BUILDDIR)/libmdns.$(LDSUFFIX)
+       @echo "Client library done"
+
+$(BUILDDIR)/libmdns.$(LDSUFFIX): $(OBJDIR)/dnssd_clientlib.c.so.o $(OBJDIR)/dnssd_clientstub.c.so.o $(OBJDIR)/dnssd_ipc.c.so.o
+       $(LD) $(LDFLAGS) -o $@ $+
+       $(STRIP) $@
+
+#############################################################################
+
+# The Install targets place built stuff in their proper places
+InstalledDaemon: $(INSTBASE)/sbin/mdnsd
+       @echo $< " installed"
+
+InstalledLib: $(INSTBASE)/lib/libmdns.$(LDSUFFIX).$(LIBVERS) $(INSTBASE)/include/dns_sd.h
+       @echo $< " installed"
+
+InstalledStartup: $(STARTUPSCRIPTDIR)/$(STARTUPSCRIPTNAME)
+       @echo $< " installed"
+
+$(INSTBASE)/sbin/mdnsd: $(BUILDDIR)/mdnsd
+       $(CP) $< $@
+
+$(INSTBASE)/lib/libmdns.$(LDSUFFIX).$(LIBVERS): $(BUILDDIR)/libmdns.$(LDSUFFIX)
+       $(CP) $< $@
+       $(LN) $@ $(INSTBASE)/lib/libmdns.$(LDSUFFIX)
+ifdef LDCONFIG
+    # -m means 'merge into existing database', -R means 'rescan directories'
+       $(LDCONFIG) -mR
+endif
+
+$(INSTBASE)/include/dns_sd.h: $(SHAREDDIR)/dns_sd.h
+       $(CP) $< $@
+
+$(STARTUPSCRIPTDIR)/$(STARTUPSCRIPTNAME): mdnsd.sh $(STARTUPSCRIPTDIR)
+       $(CP) $< $@
+       chmod ugo+x $@
+ifdef RUNLEVELSCRIPTSDIR
+       $(LN) $@ $(RUNLEVELSCRIPTSDIR)/rc2.d/S52mdns
+       $(LN) $@ $(RUNLEVELSCRIPTSDIR)/rc3.d/S52mdns
+       $(LN) $@ $(RUNLEVELSCRIPTSDIR)/rc4.d/S52mdns
+       $(LN) $@ $(RUNLEVELSCRIPTSDIR)/rc5.d/S52mdns
+       $(LN) $@ $(RUNLEVELSCRIPTSDIR)/rc0.d/K16mdns
+       $(LN) $@ $(RUNLEVELSCRIPTSDIR)/rc6.d/K16mdns
+endif
 
-Client: setup build/mDNSClientPosix
-       @echo "Client done"
+#############################################################################
 
-Responder: setup build/mDNSResponderPosix
-       @echo "Responder done"
+# The following targets build Java wrappers for the dns-sd.h API.
 
-ProxyResponder: setup build/mDNSProxyResponderPosix
-       @echo "ProxyResponder done"
+JAVAC = $(JDK)/bin/javac
+JAVAH = $(JDK)/bin/javah
+JAVADOC = $(JDK)/bin/javadoc
+JAR = $(JDK)/bin/jar
+JAVACFLAGS = $(CFLAGS) $(JAVACFLAGS_OS) -I$(JDK)/include
 
-Identify: setup build/mDNSIdentify
+Java: setup $(BUILDDIR)/dns_sd.jar $(BUILDDIR)/libjdns_sd.$(LDSUFFIX)
+       @echo "Java wrappers done"
+
+JAVASRC        = $(SHAREDDIR)/Java
+JARCONTENTS =  $(OBJDIR)/com/apple/dnssd/DNSSDService.class \
+                               $(OBJDIR)/com/apple/dnssd/DNSRecord.class \
+                               $(OBJDIR)/com/apple/dnssd/DNSSDException.class \
+                               $(OBJDIR)/com/apple/dnssd/TXTRecord.class \
+                               $(OBJDIR)/com/apple/dnssd/DNSSDRegistration.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/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)/libjdns_sd.$(LDSUFFIX): $(JAVASRC)/JNISupport.c $(OBJDIR)/DNSSD.java.h
+       $(CC) -o $@ $< $(JAVACFLAGS) -I$(OBJDIR)
+
+$(OBJDIR)/com/apple/dnssd/%.class:     $(JAVASRC)/%.java
+       $(JAVAC) -d $(OBJDIR) -classpath $(OBJDIR) $<
+
+$(OBJDIR)/DNSSD.java.h: $(OBJDIR)/com/apple/dnssd/DNSSD.class
+       $(JAVAH) -force -classpath $(OBJDIR) -o $@ \
+               com.apple.dnssd.AppleDNSSD \
+               com.apple.dnssd.AppleBrowser \
+               com.apple.dnssd.AppleResolver \
+               com.apple.dnssd.AppleRegistration \
+               com.apple.dnssd.AppleQuery \
+               com.apple.dnssd.AppleDomainEnum \
+               com.apple.dnssd.AppleService 
+
+#############################################################################
+
+# The following target builds documentation for the Java wrappers.
+
+JavaDoc: setup Java
+       $(JAVADOC) $(JAVASRC)/*.java -classpath $(OBJDIR) -d $(BUILDDIR) -public
+
+#############################################################################
+
+# 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
+COMMONOBJ  = $(SPECIALOBJ) $(OBJDIR)/mDNS.c.o
+APPOBJ     = $(COMMONOBJ) $(OBJDIR)/ExampleClientApp.c.o
+
+Client: setup $(BUILDDIR)/mDNSClientPosix
+       @echo "Embedded Standalone Client done"
+
+Responder: setup $(BUILDDIR)/mDNSResponderPosix
+       @echo "Embedded Standalone Responder done"
+
+ProxyResponder: setup $(BUILDDIR)/mDNSProxyResponderPosix
+       @echo "Embedded Standalone ProxyResponder done"
+
+Identify: setup $(BUILDDIR)/mDNSIdentify
        @echo "Identify done"
 
-NetMonitor: setup build/mDNSNetMonitor
+NetMonitor: setup $(BUILDDIR)/mDNSNetMonitor
        @echo "NetMonitor done"
 
-# $@ means "The file name of the target of the rule"
-# $< means "The name of the first prerequisite"
-# $+ means "The names of all the prerequisites, with spaces between them, exactly as given"
-# For more magic automatic sariables, see
-# <http://www.gnu.org/manual/make-3.80/html_chapter/make_10.html#SEC111>
-build/mDNSClientPosix: $(COMMONOBJ) objects/mDNS.c.o objects/Client.c.o
+$(BUILDDIR)/mDNSClientPosix:         $(APPOBJ)     $(OBJDIR)/Client.c.o
        $(CC) $+ -o $@
 
-build/mDNSResponderPosix: $(COMMONOBJ) objects/mDNS.c.o objects/Responder.c.o
+$(BUILDDIR)/mDNSResponderPosix:      $(COMMONOBJ)  $(OBJDIR)/Responder.c.o
        $(CC) $+ -o $@
 
-build/mDNSProxyResponderPosix: $(COMMONOBJ) objects/mDNS.c.o objects/ProxyResponder.c.o
+$(BUILDDIR)/mDNSProxyResponderPosix: $(COMMONOBJ)  $(OBJDIR)/ProxyResponder.c.o
        $(CC) $+ -o $@
 
-build/mDNSIdentify: $(COMMONOBJ) objects/Identify.c.o
+$(BUILDDIR)/mDNSIdentify:            $(SPECIALOBJ) $(OBJDIR)/Identify.c.o
        $(CC) $+ -o $@
 
-build/mDNSNetMonitor: $(COMMONOBJ) objects/NetMonitor.c.o
+$(BUILDDIR)/mDNSNetMonitor:          $(SPECIALOBJ) $(OBJDIR)/NetMonitor.c.o
        $(CC) $+ -o $@
 
-objects/%.c.o: %.c ../mDNSCore/mDNS.c $(HEADERS)
-       $(CC) -c $(CFLAGS) $< -o $@
+#############################################################################
 
-objects/mDNS.c.o: ../mDNSCore/mDNS.c $(HEADERS)
-       $(CC) -c $(CFLAGS) $< -o $@
+# Implicit rules
+$(OBJDIR)/%.c.o:       %.c
+       $(CC) $(CFLAGS) -c -o $@ $<
 
-clean:
-       -rm -rf objects build .gdb_history
+$(OBJDIR)/%.c.o:       $(COREDIR)/%.c
+       $(CC) $(CFLAGS) -c -o $@ $<
+
+$(OBJDIR)/%.c.o:       $(SHAREDDIR)/%.c
+       $(CC) $(CFLAGS) -c -o $@ $<
+
+$(OBJDIR)/%.c.so.o:    %.c
+       $(CC) $(CFLAGS) -c -fPIC -o $@ $<
+
+$(OBJDIR)/%.c.so.o:    $(SHAREDDIR)/%.c
+       $(CC) $(CFLAGS) -c -fPIC -o $@ $<
index 8a90d249376ff988bc126df6a05de48742a092e2..8bce09eb923ab908e94b43086f64698afea60546 100644 (file)
@@ -3,6 +3,8 @@
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
     Change History (most recent first):
 
 $Log: NetMonitor.c,v $
+Revision 1.63  2004/05/18 23:51:26  cheshire
+Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
+
+Revision 1.62  2004/03/16 18:24:25  cheshire
+If packet destination was not multicast, then display it
+
+Revision 1.61  2004/02/20 09:36:46  cheshire
+Also show TTL in packet header, if it's not 255
+
+Revision 1.60  2004/02/07 02:11:35  cheshire
+Make mDNSNetMonitor smarter about sending targeted unicast HINFO queries
+
+Revision 1.59  2004/02/03 21:42:55  cheshire
+Add constants kReportTopServices and kReportTopHosts
+
+Revision 1.58  2004/01/27 20:15:23  cheshire
+<rdar://problem/3541288>: Time to prune obsolete code for listening on port 53
+
+Revision 1.57  2004/01/24 23:59:42  cheshire
+Change to use mDNSVal16() instead of shifting and ORing
+
+Revision 1.56  2004/01/24 05:25:34  cheshire
+mDNSNetMonitor now uses the new ability to send unicast queries so that
+it causes less perturbation of the network traffic it's monitoring.
+
+Revision 1.55  2003/12/23 00:21:31  cheshire
+Send HINFO queries to determine the mDNSResponder version of each host
+
+Revision 1.54  2003/12/17 01:06:39  cheshire
+Also show host name along with HINFO data
+
+Revision 1.53  2003/12/17 00:51:22  cheshire
+Changed mDNSNetMonitor and mDNSIdentify to link the object files
+instead of #including the "DNSCommon.c" "uDNS.c" and source files
+
+Revision 1.52  2003/12/17 00:21:51  cheshire
+If we received one, display host's HINFO record in final summary
+
+Revision 1.51  2003/12/13 03:05:28  ksekar
+<rdar://problem/3192548>: DynDNS: Unicast query of service records
+
+Revision 1.50  2003/12/08 20:47:02  rpantos
+Add support for mDNSResponder on Linux.
+
 Revision 1.49  2003/10/30 19:38:56  cheshire
 Fix warning on certain compilers
 
@@ -213,6 +259,7 @@ Added NetMonitor.c
 #include <stdlib.h>                    // For malloc()
 #include <string.h>                    // For bcopy()
 #include <time.h>                      // For "struct tm" etc.
+#include <signal.h>                    // For SIGINT, SIGTERM
 #include <netdb.h>                     // For gethostbyname()
 #include <sys/socket.h>                // For AF_INET, AF_INET6, etc.
 #include <arpa/inet.h>         // For inet_addr()
@@ -267,6 +314,12 @@ struct FilterList_struct
        mDNSAddr FilterAddr;
        };
 
+//*************************************************************************************************************
+// Constants
+
+#define kReportTopServices 15
+#define kReportTopHosts    15
+
 //*************************************************************************************************************
 // Globals
 
@@ -322,6 +375,12 @@ typedef struct
        unsigned long pkts[HostPkt_NumTypes];
        unsigned long totalops;
        unsigned long stat[OP_NumTypes];
+       domainname hostname;
+       domainname revname;
+       UTF8str255 HIHardware;
+       UTF8str255 HISoftware;
+       mDNSu32    NumQueries;
+       mDNSs32    LastQuery;
        } HostEntry;
 
 #define HostEntryTotalPackets(H) ((H)->pkts[HostPkt_Q] + (H)->pkts[HostPkt_L] + (H)->pkts[HostPkt_R] + (H)->pkts[HostPkt_B])
@@ -350,8 +409,9 @@ mDNSlocal HostEntry *FindHost(const mDNSAddr *addr, HostList* list)
        return NULL;
        }
        
-mDNSlocal HostEntry *AddHost(HostList* list)
+mDNSlocal HostEntry *AddHost(const mDNSAddr *addr, HostList* list)
        {
+       int i;
        HostEntry *entry;
        if (list->num >= list->max)
                {
@@ -362,29 +422,130 @@ mDNSlocal HostEntry *AddHost(HostList* list)
                list->max = newMax;
                list->hosts = newHosts;
                }
+
        entry = list->hosts + list->num++;
+
+       entry->addr = *addr;
+       for (i=0; i<HostPkt_NumTypes; i++) entry->pkts[i] = 0;
+       entry->totalops = 0;
+       for (i=0; i<OP_NumTypes;      i++) entry->stat[i] = 0;
+       entry->hostname.c[0] = 0;
+       entry->revname.c[0] = 0;
+       entry->HIHardware.c[0] = 0;
+       entry->HISoftware.c[0] = 0;
+       entry->NumQueries = 0;
+
+       if (entry->addr.type == mDNSAddrType_IPv4)
+               {
+               mDNSv4Addr ip = entry->addr.ip.v4;
+               char buffer[32];
+               mDNS_snprintf(buffer, sizeof(buffer), "%d.%d.%d.%d.in-addr.arpa.", ip.b[3], ip.b[2], ip.b[1], ip.b[0]);
+               MakeDomainNameFromDNSNameString(&entry->revname, buffer);
+               }
+
        return(entry);
        }
 
-mDNSlocal HostEntry *GotPacketFromHost(const mDNSAddr *addr, HostPkt_Type t)
+mDNSlocal HostEntry *GotPacketFromHost(const mDNSAddr *addr, HostPkt_Type t, mDNSOpaque16 id)
        {
        if (ExactlyOneFilter) return(NULL);
        else
                {
                HostList *list = (addr->type == mDNSAddrType_IPv4) ? &IPv4HostList : &IPv6HostList;
                HostEntry *entry = FindHost(addr, list);
-               if (!entry)
+               if (!entry) entry = AddHost(addr, list);
+               if (!entry) return(NULL);
+               // Don't count our own interrogation packets
+               if (id.NotAnInteger != 0xFFFF) entry->pkts[t]++;
+               return(entry);
+               }
+       }
+
+mDNSlocal void RecordHostInfo(HostEntry *entry, const ResourceRecord *const pktrr)
+       {
+       if (!entry->hostname.c[0])
+               {
+               if (pktrr->rrtype == kDNSType_A || pktrr->rrtype == kDNSType_AAAA)
                        {
-                       int i;
-                       entry = AddHost(list);
-                       if (!entry) return(NULL);
-                       entry->addr = *addr;
-                       for (i=0; i<HostPkt_NumTypes; i++) entry->pkts[i] = 0;
-                       entry->totalops = 0;
-                       for (i=0; i<OP_NumTypes;      i++) entry->stat[i] = 0;
+                       // Should really check that the rdata in the address record matches the source address of this packet
+                       entry->NumQueries = 0;
+                       AssignDomainName(entry->hostname, pktrr->name);
                        }
-               entry->pkts[t]++;
-               return(entry);
+
+               if (pktrr->rrtype == kDNSType_PTR)
+                       if (SameDomainName(&entry->revname, &pktrr->name))
+                               {
+                               entry->NumQueries = 0;
+                               AssignDomainName(entry->hostname, pktrr->rdata->u.name);
+                               }
+               }
+       else if (pktrr->rrtype == kDNSType_HINFO)
+               {
+               RDataBody *rd = &pktrr->rdata->u;
+               mDNSu8 *rdend = (mDNSu8 *)rd + pktrr->rdlength;
+               mDNSu8 *hw = rd->txt.c;
+               mDNSu8 *sw = hw + 1 + (mDNSu32)hw[0];
+               if (sw + 1 + sw[0] <= rdend)
+                       {
+                       AssignDomainName(entry->hostname, pktrr->name);
+                       mDNSPlatformMemCopy(hw, entry->HIHardware.c, 1 + (mDNSu32)hw[0]);
+                       mDNSPlatformMemCopy(sw, entry->HISoftware.c, 1 + (mDNSu32)sw[0]);
+                       }
+               }
+       }
+
+mDNSlocal void SendUnicastQuery(mDNS *const m, HostEntry *entry, domainname *name, mDNSu16 rrtype, mDNSInterfaceID InterfaceID)
+       {
+       const mDNSOpaque16 id = { { 0xFF, 0xFF } };
+       DNSMessage query;
+       mDNSu8       *qptr        = query.data;
+       const mDNSu8 *const limit = query.data + sizeof(query.data);
+       const mDNSAddr *target    = &entry->addr;
+       InitializeDNSMessage(&query.h, id, QueryFlags);
+       qptr = putQuestion(&query, qptr, limit, name, rrtype, kDNSClass_IN);
+       entry->LastQuery = m->timenow;
+       entry->NumQueries++;
+
+       // Note: When there are multiple mDNSResponder agents running on a single machine
+       // (e.g. Apple mDNSResponder plus a SliMP3 server with embedded mDNSResponder)
+       // it is possible that unicast queries may not go to the primary system responder.
+       // We try the first query using unicast, but if that doesn't work we try again via multicast.
+       if (entry->NumQueries > 2)
+               {
+               target = &AllDNSLinkGroup_v4;
+               }
+       else
+               {
+               //mprintf("%#a Q\n", target);
+               InterfaceID = mDNSInterface_Any;        // Send query from our unicast reply socket
+               m->ExpectUnicastResponse = m->timenow;
+               }
+
+       mDNSSendDNSMessage(&mDNSStorage, &query, qptr, InterfaceID, target, MulticastDNSPort);
+       }
+
+mDNSlocal void AnalyseHost(mDNS *const m, HostEntry *entry, const mDNSInterfaceID InterfaceID)
+       {
+       // If we've done four queries without answer, give up
+       if (entry->NumQueries >= 4) return;
+
+       // If we've done a query in the last second, give the host a chance to reply before trying again
+       if (entry->NumQueries && m->timenow - entry->LastQuery < mDNSPlatformOneSecond) return;
+
+       // If we don't know the host name, try to find that first
+       if (!entry->hostname.c[0])
+               {
+               if (entry->revname.c[0])
+                       {
+                       SendUnicastQuery(m, entry, &entry->revname, kDNSType_PTR, InterfaceID);
+                       //mprintf("%##s PTR %d\n", entry->revname.c, entry->NumQueries);
+                       }
+               }
+       // If we have the host name but no HINFO, now ask for that
+       else if (!entry->HIHardware.c[0])
+               {
+               SendUnicastQuery(m, entry, &entry->hostname, kDNSType_HINFO, InterfaceID);
+               //mprintf("%##s HINFO %d\n", entry->hostname.c, entry->NumQueries);
                }
        }
 
@@ -410,6 +571,10 @@ mDNSlocal void ShowSortedHostList(HostList *list, int max)
                        HostEntryTotalPackets(e), e->pkts[HostPkt_Q], e->pkts[HostPkt_L], e->pkts[HostPkt_R]);
                if (e->pkts[HostPkt_B]) mprintf("Bad: %8lu", e->pkts[HostPkt_B]);
                mprintf("\n");
+               if (!e->HISoftware.c[0] && e->NumQueries > 2)
+                       mDNSPlatformMemCopy("\x0E*** Jaguar ***", &e->HISoftware, 15);
+               if (e->hostname.c[0] || e->HIHardware.c[0] || e->HISoftware.c[0])
+                       mprintf("%##-45s %#-14s %#s\n", e->hostname.c, e->HIHardware.c, e->HISoftware.c);
                }
        }
 
@@ -477,6 +642,7 @@ mDNSlocal void recordstat(HostEntry *entry, domainname *fqdn, int op, mDNSu16 rr
 mDNSlocal void printstats(int max)
        {
        int i;
+       if (!stats) return;
        for (i=0; i<max; i++)
                {
                int max = 0;
@@ -492,7 +658,8 @@ mDNSlocal void printstats(int max)
                }
        }
 
-mDNSlocal const mDNSu8 *FindUpdate(mDNS *const m, const DNSMessage *const query, const mDNSu8 *ptr, const mDNSu8 *const end, DNSQuestion *q, LargeCacheRecord *pkt)
+mDNSlocal const mDNSu8 *FindUpdate(mDNS *const m, const DNSMessage *const query, const mDNSu8 *ptr, const mDNSu8 *const end,\
+       DNSQuestion *q, LargeCacheRecord *pkt)
        {
        int i;
        for (i = 0; i < query->h.numAuthorities; i++)
@@ -514,7 +681,7 @@ mDNSlocal void DisplayTimestamp(void)
        mprintf("\n%d:%02d:%02d.%06d\n", tm.tm_hour, tm.tm_min, tm.tm_sec, tv.tv_usec);
        }
 
-mDNSlocal void DisplayPacketHeader(const DNSMessage *const msg, const mDNSu8 *const end, const mDNSAddr *srcaddr, mDNSIPPort srcport)
+mDNSlocal void DisplayPacketHeader(const DNSMessage *const msg, const mDNSu8 *const end, const mDNSAddr *srcaddr, mDNSIPPort srcport, const mDNSAddr *dstaddr, mDNSu8 ttl)
        {
        const char *const ptype =   (msg->h.flags.b[0] & kDNSFlag0_QR_Response)             ? "-R- " :
                                                                (srcport.NotAnInteger == MulticastDNSPort.NotAnInteger) ? "-Q- " : "-LQ-";
@@ -523,7 +690,11 @@ mDNSlocal void DisplayPacketHeader(const DNSMessage *const msg, const mDNSu8 *co
        mprintf("%#-16a %s             Q:%3d  Ans:%3d  Auth:%3d  Add:%3d  Size:%5d bytes",
                srcaddr, ptype, msg->h.numQuestions, msg->h.numAnswers, msg->h.numAuthorities, msg->h.numAdditionals, end - (mDNSu8 *)msg);
 
-       if (msg->h.id.NotAnInteger) mprintf("  ID:%u", ((mDNSu16)msg->h.id.b[0])<<8 | msg->h.id.b[1]);
+       if (msg->h.id.NotAnInteger) mprintf("  ID:%u", mDNSVal16(msg->h.id));
+
+       if (ttl != 255) mprintf("  TTL:%u", ttl);
+
+       if (!mDNSAddrIsDNSMulticast(dstaddr)) mprintf("   To: %#a", dstaddr);
 
        if (msg->h.flags.b[0] & kDNSFlag0_TC)
                {
@@ -574,7 +745,7 @@ mDNSlocal void DisplayResourceRecord(const mDNSAddr *const srcaddr, const char *
                                                        n += 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, ((mDNSu16)rd->srv.port.b[0] << 8) | rd->srv.port.b[1]); break;
+               case kDNSType_SRV:      n += mprintf("%##s:%d", &rd->srv.target, mDNSVal16(rd->srv.port)); break;
                default:                        {
                                                        mDNSu8 *s = rd->data;
                                                        while (s < rdend && p < buffer+MaxWidth)
@@ -620,17 +791,21 @@ mDNSlocal void DisplayError(const mDNSAddr *srcaddr, const mDNSu8 *ptr, const mD
        HexDump(ptr, end);
        }
 
-mDNSlocal void DisplayQuery(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end, const mDNSAddr *srcaddr, mDNSIPPort srcport, const mDNSInterfaceID InterfaceID)
+mDNSlocal void DisplayQuery(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end,
+       const mDNSAddr *srcaddr, mDNSIPPort srcport, const mDNSAddr *dstaddr, const mDNSInterfaceID InterfaceID, mDNSu8 ttl)
        {
        int i;
        const mDNSu8 *ptr = msg->data;
        const mDNSu8 *auth = LocateAuthorities(msg, end);
        mDNSBool MQ = (srcport.NotAnInteger == MulticastDNSPort.NotAnInteger);
-       HostEntry *entry = GotPacketFromHost(srcaddr, MQ ? HostPkt_Q : HostPkt_L);
+       HostEntry *entry = GotPacketFromHost(srcaddr, MQ ? HostPkt_Q : HostPkt_L, msg->h.id);
        LargeCacheRecord pkt;
 
-       DisplayPacketHeader(msg, end, srcaddr, srcport);
-       if (MQ) NumPktQ++; else NumPktL++;
+       DisplayPacketHeader(msg, end, srcaddr, srcport, dstaddr, ttl);
+       if (msg->h.id.NotAnInteger != 0xFFFF)
+               {
+               if (MQ) NumPktQ++; else NumPktL++;
+               }
 
        for (i=0; i<msg->h.numQuestions; i++)
                {
@@ -656,7 +831,7 @@ mDNSlocal void DisplayQuery(mDNS *const m, const DNSMessage *const msg, const mD
                        if (srcport.NotAnInteger == MulticastDNSPort.NotAnInteger) NumQuestions++;
                        else { NumLegacy++; ptype = "(LQ)"; }
                        mprintf("%#-16a %-5s %-5s      %##s\n", srcaddr, ptype, DNSTypeName(q.qtype), q.qname.c);
-                       recordstat(entry, &q.qname, OP_query, q.qtype);
+                       if (msg->h.id.NotAnInteger != 0xFFFF) recordstat(entry, &q.qname, OP_query, q.qtype);
                        }
                }
 
@@ -680,17 +855,20 @@ mDNSlocal void DisplayQuery(mDNS *const m, const DNSMessage *const msg, const mD
                ptr = skipResourceRecord(msg, ptr, end);
                if (!ptr) { DisplayError(srcaddr, ep, end, "AUTHORITY"); return; }
                }
+
+       if (entry) AnalyseHost(m, entry, InterfaceID);
        }
 
-mDNSlocal void DisplayResponse(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *end, const mDNSAddr *srcaddr, mDNSIPPort srcport, const mDNSInterfaceID InterfaceID)
+mDNSlocal void DisplayResponse(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *end,
+       const mDNSAddr *srcaddr, mDNSIPPort srcport, const mDNSAddr *dstaddr, const mDNSInterfaceID InterfaceID, mDNSu8 ttl)
        {
        int i;
        const mDNSu8 *ptr = msg->data;
-       HostEntry *entry = GotPacketFromHost(srcaddr, HostPkt_R);
+       HostEntry *entry = GotPacketFromHost(srcaddr, HostPkt_R, msg->h.id);
        LargeCacheRecord pkt;
 
-       DisplayPacketHeader(msg, end, srcaddr, srcport);
-       NumPktR++;
+       DisplayPacketHeader(msg, end, srcaddr, srcport, dstaddr, ttl);
+       if (msg->h.id.NotAnInteger != 0xFFFF) NumPktR++;
 
        for (i=0; i<msg->h.numQuestions; i++)
                {
@@ -698,7 +876,10 @@ mDNSlocal void DisplayResponse(mDNS *const m, const DNSMessage *const msg, const
                const mDNSu8 *ep = ptr;
                ptr = getQuestion(msg, ptr, end, InterfaceID, &q);
                if (!ptr) { DisplayError(srcaddr, ep, end, "QUESTION"); return; }
-               mprintf("%#-16a (?)  **** ERROR: SHOULD NOT HAVE Q IN mDNS RESPONSE **** %-5s %##s\n", srcaddr, DNSTypeName(q.qtype), q.qname.c);
+               if (mDNSAddrIsDNSMulticast(dstaddr))
+                       mprintf("%#-16a (?)   **** ERROR: SHOULD NOT HAVE Q IN mDNS RESPONSE **** %-5s %##s\n", srcaddr, DNSTypeName(q.qtype), q.qname.c);
+               else
+                       mprintf("%#-16a (Q)   %-5s      %##s\n", srcaddr, DNSTypeName(q.qtype), q.qname.c);
                }
 
        for (i=0; i<msg->h.numAnswers; i++)
@@ -710,7 +891,8 @@ mDNSlocal void DisplayResponse(mDNS *const m, const DNSMessage *const msg, const
                        {
                        NumAnswers++;
                        DisplayResourceRecord(srcaddr, (pkt.r.resrec.RecordType & kDNSRecordTypePacketUniqueMask) ? "(AN)" : "(AN+)", &pkt.r.resrec);
-                       recordstat(entry, &pkt.r.resrec.name, OP_answer, pkt.r.resrec.rrtype);
+                       if (msg->h.id.NotAnInteger != 0xFFFF) recordstat(entry, &pkt.r.resrec.name, OP_answer, pkt.r.resrec.rrtype);
+                       if (entry) RecordHostInfo(entry, &pkt.r.resrec);
                        }
                else
                        {
@@ -736,6 +918,24 @@ mDNSlocal void DisplayResponse(mDNS *const m, const DNSMessage *const msg, const
                if (!ptr) { DisplayError(srcaddr, ep, end, "ADDITIONAL"); return; }
                NumAdditionals++;
                DisplayResourceRecord(srcaddr, (pkt.r.resrec.RecordType & kDNSRecordTypePacketUniqueMask) ? "(AD)" : "(AD+)", &pkt.r.resrec);
+               if (entry) RecordHostInfo(entry, &pkt.r.resrec);
+               }
+       
+       if (entry) AnalyseHost(m, entry, InterfaceID);
+       }
+
+mDNSlocal void ProcessUnicastResponse(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *end, const mDNSAddr *srcaddr, const mDNSInterfaceID InterfaceID)
+       {
+       int i;
+       const mDNSu8 *ptr = LocateAnswers(msg, end);
+       HostEntry *entry = GotPacketFromHost(srcaddr, HostPkt_R, msg->h.id);
+       //mprintf("%#a R\n", srcaddr);
+
+       for (i=0; i<msg->h.numAnswers + msg->h.numAuthorities + msg->h.numAdditionals; i++)
+               {
+               LargeCacheRecord pkt;
+               ptr = GetLargeResourceRecord(m, msg, ptr, end, InterfaceID, 0, &pkt);
+               if (pkt.r.resrec.rroriginalttl && entry) RecordHostInfo(entry, &pkt.r.resrec);
                }
        }
 
@@ -763,7 +963,7 @@ mDNSexport void mDNSCoreReceive(mDNS *const m, DNSMessage *const msg, const mDNS
        msg->h.numAnswers     = (mDNSu16)((mDNSu16)ptr[2] <<  8 | ptr[3]);
        msg->h.numAuthorities = (mDNSu16)((mDNSu16)ptr[4] <<  8 | ptr[5]);
        msg->h.numAdditionals = (mDNSu16)((mDNSu16)ptr[6] <<  8 | ptr[7]);
-       
+
        if (ttl < 254)
                {
                debugf("** Apparent spoof mDNS %s packet from %#-15a to %#-15a TTL %d on %p with %2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s",
@@ -779,14 +979,24 @@ mDNSexport void mDNSCoreReceive(mDNS *const m, DNSMessage *const msg, const mDNS
        // All IPv6 packets should just be duplicates of the v4 packets.
        if (AddressMatchesFilterList(srcaddr))
                {
-               if      (QR_OP == StdQ) DisplayQuery   (m, msg, end, srcaddr, srcport, InterfaceID);
-               else if (QR_OP == StdR) DisplayResponse(m, msg, end, srcaddr, srcport, InterfaceID);
+               mDNS_Lock(m);
+               if (!mDNSAddrIsDNSMulticast(dstaddr))
+                       {
+                       if      (QR_OP == StdQ) mprintf("Unicast query from %#a\n", srcaddr);
+                       else if (QR_OP == StdR) ProcessUnicastResponse(m, msg, end, srcaddr,                   InterfaceID);
+                       }
                else
                        {
-                       debugf("Unknown DNS packet type %02X%02X (ignored)", msg->h.flags.b[0], msg->h.flags.b[1]);
-                       GotPacketFromHost(srcaddr, HostPkt_B);
-                       NumPktB++;
+                       if      (QR_OP == StdQ) DisplayQuery          (m, msg, end, srcaddr, srcport, dstaddr, InterfaceID, ttl);
+                       else if (QR_OP == StdR) DisplayResponse       (m, msg, end, srcaddr, srcport, dstaddr, InterfaceID, ttl);
+                       else
+                               {
+                               debugf("Unknown DNS packet type %02X%02X (ignored)", msg->h.flags.b[0], msg->h.flags.b[1]);
+                               GotPacketFromHost(srcaddr, HostPkt_B, msg->h.id);
+                               NumPktB++;
+                               }
                        }
+               mDNS_Unlock(m);
                }
        }
 
@@ -794,6 +1004,7 @@ mDNSlocal mStatus mDNSNetMonitor(void)
        {
        struct tm tm;
        int h, m, s, mul, div, TotPkt;
+       sigset_t signals;
        
        mStatus status = mDNS_Init(&mDNSStorage, &PlatformStorage,
                mDNS_Init_NoCache, mDNS_Init_ZeroCacheSize,
@@ -802,7 +1013,16 @@ mDNSlocal mStatus mDNSNetMonitor(void)
        if (status) return(status);
 
        gettimeofday(&tv_start, NULL);
-       ExampleClientEventLoop(&mDNSStorage);   // Wait for user to hit Ctrl-C
+       mDNSPosixListenForSignalInEventLoop(SIGINT);
+       mDNSPosixListenForSignalInEventLoop(SIGTERM);
+
+       do 
+               {
+               struct timeval  timeout = { 0x3FFFFFFF, 0 };    // wait until SIGINT or SIGTERM
+               mDNSBool                gotSomething;
+               mDNSPosixRunEventLoopOnce(&mDNSStorage, &timeout, &signals, &gotSomething);
+               }
+       while ( !( sigismember( &signals, SIGINT) || sigismember( &signals, SIGTERM)));
        
        // Now display final summary
        TotPkt = NumPktQ + NumPktL + NumPktR;
@@ -847,12 +1067,12 @@ mDNSlocal mStatus mDNSNetMonitor(void)
        mprintf("Total Answers/Announcements:      %7d   (avg%5d/min)\n", NumAnswers,     NumAnswers     * mul / div);
        mprintf("Total Additional Records:         %7d   (avg%5d/min)\n", NumAdditionals, NumAdditionals * mul / div);
        mprintf("\n");
-       printstats(15);
+       printstats(kReportTopServices);
 
        if (!ExactlyOneFilter)
                {
-               ShowSortedHostList(&IPv4HostList, 15);
-               ShowSortedHostList(&IPv6HostList, 15);
+               ShowSortedHostList(&IPv4HostList, kReportTopHosts);
+               ShowSortedHostList(&IPv6HostList, kReportTopHosts);
                }
 
        mDNS_Close(&mDNSStorage);
@@ -868,9 +1088,9 @@ mDNSexport int main(int argc, char **argv)
 
        for (i=1; i<argc; i++)
                {
-               FilterList *f;
                struct in_addr s4;
                struct in6_addr s6;
+               FilterList *f;
                mDNSAddr a;
                a.type = mDNSAddrType_IPv4;
 
diff --git a/mDNSPosix/PosixDaemon.c b/mDNSPosix/PosixDaemon.c
new file mode 100644 (file)
index 0000000..6e943de
--- /dev/null
@@ -0,0 +1,323 @@
+/*
+ * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+       File:           daemon.c
+
+       Contains:       main & associated Application layer for mDNSResponder on Linux.
+
+       Version:        1.0
+       Tabs:           4 spaces
+
+    Change History (most recent first):
+
+$Log: PosixDaemon.c,v $
+Revision 1.10  2004/06/08 04:59:40  cheshire
+Tidy up wording -- log messages are already prefixed with "mDNSResponder", so don't need to repeat it
+
+Revision 1.9  2004/05/29 00:14:20  rpantos
+<rdar://problem/3508093> Runtime check to disable prod mdnsd on OS X.
+
+Revision 1.8  2004/04/07 01:19:04  cheshire
+Hash slot value should be unsigned
+
+Revision 1.7  2004/02/14 06:34:57  cheshire
+Use LogMsg instead of fprintf( stderr
+
+Revision 1.6  2004/02/14 01:10:42  rpantos
+Allow daemon to run if 'nobody' is not defined, with a warning. (For Roku HD1000.)
+
+Revision 1.5  2004/02/05 07:45:43  cheshire
+Add Log header
+
+Revision 1.4  2004/01/28 21:14:23  cheshire
+Reconcile debug_mode and gDebugLogging into a single flag (mDNS_DebugMode)
+
+Revision 1.3  2004/01/19 19:51:46  cheshire
+Fix compiler error (mixed declarations and code) on some versions of Linux
+
+Revision 1.2  2003/12/11 03:03:51  rpantos
+Clean up mDNSPosix so that it builds on OS X again.
+
+Revision 1.1  2003/12/08 20:47:02  rpantos
+Add support for mDNSResponder on Linux.
+
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <errno.h>
+#include <pwd.h>
+#include <sys/types.h>
+
+#include "mDNSClientAPI.h"
+#include "mDNSDebug.h"
+#include "mDNSPosix.h"
+#include "uds_daemon.h"
+
+
+static void            ParseCmdLinArgs( int argc, char **argv);
+static void            DumpStateLog( mDNS *m);
+static mStatus MainLoop( mDNS *m);
+
+
+#define RR_CACHE_SIZE 500
+static CacheRecord gRRCache[RR_CACHE_SIZE];
+
+extern const char mDNSResponderVersionString[];
+
+int            main( int argc, char **argv)
+{
+       mDNS                                    mDNSRecord;
+       mDNS_PlatformSupport    platformStorage;
+       mStatus                                 err;
+
+       bzero( &mDNSRecord, sizeof mDNSRecord);
+       bzero( &platformStorage, sizeof platformStorage);
+
+       ParseCmdLinArgs( argc, argv);
+
+       err = mDNS_Init( &mDNSRecord, &platformStorage, gRRCache, RR_CACHE_SIZE, mDNS_Init_AdvertiseLocalAddresses, 
+                                       mDNS_Init_NoInitCallback, mDNS_Init_NoInitCallbackContext); 
+
+       if ( mStatus_NoError == err)
+               err = udsserver_init( &mDNSRecord);
+
+       // Now that we're finished with anything privileged, switch over to running as "nobody"
+       if ( mStatus_NoError == err)
+       {
+               const struct passwd *pw = getpwnam("nobody");
+               if ( pw != NULL)
+                       setuid( pw->pw_uid);
+               else
+                       LogMsg("WARNING: mdnsd continuing as root because user \"nobody\" does not exist");
+       }
+
+       if ( mStatus_NoError == err)
+               err = MainLoop( &mDNSRecord);
+       mDNS_Close( &mDNSRecord);
+
+       if (udsserver_exit() < 0)
+               LogMsg("ExitCallback: udsserver_exit failed");
+ #if MDNS_DEBUGMSGS > 0
+       printf( "mDNSResponder exiting normally with %ld\n", err);
+ #endif
+       return err;
+}
+
+
+static void    ParseCmdLinArgs( int argc, char **argv)
+// Do appropriate things at startup with command line arguments. Calls exit() if unhappy.
+{
+       if ( argc > 1)
+       {
+               if ( 0 == strcmp( argv[1], "-debug"))
+               {
+                       mDNS_DebugMode = mDNStrue;
+               }
+               else
+                       printf( "Usage: mDNSResponder [-debug]\n");
+       }
+
+       if ( !mDNS_DebugMode)
+       {
+               int             result = daemon( 0, 0);
+               
+               if ( result != 0)
+               {
+                       LogMsg("Could not run as daemon - exiting");
+                       exit( result);
+               }
+
+#if __APPLE__
+               {
+                       LogMsg("The POSIX mDNSResponder should only be used on OS X for testing - exiting");
+                       exit( -1);
+               }
+#endif
+       }
+}
+
+
+static void            DumpStateLog( mDNS *m)
+// Dump a little log of what we've been up to.
+{
+       mDNSu32 slot;
+       CacheRecord *rr;
+       mDNSu32 CacheUsed = 0, CacheActive = 0;
+       mDNSs32 now = mDNSPlatformTimeNow();
+
+       LogMsgIdent(mDNSResponderVersionString, "---- BEGIN STATE LOG ----");
+
+       for (slot = 0; slot < CACHE_HASH_SLOTS; slot++)
+               {
+               mDNSu32 SlotUsed = 0;
+               for (rr = m->rrcache_hash[slot]; rr; rr=rr->next)
+                       {
+                       mDNSs32 remain = rr->resrec.rroriginalttl - (now - rr->TimeRcvd) / mDNSPlatformOneSecond;
+                       CacheUsed++;
+                       SlotUsed++;
+                       if (rr->CRActiveQuestion) CacheActive++;
+                       LogMsgNoIdent("%s%6ld %-6s%-6s%s", rr->CRActiveQuestion ? "*" : " ", remain, DNSTypeName(rr->resrec.rrtype),
+                               ((PosixNetworkInterface *)rr->resrec.InterfaceID)->intfName, GetRRDisplayString(m, rr));
+                       usleep(1000);   // Limit rate a little so we don't flood syslog too fast
+                       }
+               if (m->rrcache_used[slot] != SlotUsed)
+                       LogMsgNoIdent("Cache use mismatch: rrcache_used[slot] is %lu, true count %lu", m->rrcache_used[slot], SlotUsed);
+               }
+       if (m->rrcache_totalused != CacheUsed)
+               LogMsgNoIdent("Cache use mismatch: rrcache_totalused is %lu, true count %lu", m->rrcache_totalused, CacheUsed);
+       if (m->rrcache_active != CacheActive)
+               LogMsgNoIdent("Cache use mismatch: rrcache_active is %lu, true count %lu", m->rrcache_active, CacheActive);
+       LogMsgNoIdent("Cache currently contains %lu records; %lu referenced by active questions", CacheUsed, CacheActive);
+
+       udsserver_info();
+
+       LogMsgIdent(mDNSResponderVersionString, "----  END STATE LOG  ----");
+}
+
+static mStatus MainLoop( mDNS *m)
+// Loop until we quit.
+{
+       sigset_t        signals;
+       mDNSBool        gotData = mDNSfalse;
+
+       mDNSPosixListenForSignalInEventLoop( SIGINT);
+       mDNSPosixListenForSignalInEventLoop( SIGTERM);
+       mDNSPosixListenForSignalInEventLoop( SIGUSR1);
+       mDNSPosixListenForSignalInEventLoop( SIGPIPE);
+
+       for ( ; ;)
+       {
+               // Work out how long we expect to sleep before the next scheduled task
+               struct timeval  timeout;
+               mDNSs32                 ticks;
+
+               // Only idle if we didn't find any data the last time around
+               if ( !gotData)
+               {
+                       mDNSs32                 nextTimerEvent = mDNS_Execute(m);
+               
+                       nextTimerEvent = udsserver_idle( nextTimerEvent);
+       
+                       ticks = nextTimerEvent - mDNSPlatformTimeNow();
+                       if (ticks < 1) ticks = 1;
+               }
+               else    // otherwise call EventLoop again with 0 timemout
+                       ticks = 0;
+
+               timeout.tv_sec = ticks / mDNSPlatformOneSecond;
+               timeout.tv_usec = (ticks % mDNSPlatformOneSecond) * 1000000 / mDNSPlatformOneSecond;
+
+               (void) mDNSPosixRunEventLoopOnce( m, &timeout, &signals, &gotData);
+
+               if ( sigismember( &signals, SIGUSR1))
+                       DumpStateLog( m);
+               if ( sigismember( &signals, SIGPIPE))   // happens when we try to write to a dead client; death should be detected soon in request_callback() and cleaned up.
+                       LogMsg("Received SIGPIPE - ignoring");
+               if ( sigismember( &signals, SIGINT) || sigismember( &signals, SIGTERM))
+                       break;
+       }
+
+       return EINTR;
+}
+
+
+//             uds_daemon support              ////////////////////////////////////////////////////////////
+
+#if MDNS_MALLOC_DEBUGGING >= 2
+#define LogMalloc LogMsg
+#else
+#define        LogMalloc(ARGS...) ((void)0)
+#endif
+
+
+mStatus udsSupportAddFDToEventLoop( int fd, udsEventCallback callback, void *context)
+/* Support routine for uds_daemon.c */
+{
+       // Depends on the fact that udsEventCallback == mDNSPosixEventCallback
+       return mDNSPosixAddFDToEventLoop( fd, callback, context);
+}
+
+mStatus udsSupportRemoveFDFromEventLoop( int fd)
+{
+       return mDNSPosixRemoveFDFromEventLoop( fd);
+}
+
+#if MACOSX_MDNS_MALLOC_DEBUGGING >= 1
+
+void *mallocL(char *msg, unsigned int size)
+{
+       unsigned long *mem = malloc(size+8);
+       if (!mem)
+       {
+               LogMsg("malloc( %s : %d ) failed", msg, size);
+               return(NULL); 
+       }
+       else
+       {
+               LogMalloc("malloc( %s : %lu ) = %p", msg, size, &mem[2]);
+               mem[0] = 0xDEAD1234;
+               mem[1] = size;
+               //bzero(&mem[2], size);
+               memset(&mem[2], 0xFF, size);
+//             validatelists(&mDNSStorage);
+               return(&mem[2]);
+       }
+}
+
+void freeL(char *msg, void *x)
+{
+       if (!x)
+               LogMsg("free( %s @ NULL )!", msg);
+       else
+       {
+               unsigned long *mem = ((unsigned long *)x) - 2;
+               if (mem[0] != 0xDEAD1234)
+                       { LogMsg("free( %s @ %p ) !!!! NOT ALLOCATED !!!!", msg, &mem[2]); return; }
+               if (mem[1] > 8000)
+                       { LogMsg("free( %s : %ld @ %p) too big!", msg, mem[1], &mem[2]); return; }
+               LogMalloc("free( %s : %ld @ %p)", msg, mem[1], &mem[2]);
+               //bzero(mem, mem[1]+8);
+               memset(mem, 0xDD, mem[1]+8);
+//             validatelists(&mDNSStorage);
+               free(mem);
+       }
+}
+
+#endif // MACOSX_MDNS_MALLOC_DEBUGGING >= 1
+
+
+
+// For convenience when using the "strings" command, this is the last thing in the file
+#if mDNSResponderVersion > 1
+mDNSexport const char mDNSResponderVersionString[] = "mDNSResponder-" STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ") ";
+#else
+mDNSexport const char mDNSResponderVersionString[] = "mDNSResponder (Engineering Build) (" __DATE__ " " __TIME__ ") ";
+#endif
index 13f0d18441e7ad1678f1edbc5e6f673f6e423dd6..5030d9330e8df98ea27315d6e16194ebab1ad55e 100644 (file)
@@ -3,6 +3,8 @@
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
     Change History (most recent first):
 
 $Log: ProxyResponder.c,v $
+Revision 1.27  2004/03/12 08:03:14  cheshire
+Update comments
+
+Revision 1.26  2004/01/25 00:00:39  cheshire
+Change to use mDNSOpaque16fromIntVal() instead of shifting and masking
+
+Revision 1.25  2003/12/08 20:47:02  rpantos
+Add support for mDNSResponder on Linux.
+
 Revision 1.24  2003/11/14 21:27:09  cheshire
 <rdar://problem/3484766>: Security: Crashing bug in mDNSResponder
 Fix code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1005) instead of 256-byte buffers.
@@ -64,7 +75,7 @@ Revision 1.13  2003/04/18 22:46:12  cheshire
 Fix mistake in 1.8 -- INADDR_NONE is 0xFFFFFFFF, not 0
 
 Revision 1.12  2003/04/16 02:11:07  cheshire
-Fixed mDNS_RegisterNoSuchService non-existence function so that it works again
+Fixed mDNS_RegisterNoSuchService non-existance function so that it works again
 
 Revision 1.11  2003/03/31 22:49:35  cheshire
 Add "$Log" header
@@ -75,6 +86,7 @@ Add "$Log" header
 #include <stdlib.h>                    // For exit() etc.
 #include <string.h>                    // For strlen() etc.
 #include <unistd.h>                    // For select()
+#include <signal.h>                    // For SIGINT, SIGTERM
 #include <errno.h>                     // For errno, EINTR
 #include <arpa/inet.h>         // For inet_addr()
 #include <netinet/in.h>                // For INADDR_NONE
@@ -181,15 +193,12 @@ mDNSlocal void RegisterService(mDNS *m, ServiceRecordSet *recordset,
        {
        domainlabel n;
        domainname t, d;
-       mDNSIPPort port;
        unsigned char txtbuffer[1024], *bptr = txtbuffer;
        char buffer[MAX_ESCAPED_DOMAIN_NAME];
 
        MakeDomainLabelFromLiteralString(&n, name);
        MakeDomainNameFromDNSNameString(&t, type);
        MakeDomainNameFromDNSNameString(&d, domain);
-       port.b[0] = (mDNSu8)(PortAsNumber >> 8);
-       port.b[1] = (mDNSu8)(PortAsNumber     );
        while (argc)
                {
                int len = strlen(argv[0]);
@@ -203,10 +212,10 @@ mDNSlocal void RegisterService(mDNS *m, ServiceRecordSet *recordset,
        
        mDNS_RegisterService(m, recordset,
                &n, &t, &d,                                     // Name, type, domain
-               host, port,                                     // Host and port
+               host, mDNSOpaque16fromIntVal(PortAsNumber),
                txtbuffer, bptr-txtbuffer,      // TXT data, length
                mDNSNULL, 0,                            // Subtypes
-               mDNSInterface_Any,                      // Interace ID
+               mDNSInterface_Any,                      // Interface ID
                ServiceCallback, mDNSNULL);     // Callback and context
 
        ConvertDomainNameToCString(&recordset->RR_SRV.resrec.name, buffer);
@@ -272,7 +281,8 @@ mDNSlocal void RegisterNoSuchService(mDNS *m, AuthRecord *const rr, domainname *
 
 mDNSexport int main(int argc, char **argv)
        {
-       mStatus status;
+       mStatus                 status;
+       sigset_t                signals;
        
        if (argc < 3) goto usage;
        
@@ -282,6 +292,9 @@ mDNSexport int main(int argc, char **argv)
                mDNS_Init_NoInitCallback, mDNS_Init_NoInitCallbackContext);
        if (status) { fprintf(stderr, "Daemon start: mDNS_Init failed %ld\n", status); return(status); }
 
+       mDNSPosixListenForSignalInEventLoop(SIGINT);
+       mDNSPosixListenForSignalInEventLoop(SIGTERM);
+
        if (!strcmp(argv[1], "-"))
                {
                domainname proxyhostname;
@@ -291,8 +304,6 @@ mDNSexport int main(int argc, char **argv)
                AppendLiteralLabelString(&proxyhostname, argv[2]);
                AppendLiteralLabelString(&proxyhostname, "local");
                RegisterNoSuchService(&mDNSStorage, &proxyrecord, &proxyhostname, argv[3], argv[4], "local.");
-               ExampleClientEventLoop(&mDNSStorage);
-               mDNS_Close(&mDNSStorage);
                }
        else
                {
@@ -318,10 +329,17 @@ mDNSexport int main(int argc, char **argv)
                if (argc >=6)
                        RegisterService(&mDNSStorage, &proxyservice, argv[3], argv[4], "local.",
                                                        &proxyhost.RR_A.resrec.name, atoi(argv[5]), argc-6, &argv[6]);
+               }
 
-               ExampleClientEventLoop(&mDNSStorage);
-               mDNS_Close(&mDNSStorage);
+       do 
+               {
+               struct timeval  timeout = { 0x3FFFFFFF, 0 };    // wait until SIGINT or SIGTERM
+               mDNSBool                gotSomething;
+               mDNSPosixRunEventLoopOnce(&mDNSStorage, &timeout, &signals, &gotSomething);
                }
+       while ( !( sigismember( &signals, SIGINT) || sigismember( &signals, SIGTERM)));
+
+       mDNS_Close(&mDNSStorage);
 
        return(0);
 
index fc00dbdb188ada9804909fd391054c4751e13270..06df6e7fbcec9bfb3b373dd0c28f2f4df88bb690 100755 (executable)
@@ -1,9 +1,7 @@
 ReadMe About mDNSPosix
 ----------------------
 
-mDNSPosix is a port of Apple's core mDNS code to the Posix platform. 
-The sample shows how you might implement an mDNS responder inside an
-embedded device, such as a printer or a web camera.
+mDNSPosix is a port of Apple's core mDNS code to Posix platforms.
 
 mDNS is short for "multicast DNS", which is a technology that allows you
 to register IP services and browse the network for those services.  For
@@ -11,9 +9,9 @@ more information about mDNS, see the mDNS web site.
 
   <http://www.multicastdns.org/>
 
-mDNS is part of a family of technologies developed by the IETF zeroconf
-working group.  For information about other zeroconf technologies, see
-the zeroconf web site.
+mDNS is part of a family of technologies resulting from the efforts of
+the IETF zeroconf working group.  For information about other zeroconf
+technologies, see the zeroconf web site.
 
   <http://www.zeroconf.org/>
 
@@ -25,198 +23,121 @@ The code in this sample was compiled and tested on Mac OS X (10.1.x,
 10.2), Solaris (SunOS 5.6), Linux (Redhat 2.4.9-21), and OpenBSD (2.9). 
 YMMV.
 
-IMPORTANT
-This sample is not a full port of Apple's Rendezvous APIs to Posix. 
-Specifically, the sample includes a responder daemon that registers
-entities based on its command line arguments (or a text file).  This is
-perfect for a embedded device, but is not suitable for a general purpose
-computer.  A real implementation of the Rendezvous APIs would require a
-mDNS daemon, client libraries that applications link with, and some form
-of RPC between them.  Client libraries and client-to-daemon RPC are
-beyond the scope of this sample, however, this would be a good place to
-start if you were interested in implementing these facilities on your
-platform.
-
 
 Packing List
 ------------
-The sample includes the following files and directories:
-
-o ReadMe.txt -- This file.
-
-o mDNSCore -- A directory containing the core mDNS code.  This code is
-  written in pure ANSI C and has proved to be very portable.
-
-o mDNSPosix.h -- The interface to the platform support code.
-
-o mDNSPosix.c -- The platform support code for the Posix platform.
-  This code glues the mDNS core to Posix.
-
-o mDNSUNP.h -- Interface to the code in "mDNSUNP.c".
-
-o mDNSUNP.c -- A few routines from the "Unix Network Programming" book
-  that I borrowed to make the port easier.  The routines are slightly
-  modified from the originals to meet my specific needs.  You can get the
-  originals at the URL below.
 
-  <http://www.kohala.com/start/unpv12e.html>
+The sample uses the following directories:
 
-o Client.c -- The main program for the sample mDNS client.
+o mDNSCore -- A directory containing the core mDNS code.  This code
+  is written in pure ANSI C and has proved to be very portable.
+  Every platform needs this core protocol engine code.
 
-o Responder.c -- The main program for the sample mDNS responder.
+o mDNSShared -- A directory containing useful code that's not core to
+  the main protocol engine itself, but nonetheless useful, and used by
+  more than one (but not necessarily all) platforms.
 
-o Services.txt -- A sample configuration file for the mDNS responder. 
-  You can test with this file using the option "-f Services.txt".
+o mDNSPosix -- The files that are specific to Posix platforms: Linux,
+  Solaris, FreeBSD, NetBSD, OpenBSD, etc. This code will also work on
+  OS X, though that's not its primary purpose.
 
-o ProxyResponder.c -- Another sample mDNS responder, this one intended
-  for creating proxy registrations for other network devices that don't
-  have their own mDNS responders.
+o Clients -- Example client code showing how to use the API to the
+  services provided by the daemon.
 
-o ExampleClientApp.h
-o ExampleClientApp.c -- shared code prioviding the
-  "ExampleClientEventLoop" used by Client.c and ProxyResponder.c.
 
-o Makefile -- A makefile for building on Mac OS X and other platforms.
+Building the Code
+-----------------
 
-
-Building the Sample
--------------------
 The sample does not use autoconf technology, primarily because I didn't
 want to delay shipping while I learnt how to use it.  Thus the code
 builds using a very simple make file.  To build the sample you should
-type "make os=myos", e.g.
+cd to the mDNSPosix directory and type "make os=myos", e.g.
 
-    make os=osx
+    make os=panther
 
 For Linux you would change that to:
 
     make os=linux
 
 There are definitions for each of the platforms I ported to.  If you're
-porting to any other platform you'll have to add appropriate definitions
-for it.
+porting to any other platform please add appropriate definitions for it
+and send us the diffs so they can be incorporated into the main
+distribution.
 
 
 Using the Sample
 ----------------
-Once you've built the sample you can test it by first running the
-client, as shown below.
-
-  quinn% build/mDNSClientPosix
-  Hit ^C when you're bored waiting for responses.
-
-By default the client starts a search for AppleShare servers and then
-sits and waits, printing a message when services appear and disappear.
-
-To continue with the test you should start the responder in another
-shell window.
-
-  quinn% build/mDNSResponderPosix -n Foo
-
-This will start the responder and tell it to advertise a AppleShare
-service "Foo".  In the client window you will see the client print out
-the following as the service shows up on the network.
-
-  quinn% build/mDNSClientPosix
-  Hit ^C when you're bored waiting for responses.
-  *** Found name = 'Foo', type = '_afpovertcp._tcp.', domain = 'local.'
+When you compile, you will get:
 
-Back in the responder window you can quit the responder cleanly using
-SIGINT (typically ^C).
+o Main products for general-purpose use (e.g. on a desktop computer):
+  - mdnsd
+  - libmdns
 
-  quinn% build/mDNSResponderPosix -n Foo
-  ^C
-  quinn%
+o Standalone products for dedicated devices (printer, network camera, etc.)
+  - mDNSClientPosix
+  - mDNSResponderPosix
+  - mDNSProxyResponderPosix
 
-As the responder quits it will multicast that the "Foo" service is
-disappearing and the client will see that notification and print a
-message to that effect (shown below).  Finally, when you're done with
-the client you can use SIGINT to quit it.
+o Debugging tools
+  - mDNSNetMonitor
+  - mDNSIdentify
 
-  quinn% build/mDNSClientPosix
-  Hit ^C when you're bored waiting for responses.
-  *** Found name = 'Foo', type = '_afpovertcp._tcp.', domain = 'local.'
-  *** Lost  name = 'Foo', type = '_afpovertcp._tcp.', domain = 'local.'
-  ^C
-  quinn%
+Type "sudo make install" to install four things:
+o mdnsd           (usually in /usr/sbin)
+o libmdns         (usually in /usr/lib)
+o dns_sd.h        (usually in /usr/include)
+o startup scripts (e.g. in /etc/rc.d)
 
-If things don't work, try starting each program in verbose mode (using
-the "-v 1" option, or very verbose mode with "-v 2") to see if there's
-an obvious cause.
-
-That's it for the core functionality.  Each program supports a variety
-of other options.  For example, you can advertise and browse for a
-different service type using the "-t type" option.  Use the "-?" option
-on each program for more user-level information.
+Once you've installed the header and the library, and started the
+daemon running, you can cd to the "Clients" folder and type "make".
+This builds a test client showing how to exercise all the major
+functionality of the daemon.
 
 
 How It Works
 ------------
-A typical mDNS program is divided into three sections.
-
-    +----------------+
-    |   Application  |
-    +----------------+
-    |    mDNS Core   |
-    +----------------+
-    | Posix Platform |
-    +----------------+
-
-The mDNS core code comprises the files in the "mDNSCore" directory. 
-It's standard ANSI C that's very portable.  It relies on the underlying
-platform code for all external functionality.
-
-In this example the external platform code glues the mDNS core to a
-POSIX-ish platform.  This code is contained in the files:
-
-o mDNSPosix.h
-o mDNSPosix.c
-o mDNSUNP.h
-o mDNSUNP.c
+                                                   +--------------------+
+                                                   | Client Application |
+   +----------------+                              +--------------------+
+   |  uds_daemon.c  | <--- Unix Domain Socket ---> |      libmdns       |
+   +----------------+                              +--------------------+
+   |    mDNSCore    |
+   +----------------+
+   |  mDNSPosix.c   |
+   +----------------+
 
-The guts of the code is in "mDNSPosix.c".
+mdnsd is divided into three sections.
 
-I should be clear that true POSIX isn't powerful enough to accomplish
-the job, so this code doesn't compile with _POSIX_SOURCE defined and
-there's a bunch of conditional code that does different things on
-different Unixen.  I've isolated the hairiest parts of this code in the
-"mDNSUNP".
+o mDNSCore is the main protocol engine
+o mDNSPosix.c provides the glue it needs to run on a Posix OS
+o uds_daemon.c exports a Unix Domain Socket interface to
+  the services provided by mDNSCore
 
-Above the mDNS core code is the code that actually does
-application-specific tasks.  In this example I've supplied two
-application programs: the responder (Responder.c) acts as a simple mDNS
-responder, listening for mDNS service lookup requests and answering
-them, and the client (Client.c), which is a simple mDNS browser, making
-simple mDNS search queries.  Both programs use the same mDNS core and
-Posix platform code.
+Client applications link with the libmdns, which implements the functions
+defined in the dns_sd.h header file, and implements the IPC protocol
+used to communicate over the Unix Domain Socket interface to the daemon.
 
-A discussion of the mDNS protocol itself is beyond the scope of this
-sample.  Quite frankly, my goal here was to demonstrate how it easy it
-is to use Apple's mDNS core without actually understanding mDNS, and
-because I achieved that goal I never had to learn a lot about how the
-mDNS core code works.  It's just a black box that I call.  If you want
-to learn more about mDNS, see the references at the top of this file.
 
-The mDNS Posix platform code is actually pretty simple.  mDNS core
-requires six key features in its platform support.
+Clients for Embedded Systems
+----------------------------
 
-o the core calls the platformm at startup (mDNSPlatformInit)
-  and shutdown (mDNSPlatformClose)
+For small devices with very constrained resources, with a single address
+space and (typically) no virtual memory, the uds_daemon.c/UDS/libmdns
+layer may be eliminated, and the Client Application may live directly
+on top of mDNSCore:
 
-o the core calls the platform to send a UDP packet (mDNSPlatformSendUDP)
+    +--------------------+
+    | Client Application |
+    +--------------------+
+    |      mDNSCore      |
+    +--------------------+
+    |    mDNSPosix.c     |
+    +--------------------+
 
-o the core calls the platform to set a timer (mDNSPlatformScheduleTask)
+Programming to this model is more work, so using the daemon and its
+library is recommended if your platform is capable of that.
 
-o the platform calls the core (mDNSCoreTask) when the timer expires
-
-o the platform calls the core (mDNSCoreReceive) when a UDP datagram arrives
-
-o the platform calls the core when network interfaces are
-  added (mDNS_RegisterInterface) or removed (mDNS_DeregisterInterface)
-
-All of these features are implemented in "mDNSPosix.c".
-
-The runtime behaviour of the code is as follows.
+The runtime behaviour when using the embedded model is as follows:
 
 1. The application calls mDNS_Init, which in turns calls the platform
    (mDNSPlatformInit).
@@ -252,7 +173,58 @@ not multi-threaded.  I do everything from a main loop that calls
 "select()".  This is good because it avoids all the problems that often
 accompany multi-threaded code. If you decide to use threads in your
 platform, you will have to implement the mDNSPlatformLock() and
-mDNSPlatformUnlock() calls which are no-ops in mDNSPosix.c.
+mDNSPlatformUnlock() calls which are currently no-ops in mDNSPosix.c.
+
+
+Once you've built the embedded samples you can test them by first
+running the client, as shown below.
+
+  quinn% build/mDNSClientPosix
+  Hit ^C when you're bored waiting for responses.
+
+By default the client starts a search for AppleShare servers and then
+sits and waits, printing a message when services appear and disappear.
+
+To continue with the test you should start the responder in another
+shell window.
+
+  quinn% build/mDNSResponderPosix -n Foo
+
+This will start the responder and tell it to advertise a AppleShare
+service "Foo".  In the client window you will see the client print out
+the following as the service shows up on the network.
+
+  quinn% build/mDNSClientPosix
+  Hit ^C when you're bored waiting for responses.
+  *** Found name = 'Foo', type = '_afpovertcp._tcp.', domain = 'local.'
+
+Back in the responder window you can quit the responder cleanly using
+SIGINT (typically ^C).
+
+  quinn% build/mDNSResponderPosix -n Foo
+  ^C
+  quinn%
+
+As the responder quits it will multicast that the "Foo" service is
+disappearing and the client will see that notification and print a
+message to that effect (shown below).  Finally, when you're done with
+the client you can use SIGINT to quit it.
+
+  quinn% build/mDNSClientPosix
+  Hit ^C when you're bored waiting for responses.
+  *** Found name = 'Foo', type = '_afpovertcp._tcp.', domain = 'local.'
+  *** Lost  name = 'Foo', type = '_afpovertcp._tcp.', domain = 'local.'
+  ^C
+  quinn%
+
+If things don't work, try starting each program in verbose mode (using
+the "-v 1" option, or very verbose mode with "-v 2") to see if there's
+an obvious cause.
+
+That's it for the core functionality.  Each program supports a variety
+of other options.  For example, you can advertise and browse for a
+different service type using the "-t type" option.  Use the "-?" option
+on each program for more user-level information.
 
 
 Caveats
@@ -305,6 +277,5 @@ Networking, Communications, Hardware
 
 To Do List
 ----------
-Â¥ port to a System V that's not Solaris
-Â¥ use sig_atomic_t for signal to main thread flags
-Â¥ test and debug the daemon function, including properly logging
+• port to a System V that's not Solaris
+• use sig_atomic_t for signal to main thread flags
index 936df495aca81121dd9aba911793432b3123b060..a8c297a13417d651cbca593da12bebdc13ec1d73 100755 (executable)
@@ -3,6 +3,8 @@
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
     Change History (most recent first):
 
 $Log: Responder.c,v $
-Revision 1.16.2.1  2004/04/07 23:51:09  cheshire
-Remove obsolete comments referring to doing mDNS on port 53
+Revision 1.20  2004/05/18 23:51:26  cheshire
+Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
+
+Revision 1.19  2004/03/12 08:03:14  cheshire
+Update comments
+
+Revision 1.18  2004/01/25 00:00:55  cheshire
+Change to use mDNSOpaque16fromIntVal() instead of shifting and masking
+
+Revision 1.17  2003/12/11 19:11:55  cheshire
+Fix compiler warning
 
 Revision 1.16  2003/08/14 02:19:55  cheshire
 <rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
@@ -60,7 +71,7 @@ Revision 1.6  2003/03/08 00:35:56  cheshire
 Switched to using new "mDNS_Execute" model (see "mDNSCore/Implementer Notes.txt")
 
 Revision 1.5  2003/02/20 06:48:36  cheshire
-Bug #: 3169535 Xserve RAID needs to do interface-specific registrations
+<rdar://problem/3169535> Xserve RAID needs to do interface-specific registrations
 Reviewed by: Josh Graessley, Bob Bradley
 
 Revision 1.4  2003/01/28 03:07:46  cheshire
@@ -357,13 +368,14 @@ enum {
 static void PrintUsage()
 {
     fprintf(stderr, 
-            "Usage: %s [-v level ] [-n name] [-t type] [-d domain] [-x TXT] [-p port] [-f file] [-b] [-P pidfile]\n", 
+            "Usage: %s [-v level ] [-r] [-n name] [-t type] [-d domain] [-x TXT] [-p port] [-f file] [-b] [-P pidfile]\n", 
             gProgramName);
     fprintf(stderr, "          -v verbose mode, level is a number from 0 to 2\n");
     fprintf(stderr, "             0 = no debugging info (default)\n");
     fprintf(stderr, "             1 = standard debugging info\n");
     fprintf(stderr, "             2 = intense debugging info\n");
     fprintf(stderr, "             can be cycled kill -USR1\n");
+    fprintf(stderr, "          -r also bind to port 53 (port 5353 is always bound)\n");
     fprintf(stderr, "          -n uses 'name' as the host name (default is none)\n");
     fprintf(stderr, "          -t uses 'type' as the service type (default is '%s')\n", kDefaultServiceType);
     fprintf(stderr, "          -d uses 'domain' as the service domain (default is '%s')\n", kDefaultServiceDomain);
@@ -376,6 +388,7 @@ static void PrintUsage()
     fprintf(stderr, "             only meaningful if -b also specified\n");
 }
 
+static   mDNSBool  gAvoidPort53      = mDNStrue;
 static const char *gRichTextHostName = "";
 static const char *gServiceType      = kDefaultServiceType;
 static const char *gServiceDomain    = kDefaultServiceDomain;
@@ -416,6 +429,9 @@ static void ParseArguments(int argc, char **argv)
                         exit(1);
                     }
                     break;
+                case 'r':
+                    gAvoidPort53 = mDNSfalse;
+                    break;
                 case 'n':
                     gRichTextHostName = optarg;
                     if ( ! CheckThatRichTextHostNameIsUsable(gRichTextHostName, mDNStrue) ) {
@@ -559,7 +575,6 @@ static mStatus RegisterOneService(const char *  richTextHostName,
 {
     mStatus             status;
     PosixService *      thisServ;
-    mDNSOpaque16        port;
     domainlabel         name;
     domainname          type;
     domainname          domain;
@@ -573,14 +588,12 @@ static mStatus RegisterOneService(const char *  richTextHostName,
         MakeDomainLabelFromLiteralString(&name,  richTextHostName);
         MakeDomainNameFromDNSNameString(&type, serviceType);
         MakeDomainNameFromDNSNameString(&domain, serviceDomain);
-        port.b[0] = (portNumber >> 8) & 0x0FF;
-        port.b[1] = (portNumber >> 0) & 0x0FF;;
         status = mDNS_RegisterService(&mDNSStorage, &thisServ->coreServ,
                 &name, &type, &domain,                         // Name, type, domain
-                NULL, port,                                            // Host and port
+                NULL, mDNSOpaque16fromIntVal(portNumber),
                 text, textLen,                                         // TXT data, length
                 NULL, 0,                                                       // Subtypes
-                mDNSInterface_Any,                                     // Interace ID
+                mDNSInterface_Any,                                     // Interface ID
                 RegistrationCallback, thisServ);       // Callback and context
     }
     if (status == mStatus_NoError) {
@@ -608,20 +621,16 @@ static mStatus RegisterOneService(const char *  richTextHostName,
 }
 
 static mDNSBool ReadALine(char *buf, size_t bufSize, FILE *fp)
-{
-    mDNSBool good;
-    size_t len;
-    
-    good = (fgets(buf, bufSize, fp) != NULL);
-    if (good) {
-        len = strlen(buf);
+       {
+    mDNSBool good = (fgets(buf, bufSize, fp) != NULL);
+    if (good)
+       {
+        size_t len = strlen(buf);
         good = (len > 0 && buf[len - 1] == '\n');
-    }
-    if (good) {
-        buf[len - 1] = 0;
-    }
+               if (good) buf[len - 1] = 0;
+           }
     return good;
-}
+       }
 
 static mStatus RegisterServicesInFile(const char *filePath)
 {
index b28aa737f42e93f1b39731d5db9029935f723a22..d9426ab21e9d57f2e8fe2077316aa776ba44a6eb 100755 (executable)
@@ -3,6 +3,8 @@
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
        Change History (most recent first):
 
 $Log: mDNSPosix.c,v $
-Revision 1.25.2.1  2004/04/09 17:57:31  cheshire
-Make sure to set the TxAndRx field so that duplicate suppression works correctly
+Revision 1.46  2004/05/13 04:54:20  ksekar
+Unified list copy/free code.  Added symetric list for
+
+Revision 1.45  2004/05/12 22:03:09  ksekar
+Made GetSearchDomainList a true platform-layer call (declaration moved
+from mDNSMacOSX.h to mDNSClientAPI.h), impelemted to return "local"
+only on non-OSX platforms.  Changed call to return a copy of the list
+to avoid shared memory issues.  Added a routine to free the list.
+
+Revision 1.44  2004/04/21 02:49:11  cheshire
+To reduce future confusion, renamed 'TxAndRx' to 'McastTxRx'
+
+Revision 1.43  2004/04/14 23:09:29  ksekar
+Support for TSIG signed dynamic updates.
+
+Revision 1.42  2004/04/09 17:43:04  cheshire
+Make sure to set the McastTxRx field so that duplicate suppression works correctly
+
+Revision 1.41  2004/02/06 01:19:51  cheshire
+Conditionally exclude IPv6 code unless HAVE_IPV6 is set
+
+Revision 1.40  2004/02/05 01:00:01  rpantos
+Fix some issues that turned up when building for FreeBSD.
+
+Revision 1.39  2004/01/28 21:12:15  cheshire
+Reconcile mDNSIPv6Support & HAVE_IPV6 into a single flag (HAVE_IPV6)
+
+Revision 1.38  2004/01/27 20:15:23  cheshire
+<rdar://problem/3541288>: Time to prune obsolete code for listening on port 53
+
+Revision 1.37  2004/01/24 05:12:03  cheshire
+<rdar://problem/3534352>: Need separate socket for issuing unicast queries
+
+Revision 1.36  2004/01/24 04:59:16  cheshire
+Fixes so that Posix/Linux, OS9, Windows, and VxWorks targets build again
+
+Revision 1.35  2004/01/23 21:37:08  cheshire
+For consistency, rename multicastSocket to multicastSocket4, and multicastSocketv6 to multicastSocket6
+
+Revision 1.34  2004/01/22 03:43:09  cheshire
+Export constants like mDNSInterface_LocalOnly so that the client layers can use them
+
+Revision 1.33  2004/01/21 21:54:20  cheshire
+<rdar://problem/3448144>: Don't try to receive unicast responses if we're not the first to bind to the UDP port
+
+Revision 1.32  2004/01/20 01:49:28  rpantos
+Tweak error handling of last checkin a bit.
+
+Revision 1.31  2004/01/20 01:39:27  rpantos
+Respond to If changes by rebuilding interface list.
+
+Revision 1.30  2003/12/11 19:40:36  cheshire
+Fix 'destAddr.type == senderAddr.type;' that should have said 'destAddr.type = senderAddr.type;'
+
+Revision 1.29  2003/12/11 18:53:22  cheshire
+Fix compiler warning reported by Paul Guyot
+
+Revision 1.28  2003/12/11 03:03:51  rpantos
+Clean up mDNSPosix so that it builds on OS X again.
+
+Revision 1.27  2003/12/08 20:47:02  rpantos
+Add support for mDNSResponder on Linux.
+
+Revision 1.26  2003/11/14 20:59:09  cheshire
+Clients can't use AssignDomainName macro because mDNSPlatformMemCopy is defined in mDNSPlatformFunctions.h.
+Best solution is just to combine mDNSClientAPI.h and mDNSPlatformFunctions.h into a single file.
 
 Revision 1.25  2003/10/30 19:25:49  cheshire
 Fix signed/unsigned warning on certain compilers
@@ -122,7 +188,6 @@ First checkin
 */
 
 #include "mDNSClientAPI.h"           // Defines the interface provided to the client layer above
-#include "mDNSPlatformFunctions.h"   // Defines the interface to the supporting layer below
 #include "mDNSPosix.h"                          // Defines the specific types needed to run mDNS on this platform
 
 #include <assert.h>
@@ -131,34 +196,56 @@ First checkin
 #include <errno.h>
 #include <string.h>
 #include <unistd.h>
+#include <syslog.h>
+#include <stdarg.h>
 #include <fcntl.h>
 #include <sys/types.h>
+#include <sys/time.h>
 #include <sys/socket.h>
 #include <sys/uio.h>
+#include <sys/select.h>
 #include <netinet/in.h>
+#include <time.h>                   // platform support for UTC time
+
+#if USES_NETLINK
+#include <asm/types.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#else // USES_NETLINK
+#include <net/route.h>
+#include <net/if.h>
+#endif // USES_NETLINK
 
 #include "mDNSUNP.h"
+#include "GenLinkedList.h"
 
 // ***************************************************************************
 // Structures
 
-// PosixNetworkInterface is a record extension of the core NetworkInterfaceInfo
-// type that supports extra fields needed by the Posix platform.
-//
-// IMPORTANT: coreIntf must be the first field in the structure because
-// we cast between pointers to the two different types regularly.
-
-typedef struct PosixNetworkInterface PosixNetworkInterface;
+// 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;
 
-struct PosixNetworkInterface
+// Context record for interface change callback
+struct IfChangeRec
        {
-       NetworkInterfaceInfo    coreIntf;
-       const char *            intfName;
-       PosixNetworkInterface * aliasIntf;
-       int                     index;
-       int                     multicastSocket;
-       int                     multicastSocketv6;
+       int                     NotifySD;
+       mDNS*           mDNS;
        };
+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 sigset_t                        gEventSignalSet;                // Signals which event loop listens for
+static sigset_t                        gEventSignals;                  // Signals which were received while inside loop
 
 // ***************************************************************************
 // Globals (for debugging)
@@ -172,43 +259,6 @@ static int num_pkts_rejected = 0;
 
 int gMDNSPlatformPosixVerboseLevel = 0;
 
-// Note, this uses mDNS_vsnprintf instead of standard "vsnprintf", because mDNS_vsnprintf knows
-// how to print special data types like IP addresses and length-prefixed domain names
-mDNSexport void debugf_(const char *format, ...)
-       {
-       unsigned char buffer[512];
-       va_list ptr;
-       va_start(ptr,format);
-       buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0;
-       va_end(ptr);
-       if (gMDNSPlatformPosixVerboseLevel >= 1)
-               fprintf(stderr, "%s\n", buffer);
-       fflush(stderr);
-       }
-
-mDNSexport void verbosedebugf_(const char *format, ...)
-       {
-       unsigned char buffer[512];
-       va_list ptr;
-       va_start(ptr,format);
-       buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0;
-       va_end(ptr);
-       if (gMDNSPlatformPosixVerboseLevel >= 2)
-               fprintf(stderr, "%s\n", buffer);
-       fflush(stderr);
-       }
-
-mDNSexport void LogMsg(const char *format, ...)
-       {
-       unsigned char buffer[512];
-       va_list ptr;
-       va_start(ptr,format);
-       buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0;
-       va_end(ptr);
-       fprintf(stderr, "%s\n", buffer);
-       fflush(stderr);
-       }
-
 #define PosixErrorToStatus(errNum) ((errNum) == 0 ? mStatus_NoError : mStatus_UnknownErr)
 
 static void SockAddrTomDNSAddr(const struct sockaddr *const sa, mDNSAddr *ipAddr, mDNSIPPort *ipPort)
@@ -224,7 +274,7 @@ static void SockAddrTomDNSAddr(const struct sockaddr *const sa, mDNSAddr *ipAddr
                        break;
                        }
 
-#ifdef mDNSIPv6Support
+#if HAVE_IPV6
                case AF_INET6:
                        {
                        struct sockaddr_in6* sin6        = (struct sockaddr_in6*)sa;
@@ -250,19 +300,18 @@ static void SockAddrTomDNSAddr(const struct sockaddr *const sa, mDNSAddr *ipAddr
 
 // mDNS core calls this routine when it needs to send a packet.
 mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end,
-       mDNSInterfaceID InterfaceID, mDNSIPPort srcPort, const mDNSAddr *dst, mDNSIPPort dstPort)
+       mDNSInterfaceID InterfaceID, const mDNSAddr *dst, mDNSIPPort dstPort)
        {
-       int                     err;
+       int                     err = 0;
        struct sockaddr_storage to;
-       PosixNetworkInterface * thisIntf;
+       PosixNetworkInterface * thisIntf = (PosixNetworkInterface *)(InterfaceID);
+       int sendingsocket = -1;
 
        assert(m != NULL);
        assert(msg != NULL);
        assert(end != NULL);
        assert( (((char *) end) - ((char *) msg)) > 0 );
-       assert(InterfaceID != 0); // Can't send from zero source address
-       assert(srcPort.NotAnInteger != 0);     // Nor from a zero source port
-       assert(dstPort.NotAnInteger != 0);     // Nor from a zero source port
+       assert(dstPort.NotAnInteger != 0);
 
        if (dst->type == mDNSAddrType_IPv4)
                {
@@ -273,9 +322,10 @@ mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const DNSMessage *co
                sin->sin_family         = AF_INET;
                sin->sin_port           = dstPort.NotAnInteger;
                sin->sin_addr.s_addr    = dst->ip.v4.NotAnInteger;
+               sendingsocket           = thisIntf ? thisIntf->multicastSocket4 : m->p->unicastSocket4;
                }
 
-#ifdef mDNSIPv6Support
+#if HAVE_IPV6
        else if (dst->type == mDNSAddrType_IPv6)
                {
                struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&to;
@@ -284,23 +334,22 @@ mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const DNSMessage *co
                sin6->sin6_family         = AF_INET6;
                sin6->sin6_port           = dstPort.NotAnInteger;
                sin6->sin6_addr           = *(struct in6_addr*)&dst->ip.v6;
+               sendingsocket             = thisIntf ? thisIntf->multicastSocket6 : m->p->unicastSocket6;
                }
 #endif
 
-       err = 0;
-       thisIntf = (PosixNetworkInterface *)(InterfaceID);
-       if (dst->type == mDNSAddrType_IPv4)
-               err = sendto(thisIntf->multicastSocket, msg, (char*)end - (char*)msg, 0, (struct sockaddr *)&to, GET_SA_LEN(to));
+       if (sendingsocket >= 0)
+               err = sendto(sendingsocket, msg, (char*)end - (char*)msg, 0, (struct sockaddr *)&to, GET_SA_LEN(to));
 
-#ifdef mDNSIPv6Support
-       else if (dst->type == mDNSAddrType_IPv6)
-               err = sendto(thisIntf->multicastSocketv6, msg, (char*)end - (char*)msg, 0, (struct sockaddr *)&to, GET_SA_LEN(to));
-#endif
-
-       if (err > 0) err = 0;
+       if      (err > 0) err = 0;
        else if (err < 0)
-               verbosedebugf("mDNSPlatformSendUDP got error %d (%s) sending packet to %#a on interface %#a/%s/%d",
-                                         errno, strerror(errno), dst, &thisIntf->coreIntf.ip, thisIntf->intfName, thisIntf->index);
+               {
+               if (thisIntf)
+                       verbosedebugf("mDNSPlatformSendUDP got error %d (%s) sending packet to %#a on interface %#a/%s/%d",
+                                                 errno, strerror(errno), dst, &thisIntf->coreIntf.ip, thisIntf->intfName, thisIntf->index);
+               else
+                       verbosedebugf("mDNSPlatformSendUDP got error %d (%s) sending packet to %#a", errno, strerror(errno), dst);
+               }
 
        return PosixErrorToStatus(err);
        }
@@ -316,15 +365,16 @@ static void SocketDataReady(mDNS *const m, PosixNetworkInterface *intf, int skt)
        struct sockaddr_storage from;
        socklen_t               fromLen;
        int                     flags;
+       mDNSu8                                  ttl;
        mDNSBool                reject;
+       const mDNSInterfaceID InterfaceID = intf ? intf->coreIntf.InterfaceID : NULL;
 
        assert(m    != NULL);
-       assert(intf != NULL);
        assert(skt  >= 0);
 
        fromLen = sizeof(from);
        flags   = 0;
-       packetLen = recvfrom_flags(skt, &packet, sizeof(packet), &flags, (struct sockaddr *) &from, &fromLen, &packetInfo);
+       packetLen = recvfrom_flags(skt, &packet, sizeof(packet), &flags, (struct sockaddr *) &from, &fromLen, &packetInfo, &ttl);
 
        if (packetLen >= 0)
                {
@@ -349,7 +399,7 @@ static void SocketDataReady(mDNS *const m, PosixNetworkInterface *intf, int skt)
                #if HAVE_BROKEN_RECVDSTADDR || (!defined(IP_PKTINFO) && !defined(IP_RECVDSTADDR))
                        if ( (destAddr.NotAnInteger == 0) && (flags & MSG_MCAST) )
                                {
-                               destAddr.type == senderAddr.type;
+                               destAddr.type = senderAddr.type;
                                if      (senderAddr.type == mDNSAddrType_IPv4) destAddr.ip.v4 = AllDNSLinkGroup;
                                else if (senderAddr.type == mDNSAddrType_IPv6) destAddr.ip.v6 = AllDNSLinkGroupv6;
                                }
@@ -364,31 +414,34 @@ static void SocketDataReady(mDNS *const m, PosixNetworkInterface *intf, int skt)
                // different capabilities of our target platforms.
 
                reject = mDNSfalse;
-               if      ( packetInfo.ipi_ifname[0] != 0 ) reject = (strcmp(packetInfo.ipi_ifname, intf->intfName) != 0);
-               else if ( packetInfo.ipi_ifindex != -1 )  reject = (packetInfo.ipi_ifindex != intf->index);
-
-               if (reject)
+               if (intf)
                        {
-                       verbosedebugf("SocketDataReady ignored a packet from %#a to %#a on interface %s/%d expecting %#a/%s/%d",
-                               &senderAddr, &destAddr, packetInfo.ipi_ifname, packetInfo.ipi_ifindex,
-                               &intf->coreIntf.ip, intf->intfName, intf->index);
-                       packetLen = -1;
-                       num_pkts_rejected++;
-                       if (num_pkts_rejected > (num_pkts_accepted + 1) * (num_registered_interfaces + 1) * 2)
+                       if      ( packetInfo.ipi_ifname[0] != 0 ) reject = (strcmp(packetInfo.ipi_ifname, intf->intfName) != 0);
+                       else if ( packetInfo.ipi_ifindex != -1 )  reject = (packetInfo.ipi_ifindex != intf->index);
+       
+                       if (reject)
+                               {
+                               verbosedebugf("SocketDataReady ignored a packet from %#a to %#a on interface %s/%d expecting %#a/%s/%d",
+                                       &senderAddr, &destAddr, packetInfo.ipi_ifname, packetInfo.ipi_ifindex,
+                                       &intf->coreIntf.ip, intf->intfName, intf->index);
+                               packetLen = -1;
+                               num_pkts_rejected++;
+                               if (num_pkts_rejected > (num_pkts_accepted + 1) * (num_registered_interfaces + 1) * 2)
+                                       {
+                                       fprintf(stderr,
+                                               "*** WARNING: Received %d packets; Accepted %d packets; Rejected %d packets because of interface mismatch\n",
+                                               num_pkts_accepted + num_pkts_rejected, num_pkts_accepted, num_pkts_rejected);
+                                       num_pkts_accepted = 0;
+                                       num_pkts_rejected = 0;
+                                       }
+                               }
+                       else
                                {
-                               fprintf(stderr,
-                                       "*** WARNING: Received %d packets; Accepted %d packets; Rejected %d packets because of interface mismatch\n",
-                                       num_pkts_accepted + num_pkts_rejected, num_pkts_accepted, num_pkts_rejected);
-                               num_pkts_accepted = 0;
-                               num_pkts_rejected = 0;
+                               verbosedebugf("SocketDataReady got a packet from %#a to %#a on interface %#a/%s/%d",
+                                       &senderAddr, &destAddr, &intf->coreIntf.ip, intf->intfName, intf->index);
+                               num_pkts_accepted++;
                                }
                        }
-               else
-                       {
-                       verbosedebugf("SocketDataReady got a packet from %#a to %#a on interface %#a/%s/%d",
-                               &senderAddr, &destAddr, &intf->coreIntf.ip, intf->intfName, intf->index);
-                       num_pkts_accepted++;
-                       }
                }
 
        if (packetLen >= 0 && packetLen < (ssize_t)sizeof(DNSMessageHeader))
@@ -399,21 +452,64 @@ static void SocketDataReady(mDNS *const m, PosixNetworkInterface *intf, int skt)
 
        if (packetLen >= 0)
                mDNSCoreReceive(m, &packet, (mDNSu8 *)&packet + packetLen,
-                       &senderAddr, senderPort, &destAddr, MulticastDNSPort, intf->coreIntf.InterfaceID, 255);
+                       &senderAddr, senderPort, &destAddr, MulticastDNSPort, InterfaceID, ttl);
+       }
+
+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 int mDNSPlatformReadTCP(int sd, void *buf, int buflen)
+       {
+       (void)sd;                       // Unused
+       (void)buf;                      // Unused
+       (void)buflen;                   // Unused
+       return(0);
+       }
+
+mDNSexport int mDNSPlatformWriteTCP(int sd, const char *msg, int len)
+       {
+       (void)sd;                       // Unused
+       (void)msg;                      // Unused
+       (void)len;                      // Unused
+       return(0);
        }
 
 #if COMPILER_LIKES_PRAGMA_MARK
-#pragma mark ***** Init and Term
+#pragma mark ***** Get/Free Search Domain List
 #endif
 
-// On OS X this gets the text of the field labelled "Computer Name" in the Sharing Prefs Control Panel
-// Other platforms can either get the information from the appropriate place,
-// or they can alternatively just require all registering services to provide an explicit name
-mDNSlocal void GetUserSpecifiedFriendlyComputerName(domainlabel *const namelabel)
+mDNSexport DNameListElem *mDNSPlatformGetSearchDomainList(void)
        {
-       MakeDomainLabelFromLiteralString(namelabel, "Fill in Default Service Name Here");
+       static DNameListElem tmp;
+       static mDNSBool init = mDNSfalse;
+
+       if (!init)
+               {
+               MakeDomainNameFromDNSNameString(&tmp.name, "local.");
+               tmp.next = NULL;
+               init = mDNStrue;
+               }
+       return mDNS_CopyDNameList(&tmp);
        }
 
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark ***** Init and Term
+#endif
+
 // This gets the current hostname, truncating it at the first dot if necessary
 mDNSlocal void GetUserSpecifiedRFC1034ComputerName(domainlabel *const namelabel)
        {
@@ -423,6 +519,15 @@ mDNSlocal void GetUserSpecifiedRFC1034ComputerName(domainlabel *const namelabel)
        namelabel->c[0] = len;
        }
 
+// On OS X this gets the text of the field labelled "Computer Name" in the Sharing Prefs Control Panel
+// Other platforms can either get the information from the appropriate place,
+// or they can alternatively just require all registering services to provide an explicit name
+mDNSlocal void GetUserSpecifiedFriendlyComputerName(domainlabel *const namelabel)
+       {
+       // On Unix we have no better name than the host name, so we just use that.
+       GetUserSpecifiedRFC1034ComputerName( namelabel);
+       }
+
 // Searches the interface list looking for the named interface.
 // Returns a pointer to if it found, or NULL otherwise.
 static PosixNetworkInterface *SearchForInterfaceByName(mDNS *const m, const char *intfName)
@@ -439,14 +544,46 @@ static PosixNetworkInterface *SearchForInterfaceByName(mDNS *const m, const char
        return intf;
        }
 
+extern mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(const mDNS *const m, mDNSu32 index)
+       {
+       PosixNetworkInterface *intf;
+
+       assert(m != NULL);
+
+       if (index == (uint32_t)~0) return(mDNSInterface_LocalOnly);
+
+       intf = (PosixNetworkInterface*)(m->HostInterfaces);
+       while ( (intf != NULL) && (mDNSu32) intf->index != index) 
+               intf = (PosixNetworkInterface *)(intf->coreIntf.next);
+
+       return (mDNSInterfaceID) intf;
+       }
+       
+mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(const mDNS *const m, mDNSInterfaceID id)
+       {
+       PosixNetworkInterface *intf;
+
+       assert(m != NULL);
+
+       if (id == mDNSInterface_LocalOnly) return((mDNSu32)~0);
+
+       intf = (PosixNetworkInterface*)(m->HostInterfaces);
+       while ( (intf != NULL) && (mDNSInterfaceID) intf != id)
+               intf = (PosixNetworkInterface *)(intf->coreIntf.next);
+
+       return intf ? intf->index : 0;
+       }
+
 // Frees the specified PosixNetworkInterface structure. The underlying
 // interface must have already been deregistered with the mDNS core.
 static void FreePosixNetworkInterface(PosixNetworkInterface *intf)
        {
        assert(intf != NULL);
        if (intf->intfName != NULL)        free((void *)intf->intfName);
-       if (intf->multicastSocket   != -1) assert(close(intf->multicastSocket) == 0);
-       if (intf->multicastSocketv6 != -1) assert(close(intf->multicastSocketv6) == 0);
+       if (intf->multicastSocket4 != -1) assert(close(intf->multicastSocket4) == 0);
+#if HAVE_IPV6
+       if (intf->multicastSocket6 != -1) assert(close(intf->multicastSocket6) == 0);
+#endif
        free(intf);
        }
 
@@ -467,8 +604,9 @@ static void ClearInterfaceList(mDNS *const m)
        num_pkts_rejected = 0;
        }
 
-// Sets up a multicast send/receive socket for the specified
-// port on the interface specified by the IP addrelss intfAddr.
+// Sets up a send/receive socket.
+// 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
 static int SetupSocket(struct sockaddr *intfAddr, mDNSIPPort port, int interfaceIndex, int *sktPtr)
        {
        int err = 0;
@@ -476,22 +614,22 @@ static int SetupSocket(struct sockaddr *intfAddr, mDNSIPPort port, int interface
        static const int kIntTwoFiveFive = 255;
        static const unsigned char kByteTwoFiveFive = 255;
        
-       (void) interfaceIndex;  // Unused
+       (void) interfaceIndex;  // This parameter unused on plaforms that don't have IPv6
        assert(intfAddr != NULL);
        assert(sktPtr != NULL);
        assert(*sktPtr == -1);
 
        // Open the socket...
        if       (intfAddr->sa_family == AF_INET) *sktPtr = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
-#ifdef mDNSIPv6Support
+#if HAVE_IPV6
        else if (intfAddr->sa_family == AF_INET6) *sktPtr = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
 #endif
        else return EINVAL;
 
        if (*sktPtr < 0) { err = errno; perror("socket"); }
 
-       // ... with a shared UDP port
-       if (err == 0)
+       // ... with a shared UDP port, if it's for multicast receiving
+       if (err == 0 && port.NotAnInteger)
                {
                #if defined(SO_REUSEPORT)
                        err = setsockopt(*sktPtr, SOL_SOCKET, SO_REUSEPORT, &kOn, sizeof(kOn));
@@ -529,9 +667,16 @@ static int SetupSocket(struct sockaddr *intfAddr, mDNSIPPort port, int interface
                                #warning This platform has no way to get the destination interface information -- will only work for single-homed hosts
                        #endif
                        }
+       #if defined(IP_RECVTTL)                                                                 // Linux
+               if (err == 0)
+                       {
+                       err = setsockopt(*sktPtr, IPPROTO_IP, IP_RECVTTL, &kOn, sizeof(kOn));
+                       if (err < 0) { err = errno; perror("setsockopt - IP_RECVTTL"); }
+                       }
+       #endif
 
                // Add multicast group membership on this interface
-               if (err == 0)
+               if (err == 0 && port.NotAnInteger)
                        {
                        imr.imr_multiaddr.s_addr = AllDNSLinkGroup.NotAnInteger;
                        imr.imr_interface        = ((struct sockaddr_in*)intfAddr)->sin_addr;
@@ -540,7 +685,7 @@ static int SetupSocket(struct sockaddr *intfAddr, mDNSIPPort port, int interface
                        }
 
                // Specify outgoing interface too
-               if (err == 0)
+               if (err == 0 && port.NotAnInteger)
                        {
                        err = setsockopt(*sktPtr, IPPROTO_IP, IP_MULTICAST_IF, &((struct sockaddr_in*)intfAddr)->sin_addr, sizeof(struct in_addr));
                        if (err < 0) { err = errno; perror("setsockopt - IP_MULTICAST_IF"); }
@@ -574,23 +719,30 @@ static int SetupSocket(struct sockaddr *intfAddr, mDNSIPPort port, int interface
                        }
                } // endif (intfAddr->sa_family == AF_INET)
 
-#ifdef mDNSIPv6Support
+#if HAVE_IPV6
        else if (intfAddr->sa_family == AF_INET6)
                {
                struct ipv6_mreq imr6;
                struct sockaddr_in6 bindAddr6;
+       #if defined(IPV6_PKTINFO)
                if (err == 0)
                        {
-                       #if defined(IPV6_PKTINFO)
                                err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_PKTINFO, &kOn, sizeof(kOn));
                                if (err < 0) { err = errno; perror("setsockopt - IPV6_PKTINFO"); }
-                       #else
-                               #warning This platform has no way to get the destination interface information for IPv6 -- will only work for single-homed hosts
-                       #endif
                        }
+       #else
+               #warning This platform has no way to get the destination interface information for IPv6 -- will only work for single-homed hosts
+       #endif
+       #if defined(IPV6_HOPLIMIT)
+               if (err == 0)
+                       {
+                               err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_HOPLIMIT, &kOn, sizeof(kOn));
+                               if (err < 0) { err = errno; perror("setsockopt - IPV6_HOPLIMIT"); }
+                       }
+       #endif
 
                // Add multicast group membership on this interface
-               if (err == 0)
+               if (err == 0 && port.NotAnInteger)
                        {
                        imr6.ipv6mr_multiaddr       = *(const struct in6_addr*)&AllDNSLinkGroupv6;
                        imr6.ipv6mr_interface       = interfaceIndex;
@@ -604,7 +756,7 @@ static int SetupSocket(struct sockaddr *intfAddr, mDNSIPPort port, int interface
                        }
 
                // Specify outgoing interface too
-               if (err == 0)
+               if (err == 0 && port.NotAnInteger)
                        {
                        u_int   multicast_if = interfaceIndex;
                        err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_MULTICAST_IF, &multicast_if, sizeof(multicast_if));
@@ -683,7 +835,7 @@ static int SetupOneInterface(mDNS *const m, struct sockaddr *intfAddr, const cha
        assert(intfName != NULL);
 
        // Allocate the interface structure itself.
-       intf = malloc(sizeof(*intf));
+       intf = (PosixNetworkInterface*)malloc(sizeof(*intf));
        if (intf == NULL) { assert(0); err = ENOMEM; }
 
        // And make a copy of the intfName.
@@ -698,13 +850,15 @@ static int SetupOneInterface(mDNS *const m, struct sockaddr *intfAddr, const cha
                // Set up the fields required by the mDNS core.
                SockAddrTomDNSAddr(intfAddr, &intf->coreIntf.ip, NULL);
                intf->coreIntf.Advertise = m->AdvertiseLocalAddresses;
-               intf->coreIntf.TxAndRx   = mDNStrue;
+               intf->coreIntf.McastTxRx = mDNStrue;
 
                // Set up the extra fields in PosixNetworkInterface.
                assert(intf->intfName != NULL);         // intf->intfName already set up above
                intf->index                = if_nametoindex(intf->intfName);
-               intf->multicastSocket      = -1;
-               intf->multicastSocketv6    = -1;
+               intf->multicastSocket4     = -1;
+#if HAVE_IPV6
+               intf->multicastSocket6     = -1;
+#endif
                alias                      = SearchForInterfaceByName(m, intf->intfName);
                if (alias == NULL) alias   = intf;
                intf->coreIntf.InterfaceID = (mDNSInterfaceID)alias;
@@ -716,11 +870,11 @@ static int SetupOneInterface(mDNS *const m, struct sockaddr *intfAddr, const cha
        // Set up the multicast socket
        if (err == 0)
                {
-               if (alias->multicastSocket == -1 && intfAddr->sa_family == AF_INET)
-                       err = SetupSocket(intfAddr, MulticastDNSPort, intf->index, &alias->multicastSocket);
-#ifdef mDNSIPv6Support
-               else if (alias->multicastSocketv6 == -1 && intfAddr->sa_family == AF_INET6)
-                       err = SetupSocket(intfAddr, MulticastDNSPort, intf->index, &alias->multicastSocketv6);
+               if (alias->multicastSocket4 == -1 && intfAddr->sa_family == AF_INET)
+                       err = SetupSocket(intfAddr, MulticastDNSPort, intf->index, &alias->multicastSocket4);
+#if HAVE_IPV6
+               else if (alias->multicastSocket6 == -1 && intfAddr->sa_family == AF_INET6)
+                       err = SetupSocket(intfAddr, MulticastDNSPort, intf->index, &alias->multicastSocket6);
 #endif
                }
 
@@ -748,6 +902,7 @@ static int SetupOneInterface(mDNS *const m, struct sockaddr *intfAddr, const cha
        return err;
        }
 
+// Call get_ifi_info() to obtain a list of active interfaces and call SetupOneInterface() on each one.
 static int SetupInterfaceList(mDNS *const m)
        {
        mDNSBool        foundav4       = mDNSfalse;
@@ -760,7 +915,7 @@ static int SetupInterfaceList(mDNS *const m)
 
        if (intfList == NULL) err = ENOENT;
 
-#ifdef mDNSIPv6Support
+#if HAVE_IPV6
        if (err == 0)           /* Link the IPv6 list to the end of the IPv4 list */
                {
                struct ifi_info **p = &intfList;
@@ -775,7 +930,7 @@ static int SetupInterfaceList(mDNS *const m)
                while (i)
                        {
                        if (     ((i->ifi_addr->sa_family == AF_INET)
-#ifdef mDNSIPv6Support
+#if HAVE_IPV6
                                          || (i->ifi_addr->sa_family == AF_INET6)
 #endif
                                ) &&  (i->ifi_flags & IFF_UP) && !(i->ifi_flags & IFF_POINTOPOINT) )
@@ -809,12 +964,255 @@ static int SetupInterfaceList(mDNS *const m)
        return err;
        }
 
+#if USES_NETLINK
+
+// See <http://www.faqs.org/rfcs/rfc3549.html> for a description of NetLink
+
+// Open a socket that will receive interface change notifications
+mStatus                OpenIfNotifySocket( int *pFD)
+       {
+       mStatus                                 err = mStatus_NoError;
+       struct sockaddr_nl              snl;
+       int sock;
+       int ret;
+
+       sock = socket( AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+       if (sock < 0)
+               return errno;
+
+       // Configure read to be non-blocking because inbound msg size is not known in advance
+       (void) fcntl( sock, F_SETFL, O_NONBLOCK);
+
+       /* Subscribe the socket to Link & IP addr notifications. */
+       bzero( &snl, sizeof snl);
+       snl.nl_family = AF_NETLINK;
+       snl.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR;
+       ret = bind( sock, (struct sockaddr *) &snl, sizeof snl);
+       if ( 0 == ret)
+               *pFD = sock;
+       else
+               err = errno;
+
+       return err;
+       }
+
+#if MDNS_DEBUGMSGS
+static void            PrintNetLinkMsg( const struct nlmsghdr *pNLMsg)
+       {
+       const char *kNLMsgTypes[] = { "", "NLMSG_NOOP", "NLMSG_ERROR", "NLMSG_DONE", "NLMSG_OVERRUN" };
+       const char *kNLRtMsgTypes[] = { "RTM_NEWLINK", "RTM_DELLINK", "RTM_GETLINK", "RTM_NEWADDR", "RTM_DELADDR", "RTM_GETADDR" };
+
+       printf( "nlmsghdr len=%d, type=%s, flags=0x%x\n", pNLMsg->nlmsg_len, 
+                       pNLMsg->nlmsg_type < RTM_BASE ? kNLMsgTypes[ pNLMsg->nlmsg_type] : kNLRtMsgTypes[ pNLMsg->nlmsg_type - RTM_BASE], 
+                       pNLMsg->nlmsg_flags);
+
+       if ( RTM_NEWLINK <= pNLMsg->nlmsg_type && pNLMsg->nlmsg_type <= RTM_GETLINK)
+               {
+               struct ifinfomsg        *pIfInfo = (struct ifinfomsg*) NLMSG_DATA( pNLMsg);
+               printf( "ifinfomsg family=%d, type=%d, index=%d, flags=0x%x, change=0x%x\n", pIfInfo->ifi_family, 
+                               pIfInfo->ifi_type, pIfInfo->ifi_index, pIfInfo->ifi_flags, pIfInfo->ifi_change);
+               
+               }
+       else if ( RTM_NEWADDR <= pNLMsg->nlmsg_type && pNLMsg->nlmsg_type <= RTM_GETADDR)
+               {
+               struct ifaddrmsg        *pIfAddr = (struct ifaddrmsg*) NLMSG_DATA( pNLMsg);
+               printf( "ifaddrmsg family=%d, index=%d, flags=0x%x\n", pIfAddr->ifa_family, 
+                               pIfAddr->ifa_index, pIfAddr->ifa_flags);
+               }
+       printf( "\n");
+       }
+#endif
+
+static uint32_t                ProcessRoutingNotification( int sd)
+// Read through the messages on sd and if any indicate that any interface records should
+// be torn down and rebuilt, return affected indices as a bitmask. Otherwise return 0.
+       {
+       ssize_t                                 readCount;
+       char                                    buff[ 4096];    
+       struct nlmsghdr                 *pNLMsg = (struct nlmsghdr*) buff;
+       uint32_t                                result = 0;
+       
+       // The structure here is more complex than it really ought to be because,
+       // unfortunately, there's no good way to size a buffer in advance large
+       // enough to hold all pending data and so avoid message fragmentation.
+       // (Note that FIONREAD is not supported on AF_NETLINK.)
+
+       readCount = read( sd, buff, sizeof buff);
+       while ( 1)
+               {
+               // Make sure we've got an entire nlmsghdr in the buffer, and payload, too.
+               // If not, discard already-processed messages in buffer and read more data.
+               if ( ( (char*) &pNLMsg[1] > ( buff + readCount)) ||     // i.e. *pNLMsg extends off end of buffer 
+                        ( (char*) pNLMsg + pNLMsg->nlmsg_len > ( buff + readCount)))
+                       {
+                       if ( buff < (char*) pNLMsg)             // we have space to shuffle
+                               {
+                               // discard processed data
+                               readCount -= ( (char*) pNLMsg - buff);
+                               memmove( buff, pNLMsg, readCount);
+                               pNLMsg = (struct nlmsghdr*) buff;
+
+                               // read more data
+                               readCount += read( sd, buff + readCount, sizeof buff - readCount);
+                               continue;                                       // spin around and revalidate with new readCount
+                               }
+                       else
+                               break;  // Otherwise message does not fit in buffer
+                       }
+
+#if MDNS_DEBUGMSGS
+               PrintNetLinkMsg( pNLMsg);
+#endif
+
+               // Process the NetLink message
+               if ( pNLMsg->nlmsg_type == RTM_GETLINK || pNLMsg->nlmsg_type == RTM_NEWLINK)
+                       result |= 1 << ((struct ifinfomsg*) NLMSG_DATA( pNLMsg))->ifi_index;
+               else if ( pNLMsg->nlmsg_type == RTM_DELADDR || pNLMsg->nlmsg_type == RTM_NEWADDR)
+                       result |= 1 << ((struct ifaddrmsg*) NLMSG_DATA( pNLMsg))->ifa_index;
+
+               // Advance pNLMsg to the next message in the buffer
+               if ( ( pNLMsg->nlmsg_flags & NLM_F_MULTI) != 0 && pNLMsg->nlmsg_type != NLMSG_DONE)
+                       {
+                       ssize_t len = readCount - ( (char*)pNLMsg - buff);
+                       pNLMsg = NLMSG_NEXT( pNLMsg, len);
+                       }
+               else
+                       break;  // all done!
+               }
+
+       return result;
+       }
+
+#else // USES_NETLINK
+
+// Open a socket that will receive interface change notifications
+mStatus                OpenIfNotifySocket( int *pFD)
+       {
+       *pFD = socket( AF_ROUTE, SOCK_RAW, 0);
+
+       if ( *pFD < 0)
+               return mStatus_UnknownErr;
+
+       // Configure read to be non-blocking because inbound msg size is not known in advance
+       (void) fcntl( *pFD, F_SETFL, O_NONBLOCK);
+
+       return mStatus_NoError;
+       }
+
+#if MDNS_DEBUGMSGS
+static void            PrintRoutingSocketMsg( const struct ifa_msghdr *pRSMsg)
+       {
+       const char *kRSMsgTypes[] = { "", "RTM_ADD", "RTM_DELETE", "RTM_CHANGE", "RTM_GET", "RTM_LOSING",
+                                       "RTM_REDIRECT", "RTM_MISS", "RTM_LOCK", "RTM_OLDADD", "RTM_OLDDEL", "RTM_RESOLVE", 
+                                       "RTM_NEWADDR", "RTM_DELADDR", "RTM_IFINFO", "RTM_NEWMADDR", "RTM_DELMADDR" };
+
+       int             index = pRSMsg->ifam_type == RTM_IFINFO ? ((struct if_msghdr*) pRSMsg)->ifm_index : pRSMsg->ifam_index;
+
+       printf( "ifa_msghdr len=%d, type=%s, index=%d\n", pRSMsg->ifam_msglen, kRSMsgTypes[ pRSMsg->ifam_type], index);
+       }
+#endif
+
+static uint32_t                ProcessRoutingNotification( int sd)
+// Read through the messages on sd and if any indicate that any interface records should
+// be torn down and rebuilt, return affected indices as a bitmask. Otherwise return 0.
+       {
+       ssize_t                                 readCount;
+       char                                    buff[ 4096];    
+       struct ifa_msghdr               *pRSMsg = (struct ifa_msghdr*) buff;
+       uint32_t                                result = 0;
+
+       readCount = read( sd, buff, sizeof buff);
+       if ( readCount < (ssize_t) sizeof( struct ifa_msghdr))
+               return mStatus_UnsupportedErr;          // cannot decipher message
+
+#if MDNS_DEBUGMSGS
+       PrintRoutingSocketMsg( pRSMsg);
+#endif
+
+       // Process the message
+       if ( pRSMsg->ifam_type == RTM_NEWADDR || pRSMsg->ifam_type == RTM_DELADDR ||
+                pRSMsg->ifam_type == RTM_IFINFO)
+               {
+               if ( pRSMsg->ifam_type == RTM_IFINFO)
+                       result |= 1 << ((struct if_msghdr*) pRSMsg)->ifm_index;
+               else
+                       result |= 1 << pRSMsg->ifam_index;
+               }
+
+       return result;
+       }
+
+#endif // USES_NETLINK
+
+// Called when data appears on interface change notification socket
+static void InterfaceChangeCallback( void *context)
+       {
+       IfChangeRec             *pChgRec = (IfChangeRec*) context;
+       fd_set                  readFDs;
+       uint32_t                changedInterfaces = 0;
+       struct timeval  zeroTimeout = { 0, 0 };
+       
+       FD_ZERO( &readFDs);
+       FD_SET( pChgRec->NotifySD, &readFDs);
+       
+       do
+       {
+               changedInterfaces |= ProcessRoutingNotification( pChgRec->NotifySD);
+       }
+       while ( 0 < select( pChgRec->NotifySD + 1, &readFDs, (fd_set*) NULL, (fd_set*) NULL, &zeroTimeout));
+
+       // Currently we rebuild the entire interface list whenever any interface change is
+       // detected. If this ever proves to be a performance issue in a multi-homed 
+       // configuration, more care should be paid to changedInterfaces.
+       if ( changedInterfaces)
+               mDNSPlatformPosixRefreshInterfaceList( pChgRec->mDNS);
+       }
+
+// Register with either a Routing Socket or RtNetLink to listen for interface changes.
+static mStatus WatchForInterfaceChange(mDNS *const m)
+       {
+       mStatus         err;
+       IfChangeRec     *pChgRec;
+
+       pChgRec = (IfChangeRec*) mDNSPlatformMemAllocate( sizeof *pChgRec);
+       if ( pChgRec == NULL)
+               return mStatus_NoMemoryErr;
+
+       pChgRec->mDNS = m;
+       err = OpenIfNotifySocket( &pChgRec->NotifySD);
+       if ( err == 0)
+               err = mDNSPosixAddFDToEventLoop( pChgRec->NotifySD, InterfaceChangeCallback, pChgRec);
+
+       return err;
+       }
+
+// Test to see if we're the first client running on UDP port 5353, by trying to bind to 5353 without using SO_REUSEPORT.
+// If we fail, someone else got here first. That's not a big problem; we can share the port for multicast responses --
+// we just need to be aware that we shouldn't expect to successfully receive unicast UDP responses.
+mDNSlocal mDNSBool mDNSPlatformInit_ReceiveUnicast(void)
+       {
+       int err;
+       int s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+       struct sockaddr_in s5353;
+       s5353.sin_family      = AF_INET;
+       s5353.sin_port        = MulticastDNSPort.NotAnInteger;
+       s5353.sin_addr.s_addr = 0;
+       err = bind(s, (struct sockaddr *)&s5353, sizeof(s5353));
+       close(s);
+       if (err) debugf("No unicast UDP responses");
+       else     debugf("Unicast UDP responses okay");
+       return(err == 0);
+       }
+
 // mDNS core calls this routine to initialise the platform-specific data.
 mDNSexport mStatus mDNSPlatformInit(mDNS *const m)
        {
-       int err;
+       int err = 0;
+       struct sockaddr sa;
        assert(m != NULL);
 
+       if (mDNSPlatformInit_ReceiveUnicast()) m->CanReceiveUnicast = mDNStrue;
+
        // Tell mDNS core the names of this machine.
 
        // Set up the nice label
@@ -829,13 +1227,33 @@ mDNSexport mStatus mDNSPlatformInit(mDNS *const m)
 
        mDNS_GenerateFQDN(m);
 
+       sa.sa_family = AF_INET;
+       m->p->unicastSocket4 = -1;
+       if (err == mStatus_NoError) err = SetupSocket(&sa, zeroIPPort, 0, &m->p->unicastSocket4);
+#if HAVE_IPV6
+       sa.sa_family = AF_INET6;
+       m->p->unicastSocket6 = -1;
+       if (err == mStatus_NoError) err = SetupSocket(&sa, zeroIPPort, 0, &m->p->unicastSocket6);
+#endif
+
        // Tell mDNS core about the network interfaces on this machine.
-       err = SetupInterfaceList(m);
+       if (err == mStatus_NoError) err = SetupInterfaceList(m);
+
+       if (err == mStatus_NoError)
+               {
+               err = WatchForInterfaceChange(m);
+               // Failure to observe interface changes is non-fatal.
+               if ( err != mStatus_NoError)
+                       {
+                       fprintf(stderr, "mDNS(%d) WARNING: Unable to detect interface changes (%d).\n", getpid(), err);
+                       err = mStatus_NoError;
+                       }
+               }
 
        // We don't do asynchronous initialization on the Posix platform, so by the time
        // we get here the setup will already have succeeded or failed.  If it succeeded,
        // we should just call mDNSCoreInitComplete() immediately.
-       if (err == 0)
+       if (err == mStatus_NoError)
                mDNSCoreInitComplete(m, mStatus_NoError);
 
        return PosixErrorToStatus(err);
@@ -847,6 +1265,10 @@ mDNSexport void mDNSPlatformClose(mDNS *const m)
        {
        assert(m != NULL);
        ClearInterfaceList(m);
+       if (m->p->unicastSocket4 != -1) assert(close(m->p->unicastSocket4) == 0);
+#if HAVE_IPV6
+       if (m->p->unicastSocket6 != -1) assert(close(m->p->unicastSocket6) == 0);
+#endif
        }
 
 extern mStatus mDNSPlatformPosixRefreshInterfaceList(mDNS *const m)
@@ -944,7 +1366,18 @@ mDNSexport mDNSs32  mDNSPlatformTimeNow()
        return( (tv.tv_sec << 10) | (tv.tv_usec * 16 / 15625) );
        }
 
-mDNSexport void mDNSPosixGetFDSet(mDNS *const m, int *nfds, fd_set *readfds, struct timeval *timeout)
+mDNSexport mDNSs32 mDNSPlatformUTC(void)
+       {
+       return time(NULL);
+       }
+
+mDNSlocal void mDNSPosixAddToFDSet(int *nfds, fd_set *readfds, int s)
+       {
+       if (*nfds < s + 1) *nfds = s + 1;
+       FD_SET(s, readfds);
+       }
+
+mDNSexport void mDNSPosixGetFDSet(mDNS *m, int *nfds, fd_set *readfds, struct timeval *timeout)
        {
        mDNSs32 ticks;
        struct timeval interval;
@@ -954,20 +1387,16 @@ mDNSexport void mDNSPosixGetFDSet(mDNS *const m, int *nfds, fd_set *readfds, str
 
        // 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 HAVE_IPV6
+       if (m->p->unicastSocket6 != -1) mDNSPosixAddToFDSet(nfds, readfds, m->p->unicastSocket6);
+#endif
        while (info)
                {
-               if (info->multicastSocket != -1)
-                       {
-                       if (*nfds < info->multicastSocket + 1)
-                               *nfds = info->multicastSocket + 1;
-                       FD_SET(info->multicastSocket, readfds);
-                       }
-               if (info->multicastSocketv6 != -1)
-                       {
-                       if (*nfds < info->multicastSocketv6 + 1)
-                               *nfds = info->multicastSocketv6 + 1;
-                       FD_SET(info->multicastSocketv6, readfds);
-                       }
+               if (info->multicastSocket4 != -1) mDNSPosixAddToFDSet(nfds, readfds, info->multicastSocket4);
+#if HAVE_IPV6
+               if (info->multicastSocket6 != -1) mDNSPosixAddToFDSet(nfds, readfds, info->multicastSocket6);
+#endif
                info = (PosixNetworkInterface *)(info->coreIntf.next);
                }
 
@@ -989,18 +1418,173 @@ mDNSexport void mDNSPosixProcessFDSet(mDNS *const m, fd_set *readfds)
        assert(m       != NULL);
        assert(readfds != NULL);
        info = (PosixNetworkInterface *)(m->HostInterfaces);
+
+       if (m->p->unicastSocket4 != -1 && FD_ISSET(m->p->unicastSocket4, readfds))
+               {
+               FD_CLR(m->p->unicastSocket4, readfds);
+               SocketDataReady(m, NULL, m->p->unicastSocket4);
+               }
+#if HAVE_IPV6
+       if (m->p->unicastSocket6 != -1 && FD_ISSET(m->p->unicastSocket6, readfds))
+               {
+               FD_CLR(m->p->unicastSocket6, readfds);
+               SocketDataReady(m, NULL, m->p->unicastSocket6);
+               }
+#endif
+
        while (info)
                {
-               if (info->multicastSocket != -1 && FD_ISSET(info->multicastSocket, readfds))
+               if (info->multicastSocket4 != -1 && FD_ISSET(info->multicastSocket4, readfds))
                        {
-                       FD_CLR(info->multicastSocket, readfds);
-                       SocketDataReady(m, info, info->multicastSocket);
+                       FD_CLR(info->multicastSocket4, readfds);
+                       SocketDataReady(m, info, info->multicastSocket4);
                        }
-               if (info->multicastSocketv6 != -1 && FD_ISSET(info->multicastSocketv6, readfds))
+#if HAVE_IPV6
+               if (info->multicastSocket6 != -1 && FD_ISSET(info->multicastSocket6, readfds))
                        {
-                       FD_CLR(info->multicastSocketv6, readfds);
-                       SocketDataReady(m, info, info->multicastSocketv6);
+                       FD_CLR(info->multicastSocket6, readfds);
+                       SocketDataReady(m, info, info->multicastSocket6);
                        }
+#endif
                info = (PosixNetworkInterface *)(info->coreIntf.next);
                }
        }
+
+// update gMaxFD
+static void    DetermineMaxEventFD( void )
+       {
+       PosixEventSource        *iSource;
+       
+       gMaxFD = 0;
+       for ( iSource=(PosixEventSource*)gEventSources.Head; iSource; iSource = iSource->Next)
+               if ( gMaxFD < iSource->fd)
+                       gMaxFD = iSource->fd;
+       }
+
+// Add a file descriptor to the set that mDNSPosixRunEventLoopOnce() listens to.
+mStatus mDNSPosixAddFDToEventLoop( int fd, mDNSPosixEventCallback callback, void *context)
+       {
+       PosixEventSource        *newSource;
+       
+       if ( gEventSources.LinkOffset == 0)
+               InitLinkedList( &gEventSources, offsetof( PosixEventSource, Next));
+
+       if ( fd >= (int) FD_SETSIZE || fd < 0)
+               return mStatus_UnsupportedErr;
+       if ( callback == NULL)
+               return mStatus_BadParamErr;
+
+       newSource = (PosixEventSource*) malloc( sizeof *newSource);
+       if ( NULL == newSource)
+               return mStatus_NoMemoryErr;
+
+       newSource->Callback = callback;
+       newSource->Context = context;
+       newSource->fd = fd;
+
+       AddToTail( &gEventSources, newSource);
+       FD_SET( fd, &gEventFDs);
+
+       DetermineMaxEventFD();
+
+       return mStatus_NoError;
+       }
+
+// Remove a file descriptor from the set that mDNSPosixRunEventLoopOnce() listens to.
+mStatus mDNSPosixRemoveFDFromEventLoop( int fd)
+       {
+       PosixEventSource        *iSource;
+       
+       for ( iSource=(PosixEventSource*)gEventSources.Head; iSource; iSource = iSource->Next)
+               {
+               if ( fd == iSource->fd)
+                       {
+                       FD_CLR( fd, &gEventFDs);
+                       RemoveFromList( &gEventSources, iSource);
+                       free( iSource);
+                       DetermineMaxEventFD();
+                       return mStatus_NoError;
+                       }
+               }
+       return mStatus_NoSuchNameErr;
+       }
+
+// Simply note the received signal in gEventSignals.
+static void    NoteSignal( int signum)
+       {
+       sigaddset( &gEventSignals, signum);
+       }
+
+// Tell the event package to listen for signal and report it in mDNSPosixRunEventLoopOnce().
+mStatus mDNSPosixListenForSignalInEventLoop( int signum)
+       {
+       struct sigaction        action;
+       mStatus                         err;
+
+       bzero( &action, sizeof action);         // more portable than member-wise assignment
+       action.sa_handler = NoteSignal;
+       err = sigaction( signum, &action, (struct sigaction*) NULL);
+       
+       sigaddset( &gEventSignalSet, signum);
+
+       return err;
+       }
+
+// Tell the event package to stop listening for signal in mDNSPosixRunEventLoopOnce().
+mStatus mDNSPosixIgnoreSignalInEventLoop( int signum)
+       {
+       struct sigaction        action;
+       mStatus                         err;
+
+       bzero( &action, sizeof action);         // more portable than member-wise assignment
+       action.sa_handler = SIG_DFL;
+       err = sigaction( signum, &action, (struct sigaction*) NULL);
+       
+       sigdelset( &gEventSignalSet, signum);
+
+       return err;
+       }
+
+// Do a single pass through the attendent event sources and dispatch any found to their callbacks.
+// Return as soon as internal timeout expires, or a signal we're listening for is received.
+mStatus mDNSPosixRunEventLoopOnce( mDNS *m, const struct timeval *pTimeout, 
+                                                                       sigset_t *pSignalsReceived, mDNSBool *pDataDispatched)
+       {
+       fd_set                  listenFDs = gEventFDs;
+       int                             fdMax = 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;
+
+       numReady = select( fdMax + 1, &listenFDs, (fd_set*) NULL, (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->Context);
+                               break;  // in case callback removed elements from gEventSources
+                               }
+                       }
+               *pDataDispatched = mDNStrue;
+               }
+       else
+               *pDataDispatched = mDNSfalse;
+
+       (void) sigprocmask( SIG_BLOCK, &gEventSignalSet, (sigset_t*) NULL);
+       *pSignalsReceived = gEventSignals;
+       sigemptyset( &gEventSignals);
+       (void) sigprocmask( SIG_UNBLOCK, &gEventSignalSet, (sigset_t*) NULL);
+
+       return mStatus_NoError;
+       }
index a2545683ad6fc4d51863af16f822797cd6ae317c..d6ffbd6facc8a6fda06e05ea284976bc1e4f724f 100755 (executable)
@@ -3,6 +3,8 @@
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
     Change History (most recent first):
 
 $Log: mDNSPosix.h,v $
+Revision 1.15  2004/02/06 01:19:51  cheshire
+Conditionally exclude IPv6 code unless HAVE_IPV6 is set
+
+Revision 1.14  2004/01/28 21:12:15  cheshire
+Reconcile mDNSIPv6Support & HAVE_IPV6 into a single flag (HAVE_IPV6)
+
+Revision 1.13  2004/01/24 05:12:03  cheshire
+<rdar://problem/3534352>: Need separate socket for issuing unicast queries
+
+Revision 1.12  2004/01/23 21:37:08  cheshire
+For consistency, rename multicastSocket to multicastSocket4, and multicastSocketv6 to multicastSocket6
+
+Revision 1.11  2003/12/11 03:03:51  rpantos
+Clean up mDNSPosix so that it builds on OS X again.
+
+Revision 1.10  2003/12/08 20:47:02  rpantos
+Add support for mDNSResponder on Linux.
+
 Revision 1.9  2003/10/30 19:25:19  cheshire
 Fix warning on certain compilers
 
@@ -57,23 +77,42 @@ First checkin
 #ifndef __mDNSPlatformPosix_h
 #define __mDNSPlatformPosix_h
 
+#include <signal.h>
 #include <sys/time.h>
 
-#if HAVE_IPV6
-#define mDNSIPv6Support 1
-#endif
-
 #ifdef  __cplusplus
     extern "C" {
 #endif
 
+// PosixNetworkInterface is a record extension of the core NetworkInterfaceInfo
+// type that supports extra fields needed by the Posix platform.
+//
+// IMPORTANT: coreIntf must be the first field in the structure because
+// we cast between pointers to the two different types regularly.
+
+typedef struct PosixNetworkInterface PosixNetworkInterface;
+
+struct PosixNetworkInterface
+       {
+       NetworkInterfaceInfo    coreIntf;
+       const char *            intfName;
+       PosixNetworkInterface * aliasIntf;
+       int                     index;
+       int                     multicastSocket4;
+#if HAVE_IPV6
+       int                     multicastSocket6;
+#endif
+       };
+
 // This is a global because debugf_() needs to be able to check its value
 extern int gMDNSPlatformPosixVerboseLevel;
 
 struct mDNS_PlatformSupport_struct
        {
-    // No additional data required for Posix at this time
-       long dummy[1];  // Some compilers don't like empty structures
+       int unicastSocket4;
+#if HAVE_IPV6
+       int unicastSocket6;
+#endif
        };
 
 extern mStatus mDNSPlatformPosixRefreshInterfaceList(mDNS *const m);
@@ -85,9 +124,17 @@ extern mStatus mDNSPlatformPosixRefreshInterfaceList(mDNS *const m);
 // Set timeout->tv_sec to 0x3FFFFFFF 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 *const m, int *nfds, fd_set *readfds, struct timeval *timeout);
+extern void mDNSPosixGetFDSet(mDNS *m, int *nfds, fd_set *readfds, struct timeval *timeout);
 extern void mDNSPosixProcessFDSet(mDNS *const m, fd_set *readfds);
 
+typedef        void (*mDNSPosixEventCallback)( void *context);
+
+extern mStatus mDNSPosixAddFDToEventLoop( int fd, mDNSPosixEventCallback callback, void *context);
+extern mStatus mDNSPosixRemoveFDFromEventLoop( int fd);
+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 fa9bda0682509ab3d30f275583f6b074e7221f7e..8e60808c22e83a5134920bfdec4c17e2a2184fc9 100755 (executable)
@@ -3,6 +3,8 @@
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
     Change History (most recent first):
 
 $Log: mDNSUNP.c,v $
+Revision 1.16  2004/03/20 05:37:09  cheshire
+Fix contributed by Terry Lambert & Alfred Perlstein:
+Don't use uint8_t -- it requires stdint.h, which doesn't exist on FreeBSD 4.x
+
+Revision 1.15  2004/02/14 01:09:45  rpantos
+Just use HAVE_IPV6 rather than defined(HAVE_IPV6).
+
+Revision 1.14  2003/12/11 18:53:40  cheshire
+Fix compiler warning reported by Paul Guyot
+
+Revision 1.13  2003/12/08 20:47:02  rpantos
+Add support for mDNSResponder on Linux.
+
 Revision 1.12  2003/09/02 20:47:13  cheshire
 Fix signed/unsigned warning
 
@@ -105,7 +120,7 @@ struct ifi_info *get_ifi_info(int family, int doaliases)
     struct ifreq        *ifr, ifrcopy;
     struct sockaddr_in  *sinptr;
     
-#if defined(AF_INET6) && defined(HAVE_IPV6)
+#if defined(AF_INET6) && HAVE_IPV6
     struct sockaddr_in6 *sinptr6;
 #endif
 
@@ -121,7 +136,7 @@ struct ifi_info *get_ifi_info(int family, int doaliases)
     lastlen = 0;
     len = 100 * sizeof(struct ifreq);   /* initial buffer size guess */
     for ( ; ; ) {
-        buf = malloc(len);
+        buf = (char*)malloc(len);
         if (buf == NULL) {
             goto gotError;
         }
@@ -175,7 +190,7 @@ struct ifi_info *get_ifi_info(int family, int doaliases)
         if ((flags & IFF_UP) == 0)
             continue;   /* ignore if interface not up */
 
-        ifi = calloc(1, sizeof(struct ifi_info));
+        ifi = (struct ifi_info*)calloc(1, sizeof(struct ifi_info));
         if (ifi == NULL) {
             goto gotError;
         }
@@ -193,7 +208,7 @@ struct ifi_info *get_ifi_info(int family, int doaliases)
         case AF_INET:
             sinptr = (struct sockaddr_in *) &ifr->ifr_addr;
             if (ifi->ifi_addr == NULL) {
-                ifi->ifi_addr = calloc(1, sizeof(struct sockaddr_in));
+                ifi->ifi_addr = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
                 if (ifi->ifi_addr == NULL) {
                     goto gotError;
                 }
@@ -205,7 +220,7 @@ struct ifi_info *get_ifi_info(int family, int doaliases)
                         goto gotError;
                     }
                     sinptr = (struct sockaddr_in *) &ifrcopy.ifr_broadaddr;
-                    ifi->ifi_brdaddr = calloc(1, sizeof(struct sockaddr_in));
+                    ifi->ifi_brdaddr = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
                     if (ifi->ifi_brdaddr == NULL) {
                         goto gotError;
                     }
@@ -219,7 +234,7 @@ struct ifi_info *get_ifi_info(int family, int doaliases)
                         goto gotError;
                     }
                     sinptr = (struct sockaddr_in *) &ifrcopy.ifr_dstaddr;
-                    ifi->ifi_dstaddr = calloc(1, sizeof(struct sockaddr_in));
+                    ifi->ifi_dstaddr = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
                     if (ifi->ifi_dstaddr == NULL) {
                         goto gotError;
                     }
@@ -229,7 +244,7 @@ struct ifi_info *get_ifi_info(int family, int doaliases)
             }
             break;
 
-#if defined(AF_INET6) && defined(HAVE_IPV6)
+#if defined(AF_INET6) && HAVE_IPV6
         case AF_INET6:
             sinptr6 = (struct sockaddr_in6 *) &ifr->ifr_addr;
             if (ifi->ifi_addr == NULL) {
@@ -292,7 +307,7 @@ free_ifi_info(struct ifi_info *ifihead)
 
 ssize_t 
 recvfrom_flags(int fd, void *ptr, size_t nbytes, int *flagsp,
-               struct sockaddr *sa, socklen_t *salenptr, struct my_in_pktinfo *pktp)
+               struct sockaddr *sa, socklen_t *salenptr, struct my_in_pktinfo *pktp, u_char *ttl)
 {
     struct msghdr   msg;
     struct iovec    iov[1];
@@ -305,6 +320,8 @@ recvfrom_flags(int fd, void *ptr, size_t nbytes, int *flagsp,
       char              control[1024];
     } control_un;
 
+       *ttl = 255;                     // If kernel fails to provide TTL data then assume the TTL was 255 as it should be
+
     msg.msg_control = control_un.control;
     msg.msg_controllen = sizeof(control_un.control);
     msg.msg_flags = 0;
@@ -312,9 +329,9 @@ recvfrom_flags(int fd, void *ptr, size_t nbytes, int *flagsp,
     memset(&msg, 0, sizeof(msg));   /* make certain msg_accrightslen = 0 */
 #endif /* CMSG_FIRSTHDR */
 
-    msg.msg_name = (void *) sa;
+    msg.msg_name = (char *) sa;
     msg.msg_namelen = *salenptr;
-    iov[0].iov_base = ptr;
+    iov[0].iov_base = (char *)ptr;
     iov[0].iov_len = nbytes;
     msg.msg_iov = iov;
     msg.msg_iovlen = 1;
@@ -401,7 +418,20 @@ struct in_pktinfo
         }
 #endif
 
-#if defined(IPV6_PKTINFO) && defined(HAVE_IPV6)
+#ifdef  IP_RECVTTL
+        if (cmptr->cmsg_level == IPPROTO_IP &&
+            cmptr->cmsg_type == IP_RECVTTL) {
+                       *ttl = *(u_char*)CMSG_DATA(cmptr);
+            continue;
+        }
+        else if (cmptr->cmsg_level == IPPROTO_IP &&
+            cmptr->cmsg_type == IP_TTL) {              // some implementations seem to send IP_TTL instead of IP_RECVTTL
+                       *ttl = *(int*)CMSG_DATA(cmptr);
+            continue;
+        }
+#endif
+
+#if defined(IPV6_PKTINFO) && HAVE_IPV6
         if (cmptr->cmsg_level == IPPROTO_IPV6 && 
             cmptr->cmsg_type == IPV6_PKTINFO) {
             struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&pktp->ipi_addr;
@@ -417,6 +447,14 @@ struct in_pktinfo
             continue;
         }
 #endif
+
+#if defined(IPV6_HOPLIMIT) && HAVE_IPV6
+        if (cmptr->cmsg_level == IPPROTO_IPV6 && 
+            cmptr->cmsg_type == IPV6_HOPLIMIT) {
+                       *ttl = *(int*)CMSG_DATA(cmptr);
+            continue;
+        }
+#endif
         assert(0);  // unknown ancillary data
     }
     return(n);
index 21d13f1966fa28b7f51d26463ee3ce92e86c9bb2..0d78baa5f6f1a7d9d8f4a7c0aacea068a4063dd7 100755 (executable)
@@ -3,6 +3,8 @@
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
     Change History (most recent first):
 
 $Log: mDNSUNP.h,v $
+Revision 1.13  2004/03/20 05:37:09  cheshire
+Fix contributed by Terry Lambert & Alfred Perlstein:
+Don't use uint8_t -- it requires stdint.h, which doesn't exist on FreeBSD 4.x
+
+Revision 1.12  2004/01/28 21:12:15  cheshire
+Reconcile mDNSIPv6Support & HAVE_IPV6 into a single flag (HAVE_IPV6)
+
+Revision 1.11  2003/12/13 05:43:09  bradley
+Fixed non-sa_len and non-IPv6 version of GET_SA_LEN macro to cast as sockaddr to access
+sa_family so it works with any sockaddr-compatible address structure (e.g. sockaddr_storage).
+
+Revision 1.10  2003/12/11 03:03:51  rpantos
+Clean up mDNSPosix so that it builds on OS X again.
+
+Revision 1.9  2003/12/08 20:47:02  rpantos
+Add support for mDNSResponder on Linux.
+
 Revision 1.8  2003/08/12 19:56:26  cheshire
 Update to APSL 2.0
 
@@ -74,11 +93,11 @@ First checkin
 #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   )
-#elif mDNSIPv6Support
+#elif HAVE_IPV6
 #define GET_SA_LEN(X) (((struct sockaddr*)&(X))->sa_family == AF_INET  ? sizeof(struct sockaddr_in) : \
                        ((struct sockaddr*)&(X))->sa_family == AF_INET6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr))
 #else
-#define GET_SA_LEN(X) ((X).sa_family == AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr))
+#define GET_SA_LEN(X) (((struct sockaddr*)&(X))->sa_family == AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr))
 #endif
 
 #define IFI_NAME    16          /* same as IFNAMSIZ in <net/if.h> */
@@ -92,8 +111,14 @@ struct my_in_pktinfo {
     char                    ipi_ifname[IFI_NAME];   /* received interface name  */
 };
 
+/* From the text (Stevens, section 20.2): */
+/* 'As an example of recvmsg we will write a function named recvfrom_flags that */
+/* is similar to recvfrom but also returns: */
+/*     1. the returned msg_flags value, */
+/*     2. the destination addres of the received datagram (from the IP_RECVDSTADDR socket option, and */
+/*     3. the index of the interface on which the datagram was received (the IP_RECVIF socket option).' */
 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);
+               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 */
@@ -110,7 +135,14 @@ struct ifi_info {
 
 #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  __cplusplus
diff --git a/mDNSPosix/mdnsd.sh b/mDNSPosix/mdnsd.sh
new file mode 100644 (file)
index 0000000..92be941
--- /dev/null
@@ -0,0 +1,89 @@
+#!/bin/sh
+#
+# Linux /etc/init.d script to start/stop the mdnsd daemon.
+# Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+#
+# $Log: mdnsd.sh,v $
+# Revision 1.4  2004/02/05 20:23:10  cheshire
+# Fix mdnsd.sh to work on *BSD distributions
+#
+#
+# Revision 1.3  2004/01/19 22:47:17  cheshire
+# Define killprocterm() to do "killproc $1 -TERM" for Linux
+#
+# Revision 1.2  2003/12/11 19:42:13  cheshire
+# Change name "mDNSResponderd" to "mdnsd" for consistency with standard Linux (Unix) naming conventions
+#
+# Revision 1.1  2003/12/08 20:47:02  rpantos
+# Add support for mDNSResponder on Linux.
+#
+# The following lines are used by the *BSD rcorder system to decide
+# the order it's going to run the rc.d scripts at startup time.
+# PROVIDE: mdnsd
+# REQUIRE: NETWORKING
+
+if [ -r /usr/sbin/mdnsd ]; then
+    DAEMON=/usr/sbin/mdnsd
+else
+    DAEMON=/usr/local/sbin/mdnsd
+fi
+
+test -r $DAEMON || exit 0
+
+# Some systems have start-stop-daemon, some don't. 
+if [ -r /sbin/start-stop-daemon ]; then
+       START=start-stop-daemon --start --quiet --exec
+       STOP=start-stop-daemon --stop -s TERM --quiet --oknodo --exec
+else
+       killmdnsd() {
+               kill -TERM `cat /var/run/mdnsd.pid`
+       }
+       START=
+       STOP=killmdnsd
+fi
+
+case "$1" in
+    start)
+       echo -n "Starting Apple Darwin Multicast DNS / DNS Service Discovery daemon:"
+       echo -n " mdnsd"
+        $START $DAEMON
+       echo "."
+       ;;
+    stop)
+        echo -n "Stopping Apple Darwin Multicast DNS / DNS Service Discovery daemon:"
+        echo -n " mdnsd" ; $STOP $DAEMON
+        echo "."
+       ;;
+    reload|restart|force-reload)
+               echo -n "Restarting Apple Darwin Multicast DNS / DNS Service Discovery daemon:"
+               $STOP $DAEMON
+               sleep 1
+               $START $DAEMON
+               echo -n " mdnsd"
+       ;;
+    *)
+       echo "Usage: /etc/init.d/mDNS {start|stop|reload|restart}"
+       exit 1
+       ;;
+esac
+
+exit 0
diff --git a/mDNSShared/GenLinkedList.c b/mDNSShared/GenLinkedList.c
new file mode 100755 (executable)
index 0000000..04a1581
--- /dev/null
@@ -0,0 +1,337 @@
+/*
+ * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+       File:           GenLinkedList.c
+
+       Contains:       implementation of generic linked lists.
+
+       Version:        1.0
+       Tabs:           4 spaces
+
+    Change History (most recent first):
+
+$Log: GenLinkedList.c,v $
+Revision 1.3  2004/04/22 21:14:42  cheshire
+Fix comment spelling mistake
+
+Revision 1.2  2004/02/05 07:41:08  cheshire
+Add Log header
+
+*/
+
+#include "GenLinkedList.h"
+
+
+// Return the link pointer contained within element e at offset o.
+#define                GETLINK( e, o)                  ( *(void**)((char*) (e) + (o)) )
+
+// Assign the link pointer l to element e at offset o.
+#define                ASSIGNLINK( e, l, o)    ( *((void**)((char*) (e) + (o))) = (l))
+
+
+//             GenLinkedList           /////////////////////////////////////////////////////////////
+
+void           InitLinkedList( GenLinkedList *pList, size_t linkOffset)
+/* Initialize the block of memory pointed to by pList as a linked list. */
+{
+       pList->Head = NULL;
+       pList->Tail = NULL;
+       pList->LinkOffset = linkOffset;
+}
+
+
+void           AddToTail( GenLinkedList *pList, void *elem)
+/* Add a linked list element to the tail of the list. */
+{
+       if ( pList->Tail) {
+               ASSIGNLINK( pList->Tail, elem, pList->LinkOffset);
+       } else
+               pList->Head = elem;
+       ASSIGNLINK( elem, NULL, pList->LinkOffset);
+
+       pList->Tail = elem;
+}
+
+
+void           AddToHead( GenLinkedList *pList, void *elem)
+/* Add a linked list element to the head of the list. */
+{
+       ASSIGNLINK( elem, pList->Head, pList->LinkOffset);
+       if ( pList->Tail == NULL) 
+               pList->Tail = elem;
+
+       pList->Head = elem;
+}
+
+
+int            RemoveFromList( GenLinkedList *pList, void *elem)
+/* Remove a linked list element from the list. Return 0 if it was not found. */
+/* If the element is removed, its link will be set to NULL. */
+{
+void   *iElem, *lastElem;
+
+       for ( iElem = pList->Head, lastElem = NULL; iElem; iElem = GETLINK( iElem, pList->LinkOffset)) {
+               if ( iElem == elem) {
+                       if ( lastElem) {                // somewhere past the head
+                               ASSIGNLINK( lastElem, GETLINK( elem, pList->LinkOffset), pList->LinkOffset);
+                       } else {                                // at the head
+                               pList->Head = GETLINK( elem, pList->LinkOffset);
+                       }
+                       if ( pList->Tail == elem)
+                               pList->Tail = lastElem ? lastElem : NULL;
+                       ASSIGNLINK( elem, NULL, pList->LinkOffset);                     // maybe catch a stale reference bug.
+                       return 1;
+               }
+               lastElem = iElem;
+       }
+       
+       return 0;
+}
+
+
+int                    ReplaceElem( GenLinkedList *pList, void *elemInList, void *newElem)
+/* Replace an element in the list with a new element, in the same position. */
+{
+void   *iElem, *lastElem;
+
+       if ( elemInList == NULL || newElem == NULL)
+               return 0;
+
+       for ( iElem = pList->Head, lastElem = NULL; iElem; iElem = GETLINK( iElem, pList->LinkOffset)) 
+       {
+               if ( iElem == elemInList)
+               {
+                       ASSIGNLINK( newElem, GETLINK( elemInList, pList->LinkOffset), pList->LinkOffset);
+                       if ( lastElem)          // somewhere past the head
+                       {
+                               ASSIGNLINK( lastElem, newElem, pList->LinkOffset);
+                       } 
+                       else                            // at the head
+                       {
+                               pList->Head = newElem;
+                       }
+                       if ( pList->Tail == elemInList)
+                               pList->Tail = newElem;
+                       return 1;
+               }
+               lastElem = iElem;
+       }
+
+       return 0;
+}
+
+
+//             GenDoubleLinkedList             /////////////////////////////////////////////////////////
+
+void           InitDoubleLinkedList( GenDoubleLinkedList *pList, size_t fwdLinkOffset,
+                                                                         size_t backLinkOffset)
+/* Initialize the block of memory pointed to by pList as a double linked list. */
+{
+       pList->Head = NULL;
+       pList->Tail = NULL;
+       pList->FwdLinkOffset = fwdLinkOffset;
+       pList->BackLinkOffset = backLinkOffset;
+}
+
+
+void                   DLLAddToHead( GenDoubleLinkedList *pList, void *elem)
+/* Add a linked list element to the head of the list. */
+{
+void           *pNext;
+
+       pNext = pList->Head;
+
+       // fix up the forward links
+       ASSIGNLINK( elem, pList->Head, pList->FwdLinkOffset);
+       pList->Head = elem;
+
+       // fix up the backward links
+       if ( pNext) {
+               ASSIGNLINK( pNext, elem, pList->BackLinkOffset);
+       } else
+               pList->Tail = elem;
+       ASSIGNLINK( elem, NULL, pList->BackLinkOffset);
+}
+
+
+void                   DLLRemoveFromList( GenDoubleLinkedList *pList, void *elem)
+/* Remove a linked list element from the list. */
+/* When the element is removed, its link will be set to NULL. */
+{
+void           *pNext, *pPrev;
+
+       pNext = GETLINK( elem, pList->FwdLinkOffset);
+       pPrev = GETLINK( elem, pList->BackLinkOffset);
+
+       // fix up the forward links
+       if ( pPrev)
+               ASSIGNLINK( pPrev, pNext, pList->FwdLinkOffset);
+       else
+               pList->Head = pNext;
+               
+       // fix up the backward links
+       if ( pNext)     
+               ASSIGNLINK( pNext, pPrev, pList->BackLinkOffset);
+       else
+               pList->Tail = pPrev;
+
+       ASSIGNLINK( elem, NULL, pList->FwdLinkOffset);
+       ASSIGNLINK( elem, NULL, pList->BackLinkOffset);
+}
+
+
+//             GenLinkedOffsetList             /////////////////////////////////////////////////////
+
+// Extract the Next offset from element
+#define                GETOFFSET( e, o)        ( *(size_t*)((char*) (e) + (o)) )
+
+static void            AssignOffsetLink( void *elem, void *link, size_t linkOffset);
+
+
+static void    AssignOffsetLink( void *elem, void *link, size_t linkOffset)
+// Assign link to elem as an offset from elem. Assign 0 to elem if link is NULL.
+{
+       GETOFFSET( elem, linkOffset) = link ? (size_t) link - (size_t) elem : 0;
+}
+
+
+void           *GetHeadPtr( GenLinkedOffsetList *pList)
+/* Return a pointer to the head element of a list, or NULL if none. */
+{
+       return pList->Head ? ( (char*) (pList) + pList->Head) : NULL;
+}
+
+
+void           *GetTailPtr( GenLinkedOffsetList *pList)
+/* Return a pointer to the tail element of a list, or NULL if none. */
+{
+       return pList->Tail ? ( (char*) (pList) + pList->Tail) : NULL;
+}
+
+
+void           *GetOffsetLink( GenLinkedOffsetList *pList, void *elem)
+/* Return the link pointer contained within element e for pList, or NULL if it is 0. */
+{
+size_t         nextOffset;
+
+       nextOffset = GETOFFSET( elem, pList->LinkOffset);
+
+       return nextOffset ? (char*) elem + nextOffset : NULL;
+}
+
+
+void           InitLinkedOffsetList( GenLinkedOffsetList *pList, size_t linkOffset)
+/* Initialize the block of memory pointed to by pList as a linked list. */
+{
+       pList->Head = 0;
+       pList->Tail = 0;
+       pList->LinkOffset = linkOffset;
+}
+
+
+void           OffsetAddToTail( GenLinkedOffsetList *pList, void *elem)
+/* Add a linked list element to the tail of the list. */
+{
+       if ( pList->Tail) {
+               AssignOffsetLink( GetTailPtr( pList), elem, pList->LinkOffset);
+       } else
+               pList->Head = (size_t) elem - (size_t) pList;
+       AssignOffsetLink( elem, NULL, pList->LinkOffset);
+
+       pList->Tail = (size_t) elem - (size_t) pList;
+}
+
+
+void           OffsetAddToHead( GenLinkedOffsetList *pList, void *elem)
+/* Add a linked list element to the head of the list. */
+{
+       AssignOffsetLink( elem, GetHeadPtr( pList), pList->LinkOffset);
+       if ( pList->Tail == 0) 
+               pList->Tail = (size_t) elem - (size_t) pList;
+
+       pList->Head = (size_t) elem - (size_t) pList;
+}
+
+
+int            OffsetRemoveFromList( GenLinkedOffsetList *pList, void *elem)
+/* Remove a linked list element from the list. Return 0 if it was not found. */
+/* If the element is removed, its link will be set to NULL. */
+{
+void   *iElem, *lastElem;
+
+       for ( iElem = GetHeadPtr( pList), lastElem = NULL; iElem; 
+                 iElem = GetOffsetLink( pList, iElem))
+       {
+               if ( iElem == elem) {
+                       if ( lastElem) {                // somewhere past the head
+                               AssignOffsetLink( lastElem, GetOffsetLink( pList, elem), pList->LinkOffset);
+                       } else {                                // at the head
+                               iElem = GetOffsetLink( pList, elem);
+                               pList->Head = iElem ? (size_t) iElem - (size_t) pList : 0;
+                       }
+                       if ( GetTailPtr( pList) == elem)
+                               pList->Tail = lastElem ? (size_t) lastElem - (size_t) pList : 0;
+                       AssignOffsetLink( elem, NULL, pList->LinkOffset);       // maybe catch a stale reference bug.
+                       return 1;
+               }
+               lastElem = iElem;
+       }
+
+       return 0;
+}
+
+
+int                    OffsetReplaceElem( GenLinkedOffsetList *pList, void *elemInList, void *newElem)
+/* Replace an element in the list with a new element, in the same position. */
+{
+void   *iElem, *lastElem;
+
+       if ( elemInList == NULL || newElem == NULL)
+               return 0;
+
+       for ( iElem = GetHeadPtr( pList), lastElem = NULL; iElem; 
+                 iElem = GetOffsetLink( pList, iElem))
+       {
+               if ( iElem == elemInList)
+               {
+                       AssignOffsetLink( newElem, GetOffsetLink( pList, elemInList), pList->LinkOffset);
+                       if ( lastElem)          // somewhere past the head
+                       {
+                               AssignOffsetLink( lastElem, newElem, pList->LinkOffset);
+                       } 
+                       else                            // at the head
+                       {
+                               pList->Head = (size_t) newElem - (size_t) pList;
+                       }
+                       if ( GetTailPtr( pList) == elemInList)
+                               pList->Tail = (size_t) newElem - (size_t) pList;
+                       return 1;
+               }
+               lastElem = iElem;
+       }
+
+       return 0;
+}
+
+
diff --git a/mDNSShared/GenLinkedList.h b/mDNSShared/GenLinkedList.h
new file mode 100755 (executable)
index 0000000..46cbb23
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+       File:           GenLinkedList.c
+
+       Contains:       interface to generic linked lists.
+
+       Version:        1.0
+       Tabs:           4 spaces
+
+    Change History (most recent first):
+
+$Log: GenLinkedList.h,v $
+Revision 1.2  2004/02/05 07:41:08  cheshire
+Add Log header
+
+*/
+
+#ifndef __GenLinkedList__
+#define __GenLinkedList__
+
+
+#include <stddef.h>
+
+
+struct GenLinkedList
+{
+       void            *Head,
+                               *Tail;
+       size_t          LinkOffset;
+};
+typedef struct GenLinkedList   GenLinkedList;
+
+
+void           InitLinkedList( GenLinkedList *pList, size_t linkOffset);
+
+void           AddToHead( GenLinkedList *pList, void *elem);
+void           AddToTail( GenLinkedList *pList, void *elem);
+
+int            RemoveFromList( GenLinkedList *pList, void *elem);
+
+int            ReplaceElem( GenLinkedList *pList, void *elemInList, void *newElem);
+
+
+
+struct GenDoubleLinkedList
+{
+       void            *Head,
+                               *Tail;
+       size_t          FwdLinkOffset,
+                               BackLinkOffset;
+};
+typedef struct GenDoubleLinkedList     GenDoubleLinkedList;
+
+
+void           InitDoubleLinkedList( GenDoubleLinkedList *pList, size_t fwdLinkOffset,
+                                                                         size_t backLinkOffset);
+
+void           DLLAddToHead( GenDoubleLinkedList *pList, void *elem);
+
+void           DLLRemoveFromList( GenDoubleLinkedList *pList, void *elem);
+
+
+
+/* A GenLinkedOffsetList is like a GenLinkedList that stores the *Next field as a signed */
+/* offset from the address of the beginning of the element, rather than as a pointer. */
+
+struct GenLinkedOffsetList
+{
+       size_t          Head,
+                               Tail;
+       size_t          LinkOffset;
+};
+typedef struct GenLinkedOffsetList     GenLinkedOffsetList;
+
+
+void           InitLinkedOffsetList( GenLinkedOffsetList *pList, size_t linkOffset);
+
+void           *GetHeadPtr( GenLinkedOffsetList *pList);
+void           *GetTailPtr( GenLinkedOffsetList *pList);
+void           *GetOffsetLink( GenLinkedOffsetList *pList, void *elem);
+
+void           OffsetAddToHead( GenLinkedOffsetList *pList, void *elem);
+void           OffsetAddToTail( GenLinkedOffsetList *pList, void *elem);
+
+int            OffsetRemoveFromList( GenLinkedOffsetList *pList, void *elem);
+
+int            OffsetReplaceElem( GenLinkedOffsetList *pList, void *elemInList, void *newElem);
+
+
+#endif //      __GenLinkedList__
index 665263d3fbb329f874928c3e6b46dd27efd1f015..f4f298b7a630a8e6b00930df8691f7cb294da424 100644 (file)
@@ -3,6 +3,8 @@
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
index 5bda3ae8cede25ca0a60d377c6de381bf9dceba5..2664e84eb2362e593e9184c622541ae47c1434bf 100644 (file)
@@ -3,6 +3,8 @@
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
index 73e1626358d3f971403cc08f93b9e5678d9deda3..d82ebd5854bcfc307c319e7c2f65c9690861fa3e 100644 (file)
@@ -3,6 +3,8 @@
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
@@ -23,9 +25,6 @@
     Change History (most recent first):
 
 $Log: DNSRecord.java,v $
-Revision 1.2  2004/12/11 03:00:59  rpantos
-<rdar://problem/3907498> Java DNSRecord API should be cleaned up
-
 Revision 1.1  2004/04/30 16:32:34  rpantos
 First checked in.
 
@@ -43,27 +42,7 @@ package      com.apple.dnssd;
        they are shared between concurrent threads.
 */
 
-public interface       DNSRecord
+abstract public class  DNSRecord
 {
-       /** Update a registered resource record.<P> 
-               The record must either be the primary txt record of a service registered via DNSSD.register(), 
-               or a record added to a registered service via addRecord().<P>
-
-               @param  flags
-                                       Currently unused, reserved for future use.
-               <P>
-               @param  rData
-                                       The new rdata to be contained in the updated resource record.
-               <P>
-               @param  ttl
-                                       The time to live of the updated resource record, in seconds.
-       */
-       void                    update( int flags, byte[] rData, int ttl)
-       throws DNSSDException;
-
-       /** Remove a registered resource record.<P> 
-       */
-       void                    remove()
-       throws DNSSDException;
 }
 
index 831b4b458142c7aa24985123149c006534731519..79cb5c703a10bd288694d051b669b398ae069365 100644 (file)
@@ -3,6 +3,8 @@
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
     Change History (most recent first):
 
 $Log: DNSSD.java,v $
-Revision 1.4  2004/12/11 03:00:59  rpantos
-<rdar://problem/3907498> Java DNSRecord API should be cleaned up
-
-Revision 1.3  2004/11/12 03:23:08  rpantos
-rdar://problem/3809541 implement getIfIndexForName, getNameForIfIndex.
-
 Revision 1.2  2004/05/20 17:43:18  cheshire
 Fix invalid UTF-8 characters in file
 
@@ -603,12 +599,12 @@ class     AppleDNSSD extends DNSSD
 
        protected String                        _getNameForIfIndex( int ifIndex)
        {
-               return GetNameForIfIndex( ifIndex);
+               return null;            // â€¢â€¢Fix me - RNP
        }
 
        protected int                           _getIfIndexForName( String ifName)
        {
-               return GetIfIndexForName( ifName);
+               return 0;               // â€¢â€¢Fix me - RNP
        }
 
 
@@ -617,10 +613,6 @@ class      AppleDNSSD extends DNSSD
        protected native void   ReconfirmRecord( int flags, int ifIndex, String fullName, int rrtype, 
                                                                                int rrclass, byte[] rdata);
 
-       protected native String GetNameForIfIndex( int ifIndex);
-
-       protected native int    GetIfIndexForName( String ifName);
-
        protected static native int     InitLibrary( int callerVersion);
 }
 
@@ -723,38 +715,9 @@ class      AppleResolver extends AppleService
 }
 
 // An AppleDNSRecord is a simple wrapper around a dns_sd DNSRecord.
-class  AppleDNSRecord implements DNSRecord
+class  AppleDNSRecord extends DNSRecord
 {
-       public                  AppleDNSRecord( AppleService owner) 
-       { 
-               fOwner = owner; 
-               fRecord = 0;            // record always starts out empty
-       }
-
-       public void                     update( int flags, byte[] rData, int ttl)
-       throws DNSSDException
-       {
-               this.ThrowOnErr( this.Update( flags, rData, ttl));
-       }
-
-       public void                     remove()
-       throws DNSSDException
-       {
-               this.ThrowOnErr( this.Remove());
-       }
-
-       protected int                   fRecord;                // Really a DNSRecord; sizeof(int) == sizeof(void*) ?
-       protected AppleService  fOwner;
-
-       protected void                  ThrowOnErr( int rc) throws DNSSDException
-       {
-               if ( rc != 0)
-                       throw new AppleDNSSDException( rc);
-       }
-
-       protected native int    Update( int flags, byte[] rData, int ttl);
-
-       protected native int    Remove();
+       public int              fRecord;                // Really a DNSRecord; sizeof(int) == sizeof(void*) ?
 }
 
 class  AppleRegistration extends AppleService implements DNSSDRegistration
@@ -772,17 +735,23 @@ class     AppleRegistration extends AppleService implements DNSSDRegistration
        public DNSRecord        addRecord( int flags, int rrType, byte[] rData, int ttl)
        throws DNSSDException
        {
-               AppleDNSRecord  newRecord = new AppleDNSRecord( this);
+               AppleDNSRecord  newRecord = new AppleDNSRecord();
 
                this.ThrowOnErr( this.AddRecord( flags, rrType, rData, ttl, newRecord));
 
                return newRecord;
        }
 
-       public DNSRecord        getTXTRecord()
+       public void                     updateRecord( DNSRecord record, int flags, byte[] rData, int ttl)
        throws DNSSDException
        {
-               return new AppleDNSRecord( this);       // A record with ref 0 is understood to be primary TXT record
+               this.ThrowOnErr( this.UpdateRecord( (AppleDNSRecord) record, flags, rData, ttl));
+       }
+
+       public void                     removeRecord( DNSRecord record, int flags)
+       throws DNSSDException
+       {
+               this.ThrowOnErr( this.RemoveRecord( (AppleDNSRecord) record, flags));
        }
 
        // Sets fNativeContext. Returns non-zero on error.
@@ -792,6 +761,10 @@ class      AppleRegistration extends AppleService implements DNSSDRegistration
        // Sets fNativeContext. Returns non-zero on error.
        protected native int    AddRecord( int flags, int rrType, byte[] rData, int ttl, AppleDNSRecord destObj);
 
+       protected native int    UpdateRecord( AppleDNSRecord destObj, int flags, byte[] rData, int ttl);
+
+       protected native int    RemoveRecord( AppleDNSRecord destObj, int flags);
+
        protected RegisterListener      fClient;
 }
 
index 595e405463ffa02a8e9f9c620c6a4e62a8275ab7..f3ccbcb43ada9ccc23aa52eec9e4afead915152e 100644 (file)
@@ -3,6 +3,8 @@
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
index 4a4942f9d93fb706a1270f83f3522120f88c8406..7be186d061f964fa20a5d8cb0dc92e7031e56a40 100644 (file)
@@ -3,6 +3,8 @@
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
@@ -23,9 +25,6 @@
     Change History (most recent first):
 
 $Log: DNSSDRegistration.java,v $
-Revision 1.2  2004/12/11 03:01:00  rpantos
-<rdar://problem/3907498> Java DNSRecord API should be cleaned up
-
 Revision 1.1  2004/04/30 16:32:34  rpantos
 First checked in.
 
@@ -42,20 +41,10 @@ package     com.apple.dnssd;
 
 public interface       DNSSDRegistration extends DNSSDService
 {
-       /** Get a reference to the primary TXT record of a registered service.<P> 
-               The record can be updated by sending it an update() message.<P>
-
-               <P>
-               @return         A {@link DNSRecord}. 
-                                       If {@link DNSSDRegistration#stop} is called, the DNSRecord is also 
-                                       invalidated and may not be used further.
-       */
-       DNSRecord               getTXTRecord()
-       throws DNSSDException;
-
        /** Add a record to a registered service.<P> 
                The name of the record will be the same as the registered service's name.<P>
-               The record can be updated or deregistered by sending it an update() or remove() message.<P>
+               The record can later be updated or deregistered by passing the DNSRecord returned 
+               by this function to updateRecord() or removeRecord().<P>
 
                @param  flags
                                        Currently unused, reserved for future use.
@@ -75,5 +64,37 @@ public interface     DNSSDRegistration extends DNSSDService
        */
        DNSRecord               addRecord( int flags, int rrType, byte[] rData, int ttl)
        throws DNSSDException;
+
+       /** Update a registered resource record.<P> 
+               The record must either be the primary txt record of a service registered via DNSSD.register(), 
+               or a record added to a registered service via addRecord().<P>
+
+               @param  record
+                                       A DNSRecord initialized by addRecord(), or null to update the
+                                       service's primary txt record.
+               <P>
+               @param  flags
+                                       Currently unused, reserved for future use.
+               <P>
+               @param  rData
+                                       The new rdata to be contained in the updated resource record.
+               <P>
+               @param  ttl
+                                       The time to live of the updated resource record, in seconds.
+       */
+       void                    updateRecord( DNSRecord record, int flags, byte[] rData, int ttl)
+       throws DNSSDException;
+
+       /** Remove a registered resource record.<P> 
+               The record must have been previously added to a service record set via via addRecord().<P>
+
+               @param  record
+                                       A DNSRecord initialized by addRecord().
+               <P>
+               @param  flags
+                                       Currently unused, reserved for future use.
+       */
+       void                    removeRecord( DNSRecord record, int flags)
+       throws DNSSDException;
 } 
 
index 98683720f1ad6e20d62009e3af85aac36887b613..bd7611a1e04c7803edeeeb5be14ea1a2ca58f7ef 100644 (file)
@@ -3,6 +3,8 @@
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
index bfb319af55d896b2605a2e4c67426c8f73b9d06a..13fad3bfa7f7e0e8790fe10911d1195d45230e8a 100644 (file)
@@ -3,6 +3,8 @@
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
index ef9940a55d099ba982cc03942aae93cc30de26cb..b57bd467c1afe4c30a7677243b69a04fb190c916 100644 (file)
@@ -3,6 +3,8 @@
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
     Change History (most recent first):
 
 $Log: JNISupport.c,v $
-Revision 1.9  2004/12/11 03:01:00  rpantos
-<rdar://problem/3907498> Java DNSRecord API should be cleaned up
-
-Revision 1.8  2004/11/30 23:51:05  cheshire
-Remove double semicolons
-
-Revision 1.7  2004/11/23 08:12:04  shersche
-Implement if_nametoindex and if_indextoname for Win32 platforms
-
-Revision 1.6  2004/11/23 03:41:14  cheshire
-Change JNISupport.c to call if_indextoname & if_nametoindex directly.
-(May require some additional glue code to work on Windows.)
-
-Revision 1.5  2004/11/17 17:07:44  cheshire
-Updated comment about AUTO_CALLBACKS
-
-Revision 1.4  2004/11/12 03:23:09  rpantos
-rdar://problem/3809541 implement getIfIndexForName, getNameForIfIndex.
-
-Revision 1.3  2004/06/18 04:44:17  rpantos
-Adapt to API unification on Windows
-
 Revision 1.2  2004/05/28 23:34:42  ksekar
-<rdar://problem/3672903>: Java project build errors
+<rdar://problem/3672903>: Java project doesn't build on Tiger8A132
 
 Revision 1.1  2004/04/30 16:29:35  rpantos
 First checked in.
@@ -54,45 +34,46 @@ First checked in.
 
        This file contains the platform support for DNSSD and related Java classes.
        It is used to shim through to the underlying <dns_sd.h> API.
+
+       To do:
+       - normalize code to eliminate USE_WIN_API
  */
 
 // AUTO_CALLBACKS should be set to 1 if the underlying mDNS implementation fires response
-// callbacks automatically (as in the early Windows prototypes).
+// callbacks automatically (as it does on Windows).
 // AUTO_CALLBACKS should be set to 0 if the client must call DNSServiceProcessResult() to
-// invoke response callbacks (as is true on Mac OS X, Posix, Windows, etc.).
-// (Invoking callbacks automatically on a different thread sounds attractive, but while
-// the client gains by not needing to add an event source to its main event loop, it loses
-// by being forced to deal with concurrency and locking, which can be a bigger burden.)
+// invoke response callbacks (as is true on Mac OS X).
 #ifndef        AUTO_CALLBACKS
 #define        AUTO_CALLBACKS  0
 #endif
 
-#if !AUTO_CALLBACKS
-#ifdef _WIN32
-#include <winsock2.h>
-#else //_WIN32
-#include <sys/types.h>
-#include <sys/select.h>
-#endif // _WIN32
-#endif // AUTO_CALLBACKS
-
-#include <dns_sd.h>
+// (Temporary, I hope - RNP)
+// USE_WIN_API should be set to 1 to use the DNSSD.h API (on Windows).
+// USE_WIN_API should be set to 0 to use the dns_sd.h API (on everything else).
+#ifndef        USE_WIN_API
+#define        USE_WIN_API     0
+#endif
 
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#ifdef _WIN32
-#include <winsock2.h>
-#include <iphlpapi.h>
-static char    *       if_indextoname( DWORD ifIndex, char * nameBuff);
-static DWORD   if_nametoindex( const char * nameStr );
-#define IF_NAMESIZE MAX_ADAPTER_NAME_LENGTH
-#else // _WIN32
-#include <sys/socket.h>
-#include <net/if.h>
-#endif // _WIN32
 #include <jni.h>
 
+#if USE_WIN_API
+#include <DNSSD.h>
+#else
+#include <dns_sd.h>
+#endif
+
+#if !USE_WIN_API
+#define CALLBACK_COMPAT        
+#endif
+
+#if !AUTO_CALLBACKS
+#include <sys/types.h>
+#include <sys/select.h>
+#endif
+
 #include "DNSSD.java.h"
 
 // convenience definition 
@@ -131,6 +112,16 @@ JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleDNSSD_InitLibrary( JNIEnv *pEnv
        if ( callerVersion != kInterfaceVersion)
                return kDNSServiceErr_Incompatible;
 
+#if USE_WIN_API
+       {
+               DNSServiceErrorType             err;
+               
+               err = DNSServiceInitialize( kDNSServiceInitializeFlagsNone, 0);
+               if ( err != kDNSServiceErr_NoError)
+                       return err;
+       }
+#endif
+
 #if AUTO_CALLBACKS
        {
                jsize   numVMs;
@@ -198,7 +189,7 @@ static OpContext    *NewContext( JNIEnv *pEnv, jobject owner, const char *ownerClas
                                                                const char *callbackName, const char *callbackSig)
 // Create and initialize a new OpContext.
 {
-       OpContext                               *pContext = (OpContext*) malloc( sizeof *pContext);
+       OpContext                               *pContext = (OpContext*) malloc( sizeof *pContext);;
 
        if ( pContext != NULL)
        {
@@ -312,7 +303,7 @@ JNIEXPORT void JNICALL Java_com_apple_dnssd_AppleService_ProcessResults( JNIEnv
 }
 
 
-static void DNSSD_API  ServiceBrowseReply( DNSServiceRef sdRef _UNUSED, DNSServiceFlags flags, uint32_t interfaceIndex, 
+static void CALLBACK_COMPAT    ServiceBrowseReply( DNSServiceRef sdRef _UNUSED, DNSServiceFlags flags, uint32_t interfaceIndex, 
                                                                DNSServiceErrorType errorCode, const char *serviceName, const char *regtype, 
                                                                const char *replyDomain, void *context)
 {
@@ -377,7 +368,7 @@ JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleBrowser_CreateBrowser( JNIEnv *
 }
 
 
-static void DNSSD_API  ServiceResolveReply( DNSServiceRef sdRef _UNUSED, DNSServiceFlags flags, uint32_t interfaceIndex, 
+static void CALLBACK_COMPAT    ServiceResolveReply( DNSServiceRef sdRef _UNUSED, DNSServiceFlags flags, uint32_t interfaceIndex, 
                                                                DNSServiceErrorType errorCode, const char *fullname, const char *hosttarget, 
                                                                uint16_t port, uint16_t txtLen, const char *txtRecord, void *context)
 {
@@ -462,7 +453,7 @@ JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleResolver_CreateResolver( JNIEnv
 }
 
 
-static void DNSSD_API  ServiceRegisterReply( DNSServiceRef sdRef _UNUSED, DNSServiceFlags flags, 
+static void CALLBACK_COMPAT    ServiceRegisterReply( DNSServiceRef sdRef _UNUSED, DNSServiceFlags flags, 
                                                                DNSServiceErrorType errorCode, const char *fullname, 
                                                                const char *regType, const char *domain, void *context)
 {
@@ -573,28 +564,23 @@ JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleRegistration_AddRecord( JNIEnv
        return err;
 }
 
-JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleDNSRecord_Update( JNIEnv *pEnv, jobject pThis, 
-                                                                                                               jint flags, jbyteArray rData, jint ttl)
+JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleRegistration_UpdateRecord( JNIEnv *pEnv, jobject pThis, 
+                                                       jobject destObj, jint flags, jbyteArray rData, jint ttl)
 {
        jclass                                  cls = (*pEnv)->GetObjectClass( pEnv, pThis);
-       jfieldID                                ownerField = (*pEnv)->GetFieldID( pEnv, cls, "fOwner", "Lcom/apple/dnssd/AppleService;");
-       jfieldID                                recField = (*pEnv)->GetFieldID( pEnv, cls, "fRecord", "I");
+       jfieldID                                contextField = (*pEnv)->GetFieldID( pEnv, cls, "fNativeContext", "I");
+       jclass                                  destCls = (*pEnv)->GetObjectClass( pEnv, destObj);
+       jfieldID                                recField = (*pEnv)->GetFieldID( pEnv, destCls, "fRecord", "I");
        OpContext                               *pContext = NULL;
        DNSServiceErrorType             err = kDNSServiceErr_NoError;
        jbyte                                   *pBytes;
        jsize                                   numBytes;
        DNSRecordRef                    recRef = NULL;
 
-       if ( ownerField != 0)
-       {
-               jobject         ownerObj = (*pEnv)->GetObjectField( pEnv, pThis, ownerField);
-               jclass          ownerClass = (*pEnv)->GetObjectClass( pEnv, ownerObj);
-               jfieldID        contextField = (*pEnv)->GetFieldID( pEnv, ownerClass, "fNativeContext", "I");
-               if ( contextField != 0)
-                       pContext = (OpContext*) (*pEnv)->GetIntField( pEnv, ownerObj, contextField);
-       }
+       if ( contextField != 0)
+               pContext = (OpContext*) (*pEnv)->GetIntField( pEnv, pThis, contextField);
        if ( recField != 0)
-               recRef = (DNSRecordRef) (*pEnv)->GetIntField( pEnv, pThis, recField);
+               recRef = (DNSRecordRef) (*pEnv)->GetIntField( pEnv, destObj, recField);
        if ( pContext == NULL || pContext->ServiceRef == NULL)
                return kDNSServiceErr_BadParam;
 
@@ -609,35 +595,31 @@ JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleDNSRecord_Update( JNIEnv *pEnv,
        return err;
 }
 
-JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleDNSRecord_Remove( JNIEnv *pEnv, jobject pThis)
+JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleRegistration_RemoveRecord( JNIEnv *pEnv, jobject pThis, 
+                                                       jobject destObj, jint flags)
 {
        jclass                                  cls = (*pEnv)->GetObjectClass( pEnv, pThis);
-       jfieldID                                ownerField = (*pEnv)->GetFieldID( pEnv, cls, "fOwner", "Lcom/apple/dnssd/AppleService;");
-       jfieldID                                recField = (*pEnv)->GetFieldID( pEnv, cls, "fRecord", "I");
+       jfieldID                                contextField = (*pEnv)->GetFieldID( pEnv, cls, "fNativeContext", "I");
+       jclass                                  destCls = (*pEnv)->GetObjectClass( pEnv, destObj);
+       jfieldID                                recField = (*pEnv)->GetFieldID( pEnv, destCls, "fRecord", "I");
        OpContext                               *pContext = NULL;
        DNSServiceErrorType             err = kDNSServiceErr_NoError;
        DNSRecordRef                    recRef = NULL;
 
-       if ( ownerField != 0)
-       {
-               jobject         ownerObj = (*pEnv)->GetObjectField( pEnv, pThis, ownerField);
-               jclass          ownerClass = (*pEnv)->GetObjectClass( pEnv, ownerObj);
-               jfieldID        contextField = (*pEnv)->GetFieldID( pEnv, ownerClass, "fNativeContext", "I");
-               if ( contextField != 0)
-                       pContext = (OpContext*) (*pEnv)->GetIntField( pEnv, ownerObj, contextField);
-       }
+       if ( contextField != 0)
+               pContext = (OpContext*) (*pEnv)->GetIntField( pEnv, pThis, contextField);
        if ( recField != 0)
-               recRef = (DNSRecordRef) (*pEnv)->GetIntField( pEnv, pThis, recField);
+               recRef = (DNSRecordRef) (*pEnv)->GetIntField( pEnv, destObj, recField);
        if ( pContext == NULL || pContext->ServiceRef == NULL)
                return kDNSServiceErr_BadParam;
 
-       err = DNSServiceRemoveRecord( pContext->ServiceRef, recRef, 0);
+       err = DNSServiceRemoveRecord( pContext->ServiceRef, recRef, flags);
 
        return err;
 }
 
 
-static void DNSSD_API  ServiceQueryReply( DNSServiceRef sdRef _UNUSED, DNSServiceFlags flags, uint32_t interfaceIndex, 
+static void CALLBACK_COMPAT    ServiceQueryReply( DNSServiceRef sdRef _UNUSED, DNSServiceFlags flags, uint32_t interfaceIndex, 
                                                                DNSServiceErrorType errorCode, const char *serviceName,
                                                                uint16_t rrtype, uint16_t rrclass, uint16_t rdlen,
                                                                const void *rdata, uint32_t ttl, void *context)
@@ -703,7 +685,7 @@ JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleQuery_CreateQuery( JNIEnv *pEnv
 }
 
 
-static void DNSSD_API  DomainEnumReply( DNSServiceRef sdRef _UNUSED, DNSServiceFlags flags, uint32_t interfaceIndex, 
+static void CALLBACK_COMPAT    DomainEnumReply( DNSServiceRef sdRef _UNUSED, DNSServiceFlags flags, uint32_t interfaceIndex, 
                                                                DNSServiceErrorType errorCode, const char *replyDomain, void *context)
 {
        OpContext               *pContext = (OpContext*) context;
@@ -802,141 +784,5 @@ JNIEXPORT void JNICALL Java_com_apple_dnssd_AppleDNSSD_ReconfirmRecord( JNIEnv *
        SafeReleaseUTFChars( pEnv, fullName, nameStr);
 }
 
-#define LOCAL_ONLY_NAME "loo"
-
-JNIEXPORT jstring JNICALL Java_com_apple_dnssd_AppleDNSSD_GetNameForIfIndex( JNIEnv *pEnv, jobject pThis _UNUSED, 
-                                                       jint ifIndex)
-{
-       char                                    *p = LOCAL_ONLY_NAME, nameBuff[IF_NAMESIZE];
-
-       if (ifIndex != kDNSServiceInterfaceIndexLocalOnly)
-               p = if_indextoname( ifIndex, nameBuff );
-
-       return (*pEnv)->NewStringUTF( pEnv, p);
-}
-
-
-JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleDNSSD_GetIfIndexForName( JNIEnv *pEnv, jobject pThis _UNUSED, 
-                                                       jstring ifName)
-{
-       uint32_t                                ifIndex = kDNSServiceInterfaceIndexLocalOnly;
-       const char                              *nameStr = SafeGetUTFChars( pEnv, ifName);
-
-       if (strcmp(nameStr, LOCAL_ONLY_NAME))
-               ifIndex = if_nametoindex( nameStr);
-
-       SafeReleaseUTFChars( pEnv, ifName, nameStr);
-
-       return ifIndex;
-}
-
-
-#if defined(_WIN32)
-static char*
-if_indextoname( DWORD ifIndex, char * nameBuff)
-{
-       PIP_ADAPTER_INFO        pAdapterInfo = NULL;
-       PIP_ADAPTER_INFO        pAdapter = NULL;
-       DWORD                           dwRetVal = 0;
-       char                    *       ifName = NULL;
-       ULONG                           ulOutBufLen = 0;
-       
-       if (GetAdaptersInfo( NULL, &ulOutBufLen) != ERROR_BUFFER_OVERFLOW)
-       {
-               goto exit;
-       }
-
-       pAdapterInfo = (IP_ADAPTER_INFO *) malloc(ulOutBufLen); 
 
-       if (pAdapterInfo == NULL)
-       {
-               goto exit;
-       }
 
-       dwRetVal = GetAdaptersInfo( pAdapterInfo, &ulOutBufLen );
-       
-       if (dwRetVal != NO_ERROR)
-       {
-               goto exit;
-       }
-
-       pAdapter = pAdapterInfo;
-       while (pAdapter)
-       {
-               if (pAdapter->Index == ifIndex)
-               {
-                       // It would be better if we passed in the length of nameBuff to this
-                       // function, so we would have absolute certainty that no buffer
-                       // overflows would occur.  Buffer overflows *shouldn't* occur because
-                       // nameBuff is of size MAX_ADAPTER_NAME_LENGTH.
-                       strcpy( nameBuff, pAdapter->AdapterName );
-                       ifName = nameBuff;
-                       break;
-               }
-  
-               pAdapter = pAdapter->Next;
-       }
-
-exit:
-
-       if (pAdapterInfo != NULL)
-       {
-               free( pAdapterInfo );
-               pAdapterInfo = NULL;
-       }
-
-       return ifName;
-}
-
-
-static DWORD
-if_nametoindex( const char * nameStr )
-{
-       PIP_ADAPTER_INFO        pAdapterInfo = NULL;
-       PIP_ADAPTER_INFO        pAdapter = NULL;
-       DWORD                           dwRetVal = 0;
-       DWORD                           ifIndex = 0;
-       ULONG                           ulOutBufLen = 0;
-
-       if (GetAdaptersInfo( NULL, &ulOutBufLen) != ERROR_BUFFER_OVERFLOW)
-       {
-               goto exit;
-       }
-
-       pAdapterInfo = (IP_ADAPTER_INFO *) malloc(ulOutBufLen); 
-
-       if (pAdapterInfo == NULL)
-       {
-               goto exit;
-       }
-
-       dwRetVal = GetAdaptersInfo( pAdapterInfo, &ulOutBufLen );
-       
-       if (dwRetVal != NO_ERROR)
-       {
-               goto exit;
-       }
-
-       pAdapter = pAdapterInfo;
-       while (pAdapter)
-       {
-               if (strcmp(pAdapter->AdapterName, nameStr) == 0)
-               {
-                       ifIndex = pAdapter->Index;
-                       break;
-               }
-  
-               pAdapter = pAdapter->Next;
-       }
-
-exit:
-
-       if (pAdapterInfo != NULL)
-       {
-               free( pAdapterInfo );
-               pAdapterInfo = NULL;
-       }
-
-       return ifIndex;
-}
-#endif
index 7ece74cf449c67c60b9c279407a0a9ea8aa1a3ad..1a8637bc1ac1a1c92be07d357e0aa445f6f1f917 100644 (file)
@@ -3,6 +3,8 @@
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
index a6cf33191dff1529f482dd3e79c446cab86a91ae..28c9fa5c09d9be0aff5bc454e695d55c7dafa9b3 100644 (file)
@@ -3,6 +3,8 @@
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
index 0e213531178d557789c6f31c2e3e89d2a4648df5..ac606cf2c47c77f79be15cf1da99aeba93acda2a 100644 (file)
@@ -3,6 +3,8 @@
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
index 5eed93eb74b44179ab9313d6fa999bce13a7b3d9..97bcea9852c8e1f57b7a8b99d1b333363d78c379 100644 (file)
@@ -3,6 +3,8 @@
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
     Change History (most recent first):
 
 $Log: TXTRecord.java,v $
-Revision 1.5  2004/08/25 21:54:36  rpantos
-<rdar://problem/3773973> Fix getValue() for values containing '='.
-
-Revision 1.4  2004/08/04 01:04:50  rpantos
-<rdar://problems/3731579&3731582> Fix set(); add remove() & toString().
-
-Revision 1.3  2004/07/13 21:24:25  rpantos
-Fix for <rdar://problem/3701120>.
-
 Revision 1.2  2004/04/30 21:48:27  rpantos
 Change line endings for CVS.
 
@@ -49,7 +42,7 @@ package       com.apple.dnssd;
 
 /**    
        Object used to construct and parse DNS-SD format TXT records.
-       For more info see <a href="http://files.dns-sd.org/draft-cheshire-dnsext-dns-sd.txt">DNS-Based Service Discovery</a>, section 6
+       For more info see <a href="http://www.zeroconf.org/Rendezvous/txtrecords.html">DNS-SD TXT record format</a>
 */
 
 public class   TXTRecord
@@ -97,8 +90,10 @@ public class TXTRecord
        */
        public void     set( String key, byte[] value)
        {
+               byte[]  oldBytes = fBytes;
                byte[]  keyBytes;
                int             valLen = (value != null) ? value.length : 0;
+               byte    newLen;
 
                try {
                        keyBytes = key.getBytes( "US-ASCII");
@@ -113,66 +108,17 @@ public class      TXTRecord
 
                if ( keyBytes.length + valLen >= 255)
                        throw new ArrayIndexOutOfBoundsException();
+               newLen = (byte) ( keyBytes.length + valLen + (valLen > 0 ? 1 : 0));
 
-               int             prevLoc = this.remove( key);
-               if ( prevLoc == -1)
-                       prevLoc = this.size();
-
-               this.insert( keyBytes, value, prevLoc);
-       }
-
-       protected void  insert( byte[] keyBytes, byte[] value, int index)
-       // Insert a key-value pair at index
-       {
-               byte[]  oldBytes = fBytes;
-               int             valLen = (value != null) ? value.length : 0;
-               int             insertion = 0;
-               byte    newLen, avLen;
-       
-               // locate the insertion point
-               for ( int i=0; i < index && insertion < fBytes.length; i++)
-                       insertion += fBytes[ insertion] + 1;
-       
-               avLen = (byte) ( keyBytes.length + valLen + (value != null ? 1 : 0));
-               newLen = (byte) ( avLen + oldBytes.length + 1);
-
-               fBytes = new byte[ newLen];
-               System.arraycopy( oldBytes, 0, fBytes, 0, insertion);
-               int secondHalfLen = oldBytes.length - insertion;
-               System.arraycopy( oldBytes, insertion, fBytes, newLen - secondHalfLen, secondHalfLen);
-               fBytes[ insertion] = avLen;
-               System.arraycopy( keyBytes, 0, fBytes, insertion + 1, keyBytes.length);
-               if ( value != null)
-               {
-                       fBytes[ insertion + 1 + keyBytes.length] = kAttrSep;
-                       System.arraycopy( value, 0, fBytes, insertion + keyBytes.length + 2, valLen);
-               }
-       }
-
-       /** Remove a key/value pair from the TXT record. Returns index it was at, or -1 if not found. */
-       public int      remove( String key)
-       {
-               int             avStart = 0;
-
-               for ( int i=0; avStart < fBytes.length; i++)
+               fBytes = new byte[ oldBytes.length + newLen + 1];
+               System.arraycopy( oldBytes, 0, fBytes, 0, oldBytes.length);
+               fBytes[ oldBytes.length] = newLen;
+               System.arraycopy( keyBytes, 0, fBytes, oldBytes.length + 1, keyBytes.length);
+               if ( valLen > 0)
                {
-                       int             avLen = fBytes[ avStart];
-                       if ( key.length() <= avLen && 
-                                ( key.length() == avLen || fBytes[ avStart + key.length() + 1] == kAttrSep))
-                       {
-                               String  s = new String( fBytes, avStart + 1, key.length());
-                               if ( 0 == key.compareToIgnoreCase( s))
-                               {
-                                       byte[]  oldBytes = fBytes;
-                                       fBytes = new byte[ oldBytes.length - avLen - 1];
-                                       System.arraycopy( oldBytes, 0, fBytes, 0, avStart);
-                                       System.arraycopy( oldBytes, avStart + avLen + 1, fBytes, avStart, oldBytes.length - avStart - avLen - 1);
-                                       return i;
-                               }
-                       }
-                       avStart += avLen + 1;
+                       fBytes[ oldBytes.length + 1 + keyBytes.length] = kAttrSep;
+                       System.arraycopy( value, 0, fBytes, oldBytes.length + keyBytes.length + 2, value.length);
                }
-               return -1;
        }
 
        /**     Return the number of keys in the TXT record. */
@@ -241,7 +187,6 @@ public class        TXTRecord
                                {
                                        value = new byte[ avLen - aLen - 1];
                                        System.arraycopy( fBytes, avStart + aLen + 2, value, 0, avLen - aLen - 1);
-                                       break;
                                }
                        }
                }
@@ -289,26 +234,5 @@ public class       TXTRecord
 
        /** Return the contents of the TXT record as raw bytes. */
        public byte[]   getRawBytes() { return (byte[]) fBytes.clone(); }
-
-       /** Return a string representation of the object. */
-       public String   toString()
-       {
-               String          a, result = null;
-               
-               for ( int i=0; null != ( a = this.getKey( i)); i++)
-               {
-                       String av = String.valueOf( i) + "={" + a;
-                       String val = this.getValueAsString( i);
-                       if ( val != null)
-                               av += "=" + val + "}";
-                       else
-                               av += "}";
-                       if ( result == null)
-                               result = av;
-                       else
-                               result = result + ", " + av;
-               }
-               return result != null ? result : "";
-       }
 }
 
index 4f22f679ce135034b386040780c8da21be7f42e1..45f51b7c0d817bbbd24a5646fee2acf23994493a 100755 (executable)
@@ -1,28 +1,84 @@
 /*
- * Copyright (c) 2003-2004, 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.
+ * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+
+$Log: dns_sd.h,v $
+Revision 1.17  2004/06/01 14:34:48  cheshire
+For compatibility with older compilers, change '//' comments to ' / * ... * / '
+
+Revision 1.16  2004/05/25 17:08:55  cheshire
+Fix compiler warning (doesn't make sense for function return type to be const)
+
+Revision 1.15  2004/05/21 21:41:35  cheshire
+Add TXT record building and parsing APIs
+
+Revision 1.14  2004/05/20 18:40:31  cheshire
+Remove trailing comma that breaks build on strict compilers
+
+Revision 1.13  2004/05/18 23:51:27  cheshire
+Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
+
+Revision 1.12  2004/05/07 21:11:07  ksekar
+API Update: Exposed new core error codes.  Added constants for
+InterfaceIndexAny and InterfaceIndexLocalOnly.  Added flag for
+long-lived unicast queries via DNSServiceQueryRecord.
+
+Revision 1.11  2004/05/07 20:51:18  ksekar
+<rdar://problem/3608226>: dns_sd.h needs to direct developers to
+register their services at <http://www.dns-sd.org/ServiceTypes.html>
+
+Revision 1.10  2004/05/06 18:42:58  ksekar
+General dns_sd.h API cleanup, including the following radars:
+<rdar://problem/3592068>: Remove flags with zero value
+<rdar://problem/3479569>: Passing in NULL causes a crash.
+
+Revision 1.9  2004/03/20 05:43:39  cheshire
+Fix contributed by Terry Lambert & Alfred Perlstein:
+On FreeBSD 4.x we need to include <sys/types.h> instead of <stdint.h>
+
+Revision 1.8  2004/03/19 17:50:40  cheshire
+Clarify comment about kDNSServiceMaxDomainName
+
+Revision 1.7  2004/03/12 08:00:06  cheshire
+Minor comment changes, headers, and wrap file in extern "C" for the benefit of C++ clients
+
+Revision 1.6  2003/12/04 06:24:33  cheshire
+Clarify meaning of MoreComing/Finished flag
+
+Revision 1.5  2003/11/13 23:35:35  ksekar
+<rdar://problem/3483020>: Header doesn't say that add/remove are possible values for flags
+Bringing mDNSResponder project copy of dns_sd.h header up to date with
+Libinfo copy
+
+Revision 1.4  2003/10/13 23:50:53  ksekar
+Updated dns_sd clientstub files to bring copies in synch with
+top-of-tree Libinfo:  A memory leak in dnssd_clientstub.c is fixed,
+and comments in dns_sd.h are improved.
+
+Revision 1.3  2003/08/12 19:51:51  cheshire
+Update to APSL 2.0
  */
 
 #ifndef _DNS_SD_H
     extern "C" {
 #endif
 
-/* standard calling convention under Win32 is __stdcall */
-#if defined(_WIN32)
-#define DNSSD_API __stdcall
-#else
-#define DNSSD_API
-#endif
-
-#if defined(__FreeBSD_version) && (__FreeBSD_version < 500000)
+#if defined(__FreeBSD__) && (__FreeBSD_version < 500000)
 /* stdint.h does not exist on FreeBSD 4.x; its types are defined in sys/types.h instead */
 #include <sys/types.h>
-#elif defined(__sun__)
-#include <sys/types.h>
-#elif defined(_WIN32)
-#include <windows.h>
-#define _UNUSED
-#define bzero(a, b) memset(a, 0, b)
-typedef UINT8       uint8_t;
-typedef INT8        int8_t;
-typedef UINT16      uint16_t;
-typedef INT16       int16_t;
-typedef UINT32      uint32_t;
-typedef INT32       int32_t;
 #else
 #include <stdint.h>
 #endif
@@ -100,7 +137,7 @@ enum
      * 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.)
+     * (ie the default name is not used.)
      */
 
     kDNSServiceFlagsShared              = 0x10,
@@ -118,89 +155,10 @@ enum
      * enumerates domains recommended for registration.
      */
 
-    kDNSServiceFlagsLongLivedQuery      = 0x100,
+    kDNSServiceFlagsLongLivedQuery      = 0x100
     /* Flag for creating a long-lived unicast query for the DNSServiceQueryRecord call. */
-
-    kDNSServiceFlagsAllowRemoteQuery    = 0x200,
-    /* Flag for creating a record for which we will answer remote queries
-     * (queries from hosts more than one hop away; hosts not directly connected to the local link).
-     */
-
-    kDNSServiceFlagsForceMulticast      = 0x400
-    /* Flag for signifying that a query or registration should be performed exclusively via multicast DNS,
-     * even for a name in a domain (e.g. foo.apple.com.) that would normally imply unicast DNS.
-     */
-    };
-
-/*
- * The values for DNS Classes and Types are listed in RFC 1035, and are available
- * on every OS in its DNS header file. Unfortunately every OS does not have the
- * same header file containing DNS Class and Type constants, and the names of
- * the constants are not consistent. For example, BIND 8 uses "T_A",
- * BIND 9 uses "ns_t_a", Windows uses "DNS_TYPE_A", etc.
- * For this reason, these constants are also listed here, so that code using
- * the DNS-SD programming APIs can use these constants, so that the same code
- * can compile on all our supported platforms.
- */
-
-enum
-    {
-    kDNSServiceClass_IN       = 1       /* Internet */
-    };
-
-enum
-    {
-    kDNSServiceType_A         = 1,      /* Host address. */
-    kDNSServiceType_NS        = 2,      /* Authoritative server. */
-    kDNSServiceType_MD        = 3,      /* Mail destination. */
-    kDNSServiceType_MF        = 4,      /* Mail forwarder. */
-    kDNSServiceType_CNAME     = 5,      /* Canonical name. */
-    kDNSServiceType_SOA       = 6,      /* Start of authority zone. */
-    kDNSServiceType_MB        = 7,      /* Mailbox domain name. */
-    kDNSServiceType_MG        = 8,      /* Mail group member. */
-    kDNSServiceType_MR        = 9,      /* Mail rename name. */
-    kDNSServiceType_NULL      = 10,     /* Null resource record. */
-    kDNSServiceType_WKS       = 11,     /* Well known service. */
-    kDNSServiceType_PTR       = 12,     /* Domain name pointer. */
-    kDNSServiceType_HINFO     = 13,     /* Host information. */
-    kDNSServiceType_MINFO     = 14,     /* Mailbox information. */
-    kDNSServiceType_MX        = 15,     /* Mail routing information. */
-    kDNSServiceType_TXT       = 16,     /* Text strings. */
-    kDNSServiceType_RP        = 17,     /* Responsible person. */
-    kDNSServiceType_AFSDB     = 18,     /* AFS cell database. */
-    kDNSServiceType_X25       = 19,     /* X_25 calling address. */
-    kDNSServiceType_ISDN      = 20,     /* ISDN calling address. */
-    kDNSServiceType_RT        = 21,     /* Router. */
-    kDNSServiceType_NSAP      = 22,     /* NSAP address. */
-    kDNSServiceType_NSAP_PTR  = 23,     /* Reverse NSAP lookup (deprecated). */
-    kDNSServiceType_SIG       = 24,     /* Security signature. */
-    kDNSServiceType_KEY       = 25,     /* Security key. */
-    kDNSServiceType_PX        = 26,     /* X.400 mail mapping. */
-    kDNSServiceType_GPOS      = 27,     /* Geographical position (withdrawn). */
-    kDNSServiceType_AAAA      = 28,     /* Ip6 Address. */
-    kDNSServiceType_LOC       = 29,     /* Location Information. */
-    kDNSServiceType_NXT       = 30,     /* Next domain (security). */
-    kDNSServiceType_EID       = 31,     /* Endpoint identifier. */
-    kDNSServiceType_NIMLOC    = 32,     /* Nimrod Locator. */
-    kDNSServiceType_SRV       = 33,     /* Server Selection. */
-    kDNSServiceType_ATMA      = 34,     /* ATM Address */
-    kDNSServiceType_NAPTR     = 35,     /* Naming Authority PoinTeR */
-    kDNSServiceType_KX        = 36,     /* Key Exchange */
-    kDNSServiceType_CERT      = 37,     /* Certification record */
-    kDNSServiceType_A6        = 38,     /* IPv6 address (deprecates AAAA) */
-    kDNSServiceType_DNAME     = 39,     /* Non-terminal DNAME (for IPv6) */
-    kDNSServiceType_SINK      = 40,     /* Kitchen sink (experimentatl) */
-    kDNSServiceType_OPT       = 41,     /* EDNS0 option (meta-RR) */
-    kDNSServiceType_TKEY      = 249,    /* Transaction key */
-    kDNSServiceType_TSIG      = 250,    /* Transaction signature. */
-    kDNSServiceType_IXFR      = 251,    /* Incremental zone transfer. */
-    kDNSServiceType_AXFR      = 252,    /* Transfer zone of authority. */
-    kDNSServiceType_MAILB     = 253,    /* Transfer mailbox records. */
-    kDNSServiceType_MAILA     = 254,    /* Transfer mail agent records. */
-    kDNSServiceType_ANY       = 255     /* Wildcard match. */
     };
 
-
 /* possible error code values */
 enum
     {
@@ -217,16 +175,12 @@ enum
     kDNSServiceErr_AlreadyRegistered   = -65547,
     kDNSServiceErr_NameConflict        = -65548,
     kDNSServiceErr_Invalid             = -65549,
-    kDNSServiceErr_Firewall            = -65550,
     kDNSServiceErr_Incompatible        = -65551,        /* client library incompatible with daemon */
     kDNSServiceErr_BadInterfaceIndex   = -65552,
     kDNSServiceErr_Refused             = -65553,
     kDNSServiceErr_NoSuchRecord        = -65554,
     kDNSServiceErr_NoAuth              = -65555,
-    kDNSServiceErr_NoSuchKey           = -65556,
-    kDNSServiceErr_NATTraversal        = -65557,
-    kDNSServiceErr_DoubleNAT           = -65558,
-    kDNSServiceErr_BadTime             = -65559
+    kDNSServiceErr_NoSuchKey           = -65556
     /* mDNS Error codes are in the range
      * FFFE FF00 (-65792) to FFFE FFFF (-65537) */
     };
@@ -237,84 +191,13 @@ enum
 
 #define kDNSServiceMaxDomainName 1005
 
-/*
- * Notes on DNS Name Escaping
- *   -- or --
- * "Why is kDNSServiceMaxDomainName 1005, when the maximum legal domain name is 255 bytes?"
- *
- * All strings used in DNS-SD are UTF-8 strings.
- * With few exceptions, most are also escaped using standard DNS escaping rules:
- *
- *   '\\' represents a single literal '\' in the name
- *   '\.' represents a single literal '.' in the name
- *   '\ddd', where ddd is a three-digit decimal value from 000 to 255,
- *        represents a single literal byte with that value.
- *   A bare unescaped '.' is a label separator, marking a boundary between domain and subdomain.
- *
- * 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
- * it is, by definition, just a single literal string. Any characters in that string
- * represent exactly what they are. The "regtype" portion is, technically speaking,
- * escaped, but since legal regtypes are only allowed to contain letters, digits,
- * and hyphens, the issue is moot. The "domain" portion is also escaped, though
- * most domains in use on the public Internet today, like regtypes, don't contain
- * any characters that need to be escaped. As DNS-SD becomes more popular, rich-text
- * domains for service discovery will become common, so software should be written
- * to cope with domains with escaping.
- *
- * For most software, these issues are transparent. When browsing, the discovered
- * servicenames should simply be displayed as-is. When resolving, the discovered
- * servicename/regtype/domain are simply passed unchanged to DNSServiceResolve().
- * When a DNSServiceResolve() succeeds, the returned fullname is already in
- * the correct format to pass to standard system DNS APIs such as res_query().
- * For converting from servicename/regtype/domain to a single properly-escaped
- * full DNS name, the helper function DNSServiceConstructFullName() is provided.
- *
- * The following (highly contrived) example illustrates the escaping process.
- * Suppose you have an service called "Dr. Smith\Dr. Johnson", of type "_ftp._tcp"
- * in subdomain "4th. Floor" of subdomain "Building 2" of domain "apple.com."
- * The full (escaped) DNS name of this service's SRV record would be:
- * Dr\.\032Smith\\Dr\.\032Johnson._ftp._tcp.4th\.\032Floor.Building\0322.apple.com.
- */
-
-
-/* 
- * Constants for specifying an interface index
- *
- * Specific interface indexes are identified via a 32-bit unsigned integer returned
- * by the if_nametoindex() family of calls.
- * 
- * If the client passes 0 for interface index, that means "do the right thing",
- * which (at present) means, "if the name is in an mDNS local multicast domain
- * (e.g. 'local.', '254.169.in-addr.arpa.', '0.8.E.F.ip6.arpa.') then multicast
- * on all applicable interfaces, otherwise send via unicast to the appropriate
- * DNS server." Normally, most clients will use 0 for interface index to
- * automatically get the default sensible behaviour.
- * 
- * If the client passes a positive interface index, then for multicast names that
- * indicates to do the operation only on that one interface. For unicast names the
- * interface index is ignored unless kDNSServiceFlagsForceMulticast is also set.
- * 
- * If the client passes kDNSServiceInterfaceIndexLocalOnly when registering
- * a service, then that service will be found *only* by other local clients
- * on the same machine that are browsing using kDNSServiceInterfaceIndexLocalOnly
- * or kDNSServiceInterfaceIndexAny.
- * If a client has a 'private' service, accessible only to other processes
- * running on the same machine, this allows the client to advertise that service
- * in a way such that it does not inadvertently appear in service lists on
- * all the other machines on the network.
- * 
- * If the client passes kDNSServiceInterfaceIndexLocalOnly when browsing
- * then it will find *all* records registered on that same local machine.
- * Clients explicitly wishing to discover *only* LocalOnly services can
- * accomplish this by inspecting the interfaceIndex of each service reported
- * to their DNSServiceBrowseReply() callback function, and discarding those
- * where the interface index is not kDNSServiceInterfaceIndexLocalOnly.
+/* Constants for specifying an interface index.  Specific interface indexes are
+ * identified via a 32-bit unsigned integer returned by the if_nametoindex()
+ * family of calls
  */
 
 #define kDNSServiceInterfaceIndexAny 0
-#define kDNSServiceInterfaceIndexLocalOnly ( (uint32_t) -1 )
+#define kDNSServiceInterfaceIndexLocalOnly ( (uint32_t) ~0 )
 
 
 typedef uint32_t DNSServiceFlags;
@@ -349,7 +232,7 @@ typedef int32_t DNSServiceErrorType;
  *                  error.
  */
 
-int DNSSD_API DNSServiceRefSockFD(DNSServiceRef sdRef);
+int DNSServiceRefSockFD(DNSServiceRef sdRef);
 
 
 /* DNSServiceProcessResult()
@@ -370,7 +253,7 @@ int DNSSD_API DNSServiceRefSockFD(DNSServiceRef sdRef);
  *                  an error code indicating the specific failure that occurred.
  */
 
-DNSServiceErrorType DNSSD_API DNSServiceProcessResult(DNSServiceRef sdRef);
+DNSServiceErrorType DNSServiceProcessResult(DNSServiceRef sdRef);
 
 
 /* DNSServiceRefDeallocate()
@@ -399,7 +282,7 @@ DNSServiceErrorType DNSSD_API DNSServiceProcessResult(DNSServiceRef sdRef);
  *
  */
 
-void DNSSD_API DNSServiceRefDeallocate(DNSServiceRef sdRef);
+void DNSServiceRefDeallocate(DNSServiceRef sdRef);
 
 
 /*********************************************************************************************
@@ -411,16 +294,11 @@ void DNSSD_API DNSServiceRefDeallocate(DNSServiceRef sdRef);
 /* 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.
  *
- * Note that the names returned are (like all of DNS-SD) UTF-8 strings,
- * and are escaped using standard DNS escaping rules.
- * (See "Notes on DNS Name Escaping" earlier in this file for more details.)
- * A graphical browser displaying a hierarchical tree-structured view should cut
- * the names at the bare dots to yield individual labels, then de-escape each
- * label according to the escaping rules, and then display the resulting UTF-8 text.
  *
  * DNSServiceDomainEnumReply Callback Parameters:
  *
@@ -443,7 +321,7 @@ void DNSSD_API DNSServiceRefDeallocate(DNSServiceRef sdRef);
  *
  */
 
-typedef void (DNSSD_API *DNSServiceDomainEnumReply)
+typedef void (*DNSServiceDomainEnumReply)
     (
     DNSServiceRef                       sdRef,
     DNSServiceFlags                     flags,
@@ -457,10 +335,8 @@ 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.  May be passed to
+ *                  DNSServiceRefDeallocate() to cancel the enumeration.
  *
  * flags:           Possible values are:
  *                  kDNSServiceFlagsBrowseDomains to enumerate domains recommended for browsing.
@@ -470,7 +346,7 @@ typedef void (DNSSD_API *DNSServiceDomainEnumReply)
  * interfaceIndex:  If non-zero, specifies the interface on which to look for domains.
  *                  (the index for a given interface is determined via the if_nametoindex()
  *                  family of calls.)  Most applications will pass 0 to enumerate domains on
- *                  all interfaces. See "Constants for specifying an interface index" for more details.
+ *                  all interfaces.
  *
  * callBack:        The function to be called when a domain is found or the call asynchronously
  *                  fails.
@@ -484,7 +360,7 @@ typedef void (DNSSD_API *DNSServiceDomainEnumReply)
  *                  is not initialized.)
  */
 
-DNSServiceErrorType DNSSD_API DNSServiceEnumerateDomains
+DNSServiceErrorType DNSServiceEnumerateDomains
     (
     DNSServiceRef                       *sdRef,
     DNSServiceFlags                     flags,
@@ -527,7 +403,7 @@ DNSServiceErrorType DNSSD_API DNSServiceEnumerateDomains
  *
  */
 
-typedef void (DNSSD_API *DNSServiceRegisterReply)
+typedef void (*DNSServiceRegisterReply)
     (
     DNSServiceRef                       sdRef,
     DNSServiceFlags                     flags,
@@ -541,15 +417,15 @@ 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.  If this call succeeds, the reference
+ *                  may be passed to
+ *                  DNSServiceRefDeallocate() to deregister the service.
  *
  * 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. See "Constants for specifying an interface index" for more details.
+ *                  available interfaces.  Pass -1 to register a service only on the local
+ *                  machine (service will not be visible to remote hosts.)
  *
  * flags:           Indicates the renaming behavior on name conflict (most applications
  *                  will pass 0).  See flag definitions above for details.
@@ -602,7 +478,7 @@ typedef void (DNSSD_API *DNSServiceRegisterReply)
  *
  */
 
-DNSServiceErrorType DNSSD_API DNSServiceRegister
+DNSServiceErrorType DNSServiceRegister
     (
     DNSServiceRef                       *sdRef,
     DNSServiceFlags                     flags,
@@ -638,19 +514,19 @@ DNSServiceErrorType DNSSD_API DNSServiceRegister
  *
  * flags:           Currently ignored, reserved for future use.
  *
- * rrtype:          The type of the record (e.g. kDNSServiceType_TXT, kDNSServiceType_SRV, etc)
+ * rrtype:          The type of the record (e.g. TXT, SRV, etc), as defined in nameser.h.
  *
  * rdlen:           The length, in bytes, of the rdata.
  *
  * rdata:           The raw rdata to be contained in the added resource record.
  *
- * ttl:             The time to live of the resource record, in seconds.  Pass 0 to use a default value.
+ * ttl:             The time to live of the resource record, in seconds.
  *
  * return value:    Returns kDNSServiceErr_NoError on success, otherwise returns an
  *                  error code indicating the error that occurred (the RecordRef is not initialized).
  */
 
-DNSServiceErrorType DNSSD_API DNSServiceAddRecord
+DNSServiceErrorType DNSServiceAddRecord
     (
     DNSServiceRef                       sdRef,
     DNSRecordRef                        *RecordRef,
@@ -690,7 +566,7 @@ DNSServiceErrorType DNSSD_API DNSServiceAddRecord
  *                  error code indicating the error that occurred.
  */
 
-DNSServiceErrorType DNSSD_API DNSServiceUpdateRecord
+DNSServiceErrorType DNSServiceUpdateRecord
     (
     DNSServiceRef                       sdRef,
     DNSRecordRef                        RecordRef,     /* may be NULL */
@@ -722,7 +598,7 @@ DNSServiceErrorType DNSSD_API DNSServiceUpdateRecord
  *                  error code indicating the error that occurred.
  */
 
-DNSServiceErrorType DNSSD_API DNSServiceRemoveRecord
+DNSServiceErrorType DNSServiceRemoveRecord
     (
     DNSServiceRef                 sdRef,
     DNSRecordRef                  RecordRef,
@@ -753,29 +629,19 @@ DNSServiceErrorType DNSSD_API DNSServiceRemoveRecord
  *                  indicate the failure that occurred.  Other parameters are undefined if
  *                  the errorCode is nonzero.
  *
- * serviceName:     The discovered service name. This name should be displayed to the user,
- *                  and stored for subsequent use in the DNSServiceResolve() call.
+ * serviceName:     The service name discovered.
  *
- * regtype:         The service type, which is usually (but not always) the same as was passed
- *                  to DNSServiceBrowse(). One case where the discovered service type may
- *                  not be the same as the requested service type is when using subtypes:
- *                  The client may want to browse for only those ftp servers that allow
- *                  anonymous connections. The client will pass the string "_ftp._tcp,_anon"
- *                  to DNSServiceBrowse(), but the type of the service that's discovered
- *                  is simply "_ftp._tcp". The regtype for each discovered service instance
- *                  should be stored along with the name, so that it can be passed to
- *                  DNSServiceResolve() when the service is later resolved.
+ * regtype:         The service type, as passed in to DNSServiceBrowse().
  *
- * domain:          The domain of the discovered service instance. This may or may not be the
- *                  same as the domain that was passed to DNSServiceBrowse(). The domain for each
- *                  discovered service instance should be stored along with the name, so that
- *                  it can be passed to DNSServiceResolve() when the service is later resolved.
+ * domain:          The domain on which the service was discovered (if the application did not
+ *                  specify a domain in DNSServicBrowse(), this indicates the domain on which the
+ *                  service was discovered.)
  *
  * context:         The context pointer that was passed to the callout.
  *
  */
 
-typedef void (DNSSD_API *DNSServiceBrowseReply)
+typedef void (*DNSServiceBrowseReply)
     (
     DNSServiceRef                       sdRef,
     DNSServiceFlags                     flags,
@@ -790,17 +656,15 @@ 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.  May be passed to
+ *                  DNSServiceRefDeallocate() 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. See "Constants for specifying an interface index" for more details.
+ *                  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".
@@ -821,7 +685,7 @@ typedef void (DNSSD_API *DNSServiceBrowseReply)
  *                  is not initialized.)
  */
 
-DNSServiceErrorType DNSSD_API DNSServiceBrowse
+DNSServiceErrorType DNSServiceBrowse
     (
     DNSServiceRef                       *sdRef,
     DNSServiceFlags                     flags,
@@ -861,10 +725,12 @@ DNSServiceErrorType DNSSD_API DNSServiceBrowse
  *                  the errorCode is nonzero.
  *
  * fullname:        The full service domain name, in the form <servicename>.<protocol>.<domain>.
- *                  (This name is escaped following standard DNS rules, making it suitable for
- *                  passing to standard system DNS APIs such as res_query(), or to the
- *                  special-purpose functions included in this API that take fullname parameters.
- *                  See "Notes on DNS Name Escaping" earlier in this file for more details.)
+ *                  (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.
@@ -880,7 +746,7 @@ DNSServiceErrorType DNSSD_API DNSServiceBrowse
  *
  */
 
-typedef void (DNSSD_API *DNSServiceResolveReply)
+typedef void (*DNSServiceResolveReply)
     (
     DNSServiceRef                       sdRef,
     DNSServiceFlags                     flags,
@@ -897,29 +763,23 @@ 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.  May be passed to
+ *                  DNSServiceRefDeallocate() to terminate the resolve.
  *
  * flags:           Currently ignored, reserved for future use.
  *
- * interfaceIndex:  The interface on which to resolve the service. If this resolve call is
- *                  as a result of a currently active DNSServiceBrowse() operation, then the
- *                  interfaceIndex should be the index reported in the DNSServiceBrowseReply
- *                  callback. If this resolve call is using information previously saved
- *                  (e.g. in a preference file) for later use, then use interfaceIndex 0, because
- *                  the desired service may now be reachable via a different physical interface.
- *                  See "Constants for specifying an interface index" for more details.
+ * 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 name of the service instance to be resolved, as reported to the
- *                  DNSServiceBrowseReply() callback.
+ * name:            The servicename to be resolved.
  *
- * regtype:         The type of the service instance to be resolved, as reported to the
- *                  DNSServiceBrowseReply() callback.
+ * 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 of the service instance to be resolved, as reported to the
- *                  DNSServiceBrowseReply() callback.
+ * domain:          The domain on which the service is registered, i.e. the domain passed
+ *                  to the DNSServiceBrowseReply callback.
  *
  * callBack:        The function to be called when a result is found, or if the call
  *                  asynchronously fails.
@@ -933,7 +793,7 @@ typedef void (DNSSD_API *DNSServiceResolveReply)
  *                  is not initialized.)
  */
 
-DNSServiceErrorType DNSSD_API DNSServiceResolve
+DNSServiceErrorType DNSServiceResolve
     (
     DNSServiceRef                       *sdRef,
     DNSServiceFlags                     flags,
@@ -952,6 +812,28 @@ DNSServiceErrorType DNSSD_API DNSServiceResolve
  *
  *********************************************************************************************/
 
+/* Note on DNS Naming Conventions:
+ *
+ * The functions below refer to resource records by their full domain name, unlike the
+ * functions above which divide the name into servicename/regtype/domain fields.  In the
+ * functions above, a dot (".") is considered to be a literal dot in the servicename field
+ * (e.g. "Dr. Pepper") and a label separator in the regtype ("_ftp._tcp") or domain
+ * ("apple.com") fields.  Literal dots in the domain field would be escaped with a backslash,
+ * and literal backslashes would be escaped with a second backslash (this is generally not an
+ * issue, as domain names on the Internet today almost never use characters other than
+ * letters, digits, or hyphens, and the dots are label separators.) Furthermore, this is
+ * transparent to the caller, so long as the fields are passed between functions without
+ * manipulation.  However, the following, special-purpose calls use a single, full domain
+ * name.  As such, all dots are considered to be label separators, unless escaped, and all
+ * backslashes are considered to be escape characters, unless preceded by a second backslash.
+ * For example, the name "Dr. Smith \ Dr. Johnson" could be passed literally as a service
+ * name parameter in the above calls, but in the special purpose calls, the dots and backslash
+ * would have to be escaped (e.g. "Dr\. Smith \\ Dr\. Johnson._ftp._tcp.apple.com" for an ftp
+ * service on the apple.com domain.) The function DNSServiceConstructFullName() is provided
+ * to aid in this conversion from servicename/regtype/domain to a single fully-qualified DNS
+ * name with proper escaping.
+ */
+
 /* DNSServiceCreateConnection()
  *
  * Create a connection to the daemon allowing efficient registration of
@@ -969,7 +851,7 @@ DNSServiceErrorType DNSSD_API DNSServiceResolve
  *                  case the DNSServiceRef is not initialized).
  */
 
-DNSServiceErrorType DNSSD_API DNSServiceCreateConnection(DNSServiceRef *sdRef);
+DNSServiceErrorType DNSServiceCreateConnection(DNSServiceRef *sdRef);
 
 
 /* DNSServiceRegisterRecord
@@ -999,7 +881,7 @@ DNSServiceErrorType DNSSD_API DNSServiceCreateConnection(DNSServiceRef *sdRef);
  *
  */
 
- typedef void (DNSSD_API *DNSServiceRegisterRecordReply)
+ typedef void (*DNSServiceRegisterRecordReply)
     (
     DNSServiceRef                       sdRef,
     DNSRecordRef                        RecordRef,
@@ -1025,19 +907,21 @@ DNSServiceErrorType DNSSD_API DNSServiceCreateConnection(DNSServiceRef *sdRef);
  * interfaceIndex:  If non-zero, specifies the interface on which to register the record
  *                  (the index for a given interface is determined via the if_nametoindex()
  *                  family of calls.)  Passing 0 causes the record to be registered on all interfaces.
- *                  See "Constants for specifying an interface index" for more details.
+ *                  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. kDNSServiceType_PTR, kDNSServiceType_SRV, etc)
+ * 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 (usually kDNSServiceClass_IN)
+ * rrclass:         The class of the resource record, as defined in nameser.h (usually 1 for the
+ *                  Internet class).
  *
  * rdlen:           Length, in bytes, of the rdata.
  *
  * rdata:           A pointer to the raw rdata, as it is to appear in the DNS record.
  *
- * ttl:             The time to live of the resource record, in seconds.  Pass 0 to use a default value.
+ * ttl:             The time to live of the resource record, in seconds.
  *
  * callBack:        The function to be called when a result is found, or if the call
  *                  asynchronously fails (e.g. because of a name conflict.)
@@ -1051,7 +935,7 @@ DNSServiceErrorType DNSSD_API DNSServiceCreateConnection(DNSServiceRef *sdRef);
  *                  not initialized.)
  */
 
-DNSServiceErrorType DNSSD_API DNSServiceRegisterRecord
+DNSServiceErrorType DNSServiceRegisterRecord
     (
     DNSServiceRef                       sdRef,
     DNSRecordRef                        *RecordRef,
@@ -1083,7 +967,6 @@ DNSServiceErrorType DNSSD_API DNSServiceRegisterRecord
  *
  * interfaceIndex:  The interface on which the query was resolved (the index for a given
  *                  interface is determined via the if_nametoindex() family of calls).
- *                  See "Constants for specifying an interface index" for more details.
  *
  * errorCode:       Will be kDNSServiceErr_NoError on success, otherwise will
  *                  indicate the failure that occurred.  Other parameters are undefined if
@@ -1091,9 +974,9 @@ DNSServiceErrorType DNSSD_API DNSServiceRegisterRecord
  *
  * fullname:        The resource record's full domain name.
  *
- * rrtype:          The resource record's type (e.g. kDNSServiceType_PTR, kDNSServiceType_SRV, etc)
+ * rrtype:          The resource record's type (e.g. PTR, SRV, etc) as defined in nameser.h.
  *
- * rrclass:         The class of the resource record (usually kDNSServiceClass_IN).
+ * rrclass:         The class of the resource record, as defined in nameser.h (usually 1).
  *
  * rdlen:           The length, in bytes, of the resource record rdata.
  *
@@ -1105,7 +988,7 @@ DNSServiceErrorType DNSSD_API DNSServiceRegisterRecord
  *
  */
 
-typedef void (DNSSD_API *DNSServiceQueryRecordReply)
+typedef void (*DNSServiceQueryRecordReply)
     (
     DNSServiceRef                       DNSServiceRef,
     DNSServiceFlags                     flags,
@@ -1123,10 +1006,7 @@ 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.
  *
  * flags:           Pass kDNSServiceFlagsLongLivedQuery to create a "long-lived" unicast
  *                  query in a non-local domain.  Without setting this flag, unicast queries
@@ -1138,14 +1018,16 @@ typedef void (DNSSD_API *DNSServiceQueryRecordReply)
  * interfaceIndex:  If non-zero, specifies the interface on which to issue the query
  *                  (the index for a given interface is determined via the if_nametoindex()
  *                  family of calls.)  Passing 0 causes the name to be queried for on all
- *                  interfaces. See "Constants for specifying an interface index" for more details.
+ *                  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. kDNSServiceType_PTR, kDNSServiceType_SRV, etc)
+ * 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 (usually kDNSServiceClass_IN).
+ * rrclass:         The class of the resource record, as defined in nameser.h
+ *                  (usually 1 for the Internet class).
  *
  * callBack:        The function to be called when a result is found, or if the call
  *                  asynchronously fails.
@@ -1159,7 +1041,7 @@ typedef void (DNSSD_API *DNSServiceQueryRecordReply)
  *                  is not initialized.)
  */
 
-DNSServiceErrorType DNSSD_API DNSServiceQueryRecord
+DNSServiceErrorType DNSServiceQueryRecord
     (
     DNSServiceRef                       *sdRef,
     DNSServiceFlags                     flags,
@@ -1183,14 +1065,11 @@ DNSServiceErrorType DNSSD_API DNSServiceQueryRecord
  *
  * flags:           Currently unused, reserved for future use.
  *
- * interfaceIndex:  If non-zero, specifies the interface of the record in question.
- *                  Passing 0 causes all instances of this record to be reconfirmed.
- *
  * fullname:        The resource record's full domain name.
  *
- * rrtype:          The resource record's type (e.g. kDNSServiceType_PTR, kDNSServiceType_SRV, etc)
+ * rrtype:          The resource record's type (e.g. PTR, SRV, etc) as defined in nameser.h.
  *
- * rrclass:         The class of the resource record (usually kDNSServiceClass_IN).
+ * rrclass:         The class of the resource record, as defined in nameser.h (usually 1).
  *
  * rdlen:           The length, in bytes, of the resource record rdata.
  *
@@ -1198,7 +1077,7 @@ DNSServiceErrorType DNSSD_API DNSServiceQueryRecord
  *
  */
 
-void DNSSD_API DNSServiceReconfirmRecord
+void DNSServiceReconfirmRecord
     (
     DNSServiceFlags                    flags,
     uint32_t                           interfaceIndex,
@@ -1228,21 +1107,21 @@ void DNSSD_API DNSServiceReconfirmRecord
  *                  The buffer must be kDNSServiceMaxDomainName (1005) bytes in length to
  *                  accommodate the longest legal domain name without buffer overrun.
  *
- * service:         The service name - any dots or backslashes must NOT be escaped.
+ * service:         The service name - any dots or slashes must NOT be escaped.
  *                  May be NULL (to construct a PTR record name, e.g.
- *                  "_ftp._tcp.apple.com.").
+ *                  "_ftp._tcp.apple.com").
  *
  * regtype:         The service type followed by the protocol, separated by a dot
  *                  (e.g. "_ftp._tcp").
  *
- * domain:          The domain name, e.g. "apple.com.".  Literal dots or backslashes,
- *                  if any, must be escaped, e.g. "1st\. Floor.apple.com."
+ * domain:          The domain name, e.g. "apple.com".  Any literal dots or backslashes
+ *                  must be escaped.
  *
  * return value:    Returns 0 on success, -1 on error.
  *
  */
 
-int DNSSD_API DNSServiceConstructFullName
+int DNSServiceConstructFullName
     (
     char                            *fullName,
     const char                      *service,      /* may be NULL */
@@ -1278,7 +1157,7 @@ int DNSSD_API DNSServiceConstructFullName
  * Note: Represents a DNS-SD TXT record.
  */
 
-typedef struct _TXTRecordRef_t { char privatedata[16]; } TXTRecordRef;
+typedef struct _TXTRecordRef_t { char private[16]; } TXTRecordRef;
 
 
 /* TXTRecordCreate()
@@ -1308,11 +1187,6 @@ typedef struct _TXTRecordRef_t { char privatedata[16]; } TXTRecordRef;
  * Recommended size limits for DNS-SD TXT Records are discussed in
  * <http://files.dns-sd.org/draft-cheshire-dnsext-dns-sd.txt>
  *
- * Note: When passing parameters to and from these TXT record APIs,
- * the key name does not include the '=' character. The '=' character
- * is the separator between the key and value in the on-the-wire
- * packet format; it is not part of either the key or the value.
- *
  * txtRecord:       A pointer to an uninitialized TXTRecordRef.
  *
  * bufferLen:       The size of the storage provided in the "buffer" parameter.
@@ -1322,7 +1196,7 @@ typedef struct _TXTRecordRef_t { char privatedata[16]; } TXTRecordRef;
  *                  the TXTRecordRef.
  */
 
-void DNSSD_API TXTRecordCreate
+void TXTRecordCreate
     (
     TXTRecordRef     *txtRecord,
     uint16_t         bufferLen,
@@ -1340,7 +1214,7 @@ void DNSSD_API TXTRecordCreate
  *
  */
 
-void DNSSD_API TXTRecordDeallocate
+void TXTRecordDeallocate
     (
     TXTRecordRef     *txtRecord
     );
@@ -1363,7 +1237,7 @@ void DNSSD_API TXTRecordDeallocate
  *
  * key:             A null-terminated string which only contains printable ASCII
  *                  values (0x20-0x7E), excluding '=' (0x3D). Keys should be
- *                  8 characters or less (not counting the terminating null).
+ *                  14 characters or less (not counting the terminating null).
  *
  * valueSize:       The size of the value.
  *
@@ -1383,7 +1257,7 @@ void DNSSD_API TXTRecordDeallocate
  *                  exceed the available storage.
  */
 
-DNSServiceErrorType DNSSD_API TXTRecordSetValue
+DNSServiceErrorType TXTRecordSetValue
     (
     TXTRecordRef     *txtRecord,
     const char       *key,
@@ -1407,7 +1281,7 @@ DNSServiceErrorType DNSSD_API TXTRecordSetValue
  *
  */
 
-DNSServiceErrorType DNSSD_API TXTRecordRemoveValue
+DNSServiceErrorType TXTRecordRemoveValue
     (
     TXTRecordRef     *txtRecord,
     const char       *key
@@ -1427,7 +1301,7 @@ DNSServiceErrorType DNSSD_API TXTRecordRemoveValue
  *
  */
 
-uint16_t DNSSD_API TXTRecordGetLength
+uint16_t TXTRecordGetLength
     (
     const TXTRecordRef *txtRecord
     );
@@ -1445,7 +1319,7 @@ uint16_t DNSSD_API TXTRecordGetLength
  *
  */
 
-const void * DNSSD_API TXTRecordGetBytesPtr
+const void * TXTRecordGetBytesPtr
     (
     const TXTRecordRef *txtRecord
     );
@@ -1500,7 +1374,7 @@ const void * DNSSD_API TXTRecordGetBytesPtr
  *
  */
 
-int DNSSD_API TXTRecordContainsKey
+int TXTRecordContainsKey
     (
     uint16_t         txtLen,
     const void       *txtRecord,
@@ -1529,7 +1403,7 @@ int DNSSD_API TXTRecordContainsKey
  *                  For non-empty value, valueLen will be length of value data.
  */
 
-const void * DNSSD_API TXTRecordGetValuePtr
+const void * TXTRecordGetValuePtr
     (
     uint16_t         txtLen,
     const void       *txtRecord,
@@ -1551,7 +1425,7 @@ const void * DNSSD_API TXTRecordGetValuePtr
  *
  */
 
-uint16_t DNSSD_API TXTRecordGetCount
+uint16_t TXTRecordGetCount
     (
     uint16_t         txtLen,
     const void       *txtRecord
@@ -1582,7 +1456,7 @@ uint16_t DNSSD_API TXTRecordGetCount
  * key:             A string buffer used to store the key name.
  *                  On return, the buffer contains a null-terminated C string
  *                  giving the key name. DNS-SD TXT keys are usually
- *                  8 characters or less. To hold the maximum possible
+ *                  14 characters or less. To hold the maximum possible
  *                  key name, the buffer should be 256 bytes long.
  *
  * valueLen:        On output, will be set to the size of the "value" data.
@@ -1596,7 +1470,7 @@ uint16_t DNSSD_API TXTRecordGetCount
  *                  TXTRecordGetCount()-1.
  */
 
-DNSServiceErrorType DNSSD_API TXTRecordGetItemAtIndex
+DNSServiceErrorType TXTRecordGetItemAtIndex
     (
     uint16_t         txtLen,
     const void       *txtRecord,
@@ -1607,39 +1481,6 @@ DNSServiceErrorType DNSSD_API TXTRecordGetItemAtIndex
     const void       **value
     );
 
-#ifdef __APPLE_API_PRIVATE
-
-/*
- * Mac OS X specific functionality
- * 3rd party clients of this API should not depend on future support or availability of this routine
- */
-
-/* DNSServiceSetDefaultDomainForUser()
- *
- * Set the default domain for the caller's UID.  Future browse and registration
- * calls by this user that do not specify an explicit domain will browse and
- * register in this wide-area domain in addition to .local.  In addition, this
- * domain will be returned as a Browse domain via domain enumeration calls.
- * 
- *
- * Parameters:
- *
- * flags:           Pass kDNSServiceFlagsAdd to add a domain for a user.  Call without
- *                  this flag set to clear a previously added domain.
- *
- * domain:          The domain to be used for the caller's UID.
- *
- * return value:    Returns kDNSServiceErr_NoError on succeses, otherwise returns
- *                  an error code indicating the error that occurred
- */
-
-DNSServiceErrorType DNSSD_API DNSServiceSetDefaultDomainForUser
-    (
-    DNSServiceFlags                    flags,
-    const char                         *domain
-    ); 
-       
-#endif //__APPLE_API_PRIVATE
 
 #ifdef  __cplusplus
     }
diff --git a/mDNSShared/dnssd_clientlib.c b/mDNSShared/dnssd_clientlib.c
new file mode 100755 (executable)
index 0000000..d5a0f04
--- /dev/null
@@ -0,0 +1,342 @@
+/*
+ * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+   Change History (most recent first):
+
+$Log: dnssd_clientlib.c,v $
+Revision 1.5  2004/05/25 18:29:33  cheshire
+Move DNSServiceConstructFullName() from dnssd_clientstub.c to dnssd_clientlib.c,
+so that it's also accessible to dnssd_clientshim.c (single address space) clients.
+
+Revision 1.4  2004/05/25 17:08:55  cheshire
+Fix compiler warning (doesn't make sense for function return type to be const)
+
+Revision 1.3  2004/05/21 21:41:35  cheshire
+Add TXT record building and parsing APIs
+
+Revision 1.2  2004/05/20 22:22:21  cheshire
+Enable code that was bracketed by "#if 0"
+
+Revision 1.1  2004/03/12 21:30:29  cheshire
+Build a System-Context Shared Library from mDNSCore, for the benefit of developers
+like Muse Research who want to be able to use mDNS/DNS-SD from GPL-licensed code.
+
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "dns_sd.h"
+
+#if MDNS_BUILDINGSHAREDLIBRARY || MDNS_BUILDINGSTUBLIBRARY
+#pragma export on
+#endif
+
+/*********************************************************************************************
+ *
+ *  Supporting Functions
+ *
+ *********************************************************************************************/
+
+#define mdnsIsDigit(X)     ((X) >= '0' && (X) <= '9')
+
+static int DomainEndsInDot(const char *dom)
+       {
+       while (dom[0] && dom[1])
+               {
+               if (dom[0] == '\\') // advance past escaped byte sequence
+                       {
+                       if (mdnsIsDigit(dom[1]) && mdnsIsDigit(dom[2]) && mdnsIsDigit(dom[3]))
+                               dom += 4;                       // If "\ddd"    then skip four
+                       else dom += 2;                  // else if "\x" then skip two
+                       }
+               else dom++;                                     // else goto next character
+               }
+       return (dom[0] == '.');
+       }
+
+static uint8_t *InternalTXTRecordSearch
+       (
+       uint16_t         txtLen,
+       const void       *txtRecord,
+       const char       *key,
+       unsigned long    *keylen
+       )
+       {
+       uint8_t *p = (uint8_t*)txtRecord;
+       uint8_t *e = p + txtLen;
+       *keylen = strlen(key);
+       while (p<e)
+               {
+               uint8_t *x = p;
+               p += 1 + p[0];
+               if (p <= e && *keylen <= x[0] && !strncmp(key, (char*)x+1, *keylen))
+                       if (*keylen == x[0] || x[1+*keylen] == '=') return(x);
+               }
+       return(NULL);
+       }
+
+/*********************************************************************************************
+ *
+ *  General Utility Functions
+ *
+ *********************************************************************************************/
+
+int DNSServiceConstructFullName
+       (
+       char                      *fullName,
+       const char                *service,      /* may be NULL */
+       const char                *regtype,
+       const char                *domain
+       )
+       {
+       unsigned long len;
+       unsigned char c;
+       char *fn = fullName;
+       const char *s = service;
+       const char *r = regtype;
+       const char *d = domain;
+
+       if (service)
+               {
+               while(*s)
+                       {
+                       c = (unsigned char)*s++;
+                       if (c == '.' || (c == '\\')) *fn++ = '\\'; // escape dot and backslash literals
+                       else if (c <= ' ') // escape non-printable characters
+                               {
+                               *fn++ = '\\';
+                               *fn++ = (char) ('0' + (c / 100));
+                               *fn++ = (char) ('0' + (c / 10) % 10);
+                               c = (unsigned char)('0' + (c % 10));
+                               }
+                       *fn++ = (char)c;
+                       }
+               *fn++ = '.';
+               }
+
+       if (!regtype) return -1;
+       len = strlen(regtype);
+       if (DomainEndsInDot(regtype)) len--;
+       if (len < 6) return -1; // regtype must be at least "x._udp" or "x._tcp"
+       if (strncmp((regtype + len - 4), "_tcp", 4) && strncmp((regtype + len - 4), "_udp", 4)) return -1;
+       while(*r) *fn++ = *r++;
+       if (!DomainEndsInDot(regtype)) *fn++ = '.';
+
+       if (!domain || !domain[0]) return -1;
+       while(*d) *fn++ = *d++;
+       if (!DomainEndsInDot(domain)) *fn++ = '.';
+       *fn = '\0';
+       return 0;
+       }
+
+/*********************************************************************************************
+ *
+ *   TXT Record Construction Functions
+ *
+ *********************************************************************************************/
+
+typedef struct _TXTRecordRefRealType
+       {
+       uint8_t  *buffer;               // Pointer to data
+       uint16_t buflen;                // Length of buffer
+       uint16_t datalen;               // Length currently in use
+       uint16_t malloced;      // Non-zero if buffer was allocated via malloc()
+       } TXTRecordRefRealType;
+
+#define txtRec ((TXTRecordRefRealType*)txtRecord)
+
+// The opaque storage defined in the public dns_sd.h header is 16 bytes;
+// make sure we don't exceed that.
+struct dnssd_clientlib_CompileTimeAssertionCheck
+       {
+       char assert0[(sizeof(TXTRecordRefRealType) <= 16) ? 1 : -1];
+       };
+
+void TXTRecordCreate
+       (
+       TXTRecordRef     *txtRecord,
+       uint16_t         bufferLen,
+       void             *buffer
+       )
+       {
+       txtRec->buffer   = buffer;
+       txtRec->buflen   = buffer ? bufferLen : (uint16_t)0;
+       txtRec->datalen  = 0;
+       txtRec->malloced = 0;
+       }
+
+void TXTRecordDeallocate(TXTRecordRef *txtRecord)
+       {
+       if (txtRec->malloced) free(txtRec->buffer);
+       }
+
+DNSServiceErrorType TXTRecordSetValue
+       (
+       TXTRecordRef     *txtRecord,
+       const char       *key,
+       uint8_t          valueSize,
+       const void       *value
+       )
+       {
+       uint8_t *start, *p;
+       const char *k;
+       unsigned long keysize, keyvalsize;
+
+       for (k = key; *k; k++) if (*k < 0x20 || *k > 0x7E || *k == '=') return(kDNSServiceErr_Invalid);
+       keysize = (unsigned long)(k - key);
+       keyvalsize = 1 + keysize + (value ? (1 + valueSize) : 0);
+       if (keysize < 1 || keyvalsize > 255) return(kDNSServiceErr_Invalid);
+       (void)TXTRecordRemoveValue(txtRecord, key);
+       if (txtRec->datalen + keyvalsize > txtRec->buflen)
+               {
+               unsigned char *newbuf;
+               unsigned long newlen = txtRec->datalen + keyvalsize;
+               if (newlen > 0xFFFF) return(kDNSServiceErr_Invalid);
+               newbuf = malloc((size_t)newlen);
+               if (!newbuf) return(kDNSServiceErr_NoMemory);
+               memcpy(newbuf, txtRec->buffer, txtRec->datalen);
+               if (txtRec->malloced) free(txtRec->buffer);
+               txtRec->buffer = newbuf;
+               txtRec->buflen = (uint16_t)(newlen);
+               txtRec->malloced = 1;
+               }
+       start = txtRec->buffer + txtRec->datalen;
+       p = start + 1;
+       memcpy(p, key, keysize);
+       p += keysize;
+       if (value)
+               {
+               *p++ = '=';
+               memcpy(p, value, valueSize);
+               p += valueSize;
+               }
+       *start = (uint8_t)(p - start - 1);
+       txtRec->datalen += p - start;
+       return(kDNSServiceErr_NoError);
+       }
+
+DNSServiceErrorType TXTRecordRemoveValue
+       (
+       TXTRecordRef     *txtRecord,
+       const char       *key
+       )
+       {
+       unsigned long keylen, itemlen, remainder;
+       uint8_t *item = InternalTXTRecordSearch(txtRec->datalen, txtRec->buffer, key, &keylen);
+       if (!item) return(kDNSServiceErr_NoSuchKey);
+       itemlen   = (unsigned long)(1 + item[0]);
+       remainder = (unsigned long)((txtRec->buffer + txtRec->datalen) - (item + itemlen));
+       // Use memmove because memcpy behaviour is undefined for overlapping regions
+       memmove(item, item + itemlen, remainder);
+       txtRec->datalen -= itemlen;
+       return(kDNSServiceErr_NoError);
+       }
+
+uint16_t       TXTRecordGetLength  (const TXTRecordRef *txtRecord) { return(txtRec->datalen); }
+const void *   TXTRecordGetBytesPtr(const TXTRecordRef *txtRecord) { return(txtRec->buffer); }
+
+/*********************************************************************************************
+ *
+ *   TXT Record Parsing Functions
+ *
+ *********************************************************************************************/
+
+int TXTRecordContainsKey
+       (
+       uint16_t         txtLen,
+       const void       *txtRecord,
+       const char       *key
+       )
+       {
+       unsigned long keylen;
+       return (InternalTXTRecordSearch(txtLen, txtRecord, key, &keylen) ? 1 : 0);
+       }
+
+const void * TXTRecordGetValuePtr
+       (
+       uint16_t         txtLen,
+       const void       *txtRecord,
+       const char       *key,
+       uint8_t          *valueLen
+       )
+       {
+       unsigned long keylen;
+       uint8_t *item = InternalTXTRecordSearch(txtLen, txtRecord, key, &keylen);
+       if (!item || item[0] <= keylen) return(NULL);   // If key not found, or found with no value, return NULL
+       *valueLen = (uint8_t)(item[0] - (keylen + 1));
+       return (item + 1 + keylen + 1);
+       }
+
+uint16_t TXTRecordGetCount
+       (
+       uint16_t         txtLen,
+       const void       *txtRecord
+       )
+       {
+       uint16_t count = 0;
+       uint8_t *p = (uint8_t*)txtRecord;
+       uint8_t *e = p + txtLen;
+       while (p<e) { p += 1 + p[0]; count++; }
+       return((p>e) ? (uint16_t)0 : count);
+       }
+
+DNSServiceErrorType TXTRecordGetItemAtIndex
+       (
+       uint16_t         txtLen,
+       const void       *txtRecord,
+       uint16_t         index,
+       uint16_t         keyBufLen,
+       char             *key,
+       uint8_t          *valueLen,
+       const void       **value
+       )
+       {
+       uint16_t count = 0;
+       uint8_t *p = (uint8_t*)txtRecord;
+       uint8_t *e = p + txtLen;
+       while (p<e && count<index) { p += 1 + p[0]; count++; }  // Find requested item
+       if (p<e && p + 1 + p[0] <= e)   // If valid
+               {
+               uint8_t *x = p+1;
+               unsigned long len = 0;
+               e = p + 1 + p[0];
+               while (x+len<e && x[len] != '=') len++;
+               if (len >= keyBufLen) return(kDNSServiceErr_NoMemory);
+               memcpy(key, x, len);
+               key[len] = 0;
+               if (x+len<e)            // If we found '='
+                       {
+                       *value = x + len + 1;
+                       *valueLen = (uint8_t)(p[0] - (len + 1));
+                       }
+               else
+                       {
+                       *value = NULL;
+                       *valueLen = 0;
+                       }
+               return(kDNSServiceErr_NoError);
+               }
+       return(kDNSServiceErr_Invalid);
+       }
diff --git a/mDNSShared/dnssd_clientshim.c b/mDNSShared/dnssd_clientshim.c
new file mode 100644 (file)
index 0000000..98b187f
--- /dev/null
@@ -0,0 +1,699 @@
+/*
+ * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
+ * 
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+ * This file defines a simple shim layer between a client calling the "/usr/include/dns_sd.h" APIs
+ * and an implementation of mDNSCore ("mDNSClientAPI.h" APIs) in the same address space.
+ * When the client calls a dns_sd.h function, the shim calls the corresponding mDNSClientAPI.h
+ * function, and when mDNSCore calls the shim's callback, we call through to the client's callback.
+ * The shim is responsible for two main things:
+ * - converting string parameters between C string format and native DNS format,
+ * - and for allocating and freeing memory.
+
+       Change History (most recent first):
+
+$Log: dnssd_clientshim.c,v $
+Revision 1.3  2004/05/27 06:26:31  cheshire
+Add shim for DNSServiceQueryRecord()
+
+Revision 1.2  2004/05/20 18:41:24  cheshire
+Fix build broken by removal of 'kDNSServiceFlagsRemove' from dns_sd.h
+
+Revision 1.1  2004/03/12 21:30:29  cheshire
+Build a System-Context Shared Library from mDNSCore, for the benefit of developers
+like Muse Research who want to be able to use mDNS/DNS-SD from GPL-licensed code.
+
+ */
+
+#include "dns_sd.h"                            // Defines the interface to the client layer above
+#include "mDNSClientAPI.h"             // The interface we're building on top of
+extern mDNS mDNSStorage;               // We need to pass the address of this storage to the lower-layer functions
+
+#if MDNS_BUILDINGSHAREDLIBRARY || MDNS_BUILDINGSTUBLIBRARY
+#pragma export on
+#endif
+
+//*************************************************************************************************************
+// General Utility Functions
+
+// All mDNS_DirectOP structures start with the pointer to the type-specific disposal function.
+// Optional type-specific data follows these three fields
+// When the client starts an operation, we return the address of the corresponding mDNS_DirectOP
+// as the DNSServiceRef for the operation
+// We stash the value in core context fields so we can get it back to recover our state in our callbacks,
+// and pass it though to the client for it to recover its state
+
+typedef struct mDNS_DirectOP_struct mDNS_DirectOP;
+typedef void mDNS_DirectOP_Dispose(mDNS_DirectOP *op);
+struct mDNS_DirectOP_struct
+       {
+       mDNS_DirectOP_Dispose  *disposefn;
+       };
+
+typedef struct
+       {
+       mDNS_DirectOP_Dispose  *disposefn;
+       DNSServiceRegisterReply callback;
+       void                   *context;
+       mDNSBool                autoname;
+       mDNSBool                autorename;
+       domainlabel             name;
+       ServiceRecordSet        s;
+       } mDNS_DirectOP_Register;
+
+typedef struct
+       {
+       mDNS_DirectOP_Dispose  *disposefn;
+       DNSServiceBrowseReply   callback;
+       void                   *context;
+       DNSQuestion             q;
+       } mDNS_DirectOP_Browse;
+
+typedef struct
+       {
+       mDNS_DirectOP_Dispose  *disposefn;
+       DNSServiceResolveReply  callback;
+       void                   *context;
+       const ResourceRecord   *SRV;
+       const ResourceRecord   *TXT;
+       DNSQuestion             qSRV;
+       DNSQuestion             qTXT;
+       } mDNS_DirectOP_Resolve;
+
+typedef struct
+       {
+       mDNS_DirectOP_Dispose      *disposefn;
+       DNSServiceQueryRecordReply  callback;
+       void                       *context;
+       DNSQuestion                 q;
+       } mDNS_DirectOP_QueryRecord;
+
+int DNSServiceRefSockFD(DNSServiceRef sdRef)
+       {
+       (void)sdRef;    // Unused
+       return(0);
+       }
+
+DNSServiceErrorType DNSServiceProcessResult(DNSServiceRef sdRef)
+       {
+       (void)sdRef;    // Unused
+       return(kDNSServiceErr_NoError);
+       }
+
+void DNSServiceRefDeallocate(DNSServiceRef sdRef)
+       {
+       mDNS_DirectOP *op = (mDNS_DirectOP *)sdRef;
+       //LogMsg("DNSServiceRefDeallocate");
+       op->disposefn(op);
+       }
+
+//*************************************************************************************************************
+// Domain Enumeration
+
+// Not yet implemented, so don't include in stub library
+// We DO include it in the actual Extension, so that if a later client compiled to use this
+// is run against this Extension, it will get a reasonable error code instead of just
+// failing to launch (Strong Link) or calling an unresolved symbol and crashing (Weak Link)
+#if !MDNS_BUILDINGSTUBLIBRARY
+DNSServiceErrorType DNSServiceEnumerateDomains
+       (
+       DNSServiceRef                       *sdRef,
+       DNSServiceFlags                     flags,
+       uint32_t                            interfaceIndex,
+       DNSServiceDomainEnumReply           callback,
+       void                                *context  /* may be NULL */
+       )
+       {
+       (void)sdRef;                    // Unused
+       (void)flags;                    // Unused
+       (void)interfaceIndex;   // Unused
+       (void)callback;                 // Unused
+       (void)context;                  // Unused
+       return(kDNSServiceErr_Unsupported);
+       }
+#endif
+
+//*************************************************************************************************************
+// Register Service
+
+mDNSlocal void FreeDNSServiceRegistration(mDNS_DirectOP_Register *x)
+       {
+       while (x->s.Extras)
+               {
+               ExtraResourceRecord *extras = x->s.Extras;
+               x->s.Extras = x->s.Extras->next;
+               if (extras->r.resrec.rdata != &extras->r.rdatastorage)
+                       mDNSPlatformMemFree(extras->r.resrec.rdata);
+               mDNSPlatformMemFree(extras);
+               }
+
+       if (x->s.RR_TXT.resrec.rdata != &x->s.RR_TXT.rdatastorage)
+                       mDNSPlatformMemFree(x->s.RR_TXT.resrec.rdata);
+
+       if (x->s.SubTypes) mDNSPlatformMemFree(x->s.SubTypes);
+       
+       mDNSPlatformMemFree(x);
+       }
+
+static void DNSServiceRegisterDispose(mDNS_DirectOP *op)
+       {
+       mDNS_DirectOP_Register *x = (mDNS_DirectOP_Register*)op;
+       x->autorename = mDNSfalse;
+       // If mDNS_DeregisterService() returns mStatus_NoError, that means that the service was found in the list,
+       // is sending its goodbye packet, and we'll get an mStatus_MemFree message when we can free the memory.
+       // If mDNS_DeregisterService() returns an error, it means that the service had already been removed from
+       // the list, so we should go ahead and free the memory right now
+       if (mDNS_DeregisterService(&mDNSStorage, &x->s) != mStatus_NoError)
+               FreeDNSServiceRegistration(x);
+       }
+
+mDNSlocal void RegCallback(mDNS *const m, ServiceRecordSet *const sr, mStatus result)
+       {
+       mDNS_DirectOP_Register *x = (mDNS_DirectOP_Register*)sr->ServiceContext;
+
+    domainlabel name;
+    domainname type, dom;
+       char namestr[MAX_DOMAIN_LABEL+1];               // Unescaped name: up to 63 bytes plus C-string terminating NULL.
+       char typestr[MAX_ESCAPED_DOMAIN_NAME];
+       char domstr [MAX_ESCAPED_DOMAIN_NAME];
+    if (!DeconstructServiceName(&sr->RR_SRV.resrec.name, &name, &type, &dom)) return;
+    if (!ConvertDomainLabelToCString_unescaped(&name, namestr)) return;
+    if (!ConvertDomainNameToCString(&type, typestr)) return;
+    if (!ConvertDomainNameToCString(&dom, domstr)) return;
+
+       if (result == mStatus_NoError)
+               {
+               if (x->callback)
+                       x->callback((DNSServiceRef)x, 0, result, namestr, typestr, domstr, x->context);
+               }
+       else if (result == mStatus_NameConflict)
+               {
+               if (x->autoname) mDNS_RenameAndReregisterService(m, sr, mDNSNULL);
+               else if (x->callback)
+                               x->callback((DNSServiceRef)x, 0, result, namestr, typestr, domstr, x->context);
+               }
+       else if (result == mStatus_MemFree)
+               {
+               if (x->autorename)
+                       {
+                       x->autorename = mDNSfalse;
+                       x->name = mDNSStorage.nicelabel;
+                       mDNS_RenameAndReregisterService(m, &x->s, &x->name);
+                       }
+               else
+                       FreeDNSServiceRegistration(x);
+               }
+       }
+
+DNSServiceErrorType DNSServiceRegister
+       (
+       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                            notAnIntPort,
+       uint16_t                            txtLen,
+       const void                          *txtRecord,    /* may be NULL */
+       DNSServiceRegisterReply             callback,      /* may be NULL */
+       void                                *context       /* may be NULL */
+       )
+       {
+       mStatus err = mStatus_NoError;
+       const char *errormsg = "Unknown";
+       domainlabel n;
+       domainname t, d, h, srv;
+       mDNSIPPort port;
+       unsigned int size = sizeof(RDataBody);
+       AuthRecord *SubTypes = mDNSNULL;
+       mDNSu32 NumSubTypes = 0;
+       mDNS_DirectOP_Register *x;
+       (void)flags;                    // Unused
+       (void)interfaceIndex;   // Unused
+
+       // Check parameters
+       if (!name[0]) n = mDNSStorage.nicelabel;
+       else if (!MakeDomainLabelFromLiteralString(&n, name))                              { errormsg = "Bad Instance Name"; goto badparam; }
+       if (!regtype || !*regtype || !MakeDomainNameFromDNSNameString(&t, regtype))        { errormsg = "Bad Service Type";  goto badparam; }
+       if (!MakeDomainNameFromDNSNameString(&d, (domain && *domain) ? domain : "local.")) { errormsg = "Bad Domain";        goto badparam; }
+       if (!MakeDomainNameFromDNSNameString(&h, (host   && *host  ) ? host   : ""))       { errormsg = "Bad Target Host";   goto badparam; }
+       if (!ConstructServiceName(&srv, &n, &t, &d))                                       { errormsg = "Bad Name";          goto badparam; }
+       port.NotAnInteger = notAnIntPort;
+
+       // Allocate memory, and handle failure
+       if (size < txtLen)
+               size = txtLen;
+       x = (mDNS_DirectOP_Register *)mDNSPlatformMemAllocate(sizeof(*x) - sizeof(RDataBody) + size);
+       if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; }
+
+       // Set up object
+       x->disposefn = DNSServiceRegisterDispose;
+       x->callback  = callback;
+       x->context   = context;
+       x->autoname = (!name[0]);
+       x->autorename = mDNSfalse;
+       x->name = n;
+
+       // Do the operation
+       err = mDNS_RegisterService(&mDNSStorage, &x->s,
+               &x->name, &t, &d,               // Name, type, domain
+               &h, port,                               // Host and port
+               txtRecord, txtLen,              // TXT data, length
+               SubTypes, NumSubTypes,  // Subtypes
+               mDNSInterface_Any,              // Interface ID
+               RegCallback, x);                // Callback and context
+       if (err) { mDNSPlatformMemFree(x); errormsg = "mDNS_RegisterService"; goto fail; }
+
+       // Succeeded: Wrap up and return
+       *sdRef = (DNSServiceRef)x;
+       return(mStatus_NoError);
+
+badparam:
+       err = mStatus_BadParamErr;
+fail:
+       LogMsg("DNSServiceBrowse(\"%s\", \"%s\") failed: %s (%ld)", regtype, domain, errormsg, err);
+       return(err);
+       }
+
+//*************************************************************************************************************
+// Add / Update / Remove records from existing Registration
+
+// Not yet implemented, so don't include in stub library
+// We DO include it in the actual Extension, so that if a later client compiled to use this
+// is run against this Extension, it will get a reasonable error code instead of just
+// failing to launch (Strong Link) or calling an unresolved symbol and crashing (Weak Link)
+#if !MDNS_BUILDINGSTUBLIBRARY
+DNSServiceErrorType DNSServiceAddRecord
+       (
+       DNSServiceRef                       sdRef,
+       DNSRecordRef                        *RecordRef,
+       DNSServiceFlags                     flags,
+       uint16_t                            rrtype,
+       uint16_t                            rdlen,
+       const void                          *rdata,
+       uint32_t                            ttl
+       )
+       {
+       (void)sdRef;            // Unused
+       (void)RecordRef;        // Unused
+       (void)flags;            // Unused
+       (void)rrtype;           // Unused
+       (void)rdlen;            // Unused
+       (void)rdata;            // Unused
+       (void)ttl;                      // Unused
+       return(kDNSServiceErr_Unsupported);
+       }
+
+DNSServiceErrorType DNSServiceUpdateRecord
+       (
+       DNSServiceRef                       sdRef,
+       DNSRecordRef                        RecordRef,     /* may be NULL */
+       DNSServiceFlags                     flags,
+       uint16_t                            rdlen,
+       const void                          *rdata,
+       uint32_t                            ttl
+       )
+       {
+       (void)sdRef;            // Unused
+       (void)RecordRef;        // Unused
+       (void)flags;            // Unused
+       (void)rdlen;            // Unused
+       (void)rdata;            // Unused
+       (void)ttl;                      // Unused
+       return(kDNSServiceErr_Unsupported);
+       }
+
+DNSServiceErrorType DNSServiceRemoveRecord
+       (
+       DNSServiceRef                 sdRef,
+       DNSRecordRef                  RecordRef,
+       DNSServiceFlags               flags
+       )
+       {
+       (void)sdRef;            // Unused
+       (void)RecordRef;        // Unused
+       (void)flags;            // Unused
+       return(kDNSServiceErr_Unsupported);
+       }
+#endif
+
+//*************************************************************************************************************
+// Browse for services
+
+static void DNSServiceBrowseDispose(mDNS_DirectOP *op)
+       {
+       mDNS_DirectOP_Browse *x = (mDNS_DirectOP_Browse*)op;
+       //LogMsg("DNSServiceBrowseDispose");
+       mDNS_StopBrowse(&mDNSStorage, &x->q);
+       mDNSPlatformMemFree(x);
+       }
+
+mDNSlocal void FoundInstance(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
+       {
+       DNSServiceFlags flags = AddRecord ? kDNSServiceFlagsAdd : (DNSServiceFlags)0;
+       domainlabel name;
+       domainname type, domain;
+       char cname[MAX_DOMAIN_LABEL+1];                 // Unescaped name: up to 63 bytes plus C-string terminating NULL.
+       char ctype[MAX_ESCAPED_DOMAIN_NAME];
+       char cdom [MAX_ESCAPED_DOMAIN_NAME];
+       mDNS_DirectOP_Browse *x = (mDNS_DirectOP_Browse*)question->QuestionContext;
+       (void)m;                // Unused
+       
+       if (answer->rrtype != kDNSType_PTR)
+               { LogMsg("FoundInstance: Should not be called with rrtype %d (not a PTR record)", answer->rrtype); return; }
+       
+       if (!DeconstructServiceName(&answer->rdata->u.name, &name, &type, &domain))
+               {
+               LogMsg("FoundInstance: %##s PTR %##s received from network is not valid DNS-SD service pointer",
+                       answer->name.c, answer->rdata->u.name.c);
+               return;
+               }
+
+       ConvertDomainLabelToCString_unescaped(&name, cname);
+       ConvertDomainNameToCString(&type, ctype);
+       ConvertDomainNameToCString(&domain, cdom);
+       if (x->callback)
+               x->callback((DNSServiceRef)x, flags, 0, 0, cname, ctype, cdom, x->context);
+       }
+
+DNSServiceErrorType DNSServiceBrowse
+       (
+       DNSServiceRef                       *sdRef,
+       DNSServiceFlags                     flags,
+       uint32_t                            interfaceIndex,
+       const char                          *regtype,
+       const char                          *domain,    /* may be NULL */
+       DNSServiceBrowseReply               callback,
+       void                                *context    /* may be NULL */
+       )
+       {
+       mStatus err = mStatus_NoError;
+       const char *errormsg = "Unknown";
+       domainname t, d;
+       mDNS_DirectOP_Browse *x;
+       (void)flags;                    // Unused
+       (void)interfaceIndex;   // Unused
+
+       // Check parameters
+       if (!regtype[0] || !MakeDomainNameFromDNSNameString(&t, regtype))      { errormsg = "Illegal regtype"; goto badparam; }
+       if (!MakeDomainNameFromDNSNameString(&d, *domain ? domain : "local.")) { errormsg = "Illegal domain";  goto badparam; }
+
+       // Allocate memory, and handle failure
+       x = (mDNS_DirectOP_Browse *)mDNSPlatformMemAllocate(sizeof(*x));
+       if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; }
+
+       // Set up object
+       x->disposefn = DNSServiceBrowseDispose;
+       x->callback  = callback;
+       x->context   = context;
+       x->q.QuestionContext = x;
+
+       // Do the operation
+       err = mDNS_StartBrowse(&mDNSStorage, &x->q, &t, &d, mDNSInterface_Any, FoundInstance, x);
+       if (err) { mDNSPlatformMemFree(x); errormsg = "mDNS_StartBrowse"; goto fail; }
+
+       // Succeeded: Wrap up and return
+       *sdRef = (DNSServiceRef)x;
+       return(mStatus_NoError);
+
+badparam:
+       err = mStatus_BadParamErr;
+fail:
+       LogMsg("DNSServiceBrowse(\"%s\", \"%s\") failed: %s (%ld)", regtype, domain, errormsg, err);
+       return(err);
+       }
+
+//*************************************************************************************************************
+// Resolve Service Info
+
+static void DNSServiceResolveDispose(mDNS_DirectOP *op)
+       {
+       mDNS_DirectOP_Resolve *x = (mDNS_DirectOP_Resolve*)op;
+       if (x->qSRV.ThisQInterval >= 0) mDNS_StopQuery(&mDNSStorage, &x->qSRV);
+       if (x->qTXT.ThisQInterval >= 0) mDNS_StopQuery(&mDNSStorage, &x->qTXT);
+       mDNSPlatformMemFree(x);
+       }
+
+mDNSlocal void FoundServiceInfo(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
+       {
+       mDNS_DirectOP_Resolve *x = (mDNS_DirectOP_Resolve*)question->QuestionContext;
+       (void)m;        // Unused
+       if (!AddRecord)
+               {
+               if (answer->rrtype == kDNSType_SRV && x->SRV == answer) x->SRV = mDNSNULL;
+               if (answer->rrtype == kDNSType_TXT && x->TXT == answer) x->TXT = mDNSNULL;
+               }
+       else
+               {
+               if (answer->rrtype == kDNSType_SRV) x->SRV = answer;
+               if (answer->rrtype == kDNSType_TXT) x->TXT = answer;
+               if (x->SRV && x->TXT && x->callback)
+                       {
+                       char fullname[MAX_ESCAPED_DOMAIN_NAME], targethost[MAX_ESCAPED_DOMAIN_NAME];
+                   ConvertDomainNameToCString(&answer->name, fullname);
+                   ConvertDomainNameToCString(&x->SRV->rdata->u.srv.target, targethost);
+                       x->callback((DNSServiceRef)x, 0, 0, kDNSServiceErr_NoError, fullname, targethost,
+                               x->SRV->rdata->u.srv.port.NotAnInteger, x->TXT->rdlength, (char*)x->TXT->rdata->u.txt.c, x->context);
+                       }
+               }
+       }
+
+DNSServiceErrorType DNSServiceResolve
+       (
+       DNSServiceRef                       *sdRef,
+       DNSServiceFlags                     flags,
+       uint32_t                            interfaceIndex,
+       const char                          *name,
+       const char                          *regtype,
+       const char                          *domain,
+       DNSServiceResolveReply              callback,
+       void                                *context  /* may be NULL */
+       )
+       {
+       mStatus err = mStatus_NoError;
+       const char *errormsg = "Unknown";
+       domainlabel n;
+       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; }
+       if (!domain[0]  || !MakeDomainNameFromDNSNameString(&d, domain )) { errormsg = "Bad Domain";        goto badparam; }
+       if (!ConstructServiceName(&srv, &n, &t, &d))                      { errormsg = "Bad Name";          goto badparam; }
+
+       // Allocate memory, and handle failure
+       x = (mDNS_DirectOP_Resolve *)mDNSPlatformMemAllocate(sizeof(*x));
+       if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; }
+
+       // Set up object
+       x->disposefn = DNSServiceResolveDispose;
+       x->callback  = callback;
+       x->context   = context;
+       x->SRV       = mDNSNULL;
+       x->TXT       = mDNSNULL;
+
+       x->qSRV.ThisQInterval       = -1;               // So that DNSServiceResolveDispose() knows whether to cancel this question
+       x->qSRV.InterfaceID         = mDNSInterface_Any;
+       x->qSRV.Target              = zeroAddr;
+       AssignDomainName(x->qSRV.qname, srv);
+       x->qSRV.qtype               = kDNSType_SRV;
+       x->qSRV.qclass              = kDNSClass_IN;
+       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.Target              = zeroAddr;
+       AssignDomainName(x->qTXT.qname, srv);
+       x->qTXT.qtype               = kDNSType_TXT;
+       x->qTXT.qclass              = kDNSClass_IN;
+       x->qTXT.QuestionCallback    = FoundServiceInfo;
+       x->qTXT.QuestionContext     = x;
+
+       err = mDNS_StartQuery(&mDNSStorage, &x->qSRV);
+       if (err) { DNSServiceResolveDispose((mDNS_DirectOP*)x); errormsg = "mDNS_StartQuery qSRV"; goto fail; }
+       err = mDNS_StartQuery(&mDNSStorage, &x->qTXT);
+       if (err) { DNSServiceResolveDispose((mDNS_DirectOP*)x); errormsg = "mDNS_StartQuery qTXT"; goto fail; }
+
+       // Succeeded: Wrap up and return
+       *sdRef = (DNSServiceRef)x;
+       return(mStatus_NoError);
+
+badparam:
+       err = mStatus_BadParamErr;
+fail:
+       LogMsg("DNSServiceResolve(\"%s\", \"%s\", \"%s\") failed: %s (%ld)", name, regtype, domain, errormsg, err);
+       return(err);
+       }
+
+//*************************************************************************************************************
+// Connection-oriented calls
+
+// Not yet implemented, so don't include in stub library
+// We DO include it in the actual Extension, so that if a later client compiled to use this
+// is run against this Extension, it will get a reasonable error code instead of just
+// failing to launch (Strong Link) or calling an unresolved symbol and crashing (Weak Link)
+#if !MDNS_BUILDINGSTUBLIBRARY
+DNSServiceErrorType DNSServiceCreateConnection(DNSServiceRef *sdRef)
+       {
+       (void)sdRef;    // Unused
+       return(kDNSServiceErr_Unsupported);
+       }
+
+DNSServiceErrorType 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 */
+       )
+       {
+       (void)sdRef;                    // Unused
+       (void)RecordRef;                // Unused
+       (void)flags;                    // Unused
+       (void)interfaceIndex;   // Unused
+       (void)fullname;                 // Unused
+       (void)rrtype;                   // Unused
+       (void)rrclass;                  // Unused
+       (void)rdlen;                    // Unused
+       (void)rdata;                    // Unused
+       (void)ttl;                              // Unused
+       (void)callback;                 // Unused
+       (void)context;                  // Unused
+       return(kDNSServiceErr_Unsupported);
+       }
+#endif
+
+//*************************************************************************************************************
+// DNSServiceQueryRecord
+
+static void DNSServiceQueryRecordDispose(mDNS_DirectOP *op)
+       {
+       mDNS_DirectOP_QueryRecord *x = (mDNS_DirectOP_QueryRecord*)op;
+       if (x->q.ThisQInterval >= 0) mDNS_StopQuery(&mDNSStorage, &x->q);
+       mDNSPlatformMemFree(x);
+       }
+
+mDNSlocal void DNSServiceQueryRecordResponse(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
+       {
+       mDNS_DirectOP_QueryRecord *x = (mDNS_DirectOP_QueryRecord*)question->QuestionContext;
+       char fullname[MAX_ESCAPED_DOMAIN_NAME];
+       (void)m;        // Unused
+       ConvertDomainNameToCString(&answer->name, fullname);
+       x->callback((DNSServiceRef)x, AddRecord ? kDNSServiceFlagsAdd : (DNSServiceFlags)0, 0, kDNSServiceErr_NoError,
+               fullname, answer->rrtype, answer->rrclass, answer->rdlength, answer->rdata->u.data, answer->rroriginalttl, x->context);
+       }
+
+DNSServiceErrorType DNSServiceQueryRecord
+       (
+       DNSServiceRef                       *sdRef,
+       DNSServiceFlags                     flags,
+       uint32_t                            interfaceIndex,
+       const char                          *fullname,
+       uint16_t                            rrtype,
+       uint16_t                            rrclass,
+       DNSServiceQueryRecordReply          callback,
+       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));
+       if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; }
+
+       // Set up object
+       x->disposefn = DNSServiceQueryRecordDispose;
+       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.Target              = zeroAddr;
+       MakeDomainNameFromDNSNameString(&x->q.qname, fullname);
+       x->q.qtype               = rrtype;
+       x->q.qclass              = rrclass;
+       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; }
+
+       // Succeeded: Wrap up and return
+       *sdRef = (DNSServiceRef)x;
+       return(mStatus_NoError);
+
+badparam:
+       err = mStatus_BadParamErr;
+fail:
+       LogMsg("DNSServiceQueryRecord(\"%s\", %d, %d) failed: %s (%ld)", fullname, rrtype, rrclass, errormsg, err);
+       return(err);
+       }
+
+//*************************************************************************************************************
+// DNSServiceReconfirmRecord
+
+// Not yet implemented, so don't include in stub library
+// We DO include it in the actual Extension, so that if a later client compiled to use this
+// is run against this Extension, it will get a reasonable error code instead of just
+// failing to launch (Strong Link) or calling an unresolved symbol and crashing (Weak Link)
+#if !MDNS_BUILDINGSTUBLIBRARY
+void DNSServiceReconfirmRecord
+       (
+       DNSServiceFlags                    flags,
+       uint32_t                           interfaceIndex,
+       const char                         *fullname,
+       uint16_t                           rrtype,
+       uint16_t                           rrclass,
+       uint16_t                           rdlen,
+       const void                         *rdata
+       )
+       {
+       (void)flags;                    // Unused
+       (void)interfaceIndex;   // Unused
+       (void)fullname;                 // Unused
+       (void)rrtype;                   // Unused
+       (void)rrclass;                  // Unused
+       (void)rdlen;                    // Unused
+       (void)rdata;                    // Unused
+       }
+#endif
index 7277eda7c058decc09d8cba0a3444291a892f3ea..6173ca7b91b70116fdd40a9ea04f42fe26f970c0 100755 (executable)
@@ -3,6 +3,8 @@
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
     Change History (most recent first):
 
 $Log: dnssd_clientstub.c,v $
+Revision 1.19  2004/05/25 18:29:33  cheshire
+Move DNSServiceConstructFullName() from dnssd_clientstub.c to dnssd_clientlib.c,
+so that it's also accessible to dnssd_clientshim.c (single address space) clients.
+
+Revision 1.18  2004/05/18 23:51:27  cheshire
+Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
+
+Revision 1.17  2004/05/06 18:42:58  ksekar
+General dns_sd.h API cleanup, including the following radars:
+<rdar://problem/3592068>: Remove flags with zero value
+<rdar://problem/3479569>: Passing in NULL causes a crash.
+
+Revision 1.16  2004/03/12 22:00:37  cheshire
+Added: #include <sys/socket.h>
+
+Revision 1.15  2004/01/20 18:36:29  ksekar
+Propagated Libinfo fix for <rdar://problem/3483971>: SU:
+DNSServiceUpdateRecord() doesn't allow you to update the TXT record
+into TOT mDNSResponder.
+
+Revision 1.14  2004/01/19 22:39:17  cheshire
+Don't use "MSG_WAITALL"; it makes send() return "Invalid argument" on Linux;
+use an explicit while() loop instead. (In any case, this should only make a difference
+with non-blocking sockets, which we don't use on the client side right now.)
+
+Revision 1.13  2004/01/19 21:46:52  cheshire
+Fix compiler warning
+
+Revision 1.12  2003/12/23 20:46:47  ksekar
+<rdar://problem/3497428>: sync dnssd files between libinfo & mDNSResponder
+
+Revision 1.11  2003/12/08 21:11:42  rpantos
+Changes necessary to support mDNSResponder on Linux.
+
+Revision 1.10  2003/10/13 23:50:53  ksekar
+Updated dns_sd clientstub files to bring copies in synch with
+top-of-tree Libinfo:  A memory leak in dnssd_clientstub.c is fixed,
+and comments in dns_sd.h are improved.
+
 Revision 1.9  2003/08/15 21:30:39  cheshire
 Bring up to date with LibInfo version
 
@@ -34,8 +75,13 @@ Update to APSL 2.0
 
  */
 
+#include <errno.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+
 #include "dnssd_ipc.h"
 
+
 #define CTL_PATH_PREFIX "/tmp/dnssd_clippath."
 // error socket (if needed) is named "dnssd_clipath.[pid].xxx:n" where xxx are the
 // last 3 digits of the time (in seconds) and n is the 6-digit microsecond time
@@ -46,7 +92,6 @@ DNSServiceErrorType deliver_request(void *msg, DNSServiceRef sdr, int reuse_sd);
 static ipc_msg_hdr *create_hdr(int op, int *len, char **data_start, int reuse_socket);
 static int my_read(int sd, char *buf, int len);
 static int my_write(int sd, char *buf, int len);
-static int domain_ends_in_dot(const char *dom);
 // server response handlers
 static void handle_query_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *msg);
 static void handle_browse_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data);
@@ -63,7 +108,7 @@ typedef struct _DNSServiceRef_t
     void *app_callback;
     void *app_context;
     uint32_t max_index;  //largest assigned record index - 0 if no additl. recs registered
-    } _DNSServiceRef_t;
+    } _DNSServiceRef_t;                        
 
 typedef struct _DNSRecordRef_t
     {
@@ -102,7 +147,8 @@ DNSServiceErrorType DNSServiceProcessResult(DNSServiceRef sdRef)
     if (my_read(sdRef->sockfd, data, hdr.datalen) < 0) 
         return kDNSServiceErr_Unknown;
     sdRef->process_reply(sdRef, &hdr, data);
-    return kDNSServiceErr_Unknown;
+    free(data);
+    return kDNSServiceErr_NoError;
     }
 
 
@@ -116,14 +162,14 @@ void DNSServiceRefDeallocate(DNSServiceRef sdRef)
 
 DNSServiceErrorType DNSServiceResolve
     (
-    DNSServiceRef                       *sdRef,
+    DNSServiceRef                      *sdRef,
     const DNSServiceFlags               flags,
     const uint32_t                      interfaceIndex,
-    const char                          *name,
-    const char                          *regtype,
-    const char                          *domain,
+    const char                                 *name,
+    const char                                 *regtype,
+    const char                                 *domain,
     const DNSServiceResolveReply        callBack,
-    void                                *context
+    void                                       *context
     )
     {
     char *msg = NULL, *ptr;
@@ -135,6 +181,8 @@ DNSServiceErrorType DNSServiceResolve
     if (!sdRef) return kDNSServiceErr_BadParam;
     *sdRef = NULL;
     
+       if (!name || !regtype || !domain || !callBack) return kDNSServiceErr_BadParam;
+
     // calculate total message length
     len = sizeof(flags);
     len += sizeof(interfaceIndex);
@@ -184,18 +232,19 @@ static void handle_resolve_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *d
     uint32_t ifi;
     DNSServiceErrorType err;
     char *txtrecord;
-    
-    (void)hdr;          //unused
+    int str_error = 0;
+    (void)hdr;                 //unused
     
     flags = get_flags(&data);
     ifi = get_long(&data);
     err = get_error_code(&data);
-    get_string(&data, fullname, kDNSServiceMaxDomainName);
-    get_string(&data, target, kDNSServiceMaxDomainName);
+    if (get_string(&data, fullname, kDNSServiceMaxDomainName) < 0) str_error = 1;
+    if (get_string(&data, target, kDNSServiceMaxDomainName) < 0) str_error = 1;
     port = get_short(&data);
     txtlen = get_short(&data);
     txtrecord = get_rdata(&data, txtlen);
-    
+
+       if (!err && str_error) err = kDNSServiceErr_Unknown;
     ((DNSServiceResolveReply)sdr->app_callback)(sdr, flags, ifi, err, fullname, target, port, txtlen, txtrecord, sdr->app_context);
     }
     
@@ -204,14 +253,14 @@ static void handle_resolve_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *d
 
 DNSServiceErrorType DNSServiceQueryRecord
 (
- DNSServiceRef                          *sdRef,
- const DNSServiceFlags                   flags,
- const uint32_t                         interfaceIndex,
- const char                             *name,
- const uint16_t                         rrtype,
- const uint16_t                         rrclass,
- const DNSServiceQueryRecordReply       callBack,
- void                                   *context
+ DNSServiceRef                         *sdRef,
+ const DNSServiceFlags                  flags,
+ const uint32_t                        interfaceIndex,
+ const char                            *name,
+ const uint16_t                        rrtype,
+ const uint16_t                        rrclass,
+ const DNSServiceQueryRecordReply      callBack,
+ void                                  *context
  )
     {
     char *msg = NULL, *ptr;
@@ -269,23 +318,25 @@ static void handle_query_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *dat
     DNSServiceFlags flags;
     uint32_t interfaceIndex, ttl;
     DNSServiceErrorType errorCode;
-    char name[256]; 
+    char name[kDNSServiceMaxDomainName]; 
     uint16_t rrtype, rrclass, rdlen;
     char *rdata;
+    int str_error = 0;
     (void)hdr;//Unused
 
     flags = get_flags(&data);
     interfaceIndex = get_long(&data);
     errorCode = get_error_code(&data);
-    (get_string(&data, name, 256) < 0);
+    if (get_string(&data, name, kDNSServiceMaxDomainName) < 0) str_error = 1;
     rrtype = get_short(&data);
     rrclass = get_short(&data);
     rdlen = get_short(&data);
     rdata = get_rdata(&data, rdlen);
-    ttl = get_long(&data);
-    if (!rdata) return;
-    ((DNSServiceQueryRecordReply)sdr->app_callback)(sdr, flags, interfaceIndex, errorCode, name, rrtype, rrclass,
-                                              rdlen, rdata, ttl, sdr->app_context);
+       ttl = get_long(&data);
+
+       if (!errorCode && str_error) errorCode = kDNSServiceErr_Unknown;
+       ((DNSServiceQueryRecordReply)sdr->app_callback)(sdr, flags, interfaceIndex, errorCode, name, rrtype, rrclass,
+                                                                                                       rdlen, rdata, ttl, sdr->app_context);
     return;
     }
 
@@ -353,16 +404,19 @@ static void handle_browse_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *da
     DNSServiceFlags      flags;
     uint32_t                      interfaceIndex;
     DNSServiceErrorType      errorCode;
-    char replyName[256], replyType[256], replyDomain[256];
-        (void)hdr;//Unused
+    char replyName[256], replyType[kDNSServiceMaxDomainName], 
+        replyDomain[kDNSServiceMaxDomainName];
+    int str_error = 0;
+       (void)hdr;//Unused
 
     flags = get_flags(&data);
     interfaceIndex = get_long(&data);
     errorCode = get_error_code(&data);
-    get_string(&data, replyName, 256);
-    get_string(&data, replyType, 256);
-    get_string(&data, replyDomain, 256);
-    ((DNSServiceBrowseReply)sdr->app_callback)(sdr, flags, interfaceIndex, errorCode, replyName, replyType, replyDomain, sdr->app_context);
+    if (get_string(&data, replyName, 256) < 0) str_error = 1;
+    if (get_string(&data, replyType, kDNSServiceMaxDomainName) < 0) str_error = 1;
+    if (get_string(&data, replyDomain, kDNSServiceMaxDomainName) < 0) str_error = 1;
+       if (!errorCode && str_error) errorCode = kDNSServiceErr_Unknown;
+       ((DNSServiceBrowseReply)sdr->app_callback)(sdr, flags, interfaceIndex, errorCode, replyName, replyType, replyDomain, sdr->app_context);
     }
 
 
@@ -443,7 +497,7 @@ DNSServiceErrorType DNSServiceRegister
     
 error:
     if (msg) free(msg);
-    if (*sdRef)         { free(*sdRef);  *sdRef = NULL; }
+    if (*sdRef)        { free(*sdRef);  *sdRef = NULL; }
     return kDNSServiceErr_Unknown;
     }
 
@@ -453,15 +507,17 @@ static void handle_regservice_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char
     DNSServiceFlags flags;
     uint32_t interfaceIndex;
     DNSServiceErrorType errorCode;
-    char name[256], regtype[256], domain[256];
-        (void)hdr;//Unused
+    char name[256], regtype[kDNSServiceMaxDomainName], domain[kDNSServiceMaxDomainName];
+    int str_error = 0;
+       (void)hdr;//Unused
 
     flags = get_flags(&data);
     interfaceIndex = get_long(&data);
     errorCode = get_error_code(&data);
-    get_string(&data, name, 256);
-    get_string(&data, regtype, 256);
-    get_string(&data, domain, 256);
+    if (get_string(&data, name, 256) < 0) str_error = 1;
+    if (get_string(&data, regtype, kDNSServiceMaxDomainName) < 0) str_error = 1;
+    if (get_string(&data, domain, kDNSServiceMaxDomainName) < 0) str_error = 1;
+       if (!errorCode && str_error) errorCode = kDNSServiceErr_Unknown;
     ((DNSServiceRegisterReply)sdr->app_callback)(sdr, flags, errorCode, name, regtype, domain, sdr->app_context);
     }
 
@@ -484,7 +540,10 @@ DNSServiceErrorType DNSServiceEnumerateDomains
     if (!sdRef) return kDNSServiceErr_BadParam;
     *sdRef = NULL;
 
-    len = sizeof(DNSServiceFlags);
+       if (flags != kDNSServiceFlagsBrowseDomains && flags != kDNSServiceFlagsRegistrationDomains)
+               return kDNSServiceErr_BadParam;
+
+       len = sizeof(DNSServiceFlags);
     len += sizeof(uint32_t);
 
     hdr = create_hdr(enumeration_request, &len, &ptr, 1);
@@ -522,13 +581,15 @@ static void handle_enumeration_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, cha
     DNSServiceFlags flags;
     uint32_t interfaceIndex;
     DNSServiceErrorType err;
-    char domain[256];
-        (void)hdr;//Unused
+    char domain[kDNSServiceMaxDomainName];
+    int str_error = 0;
+       (void)hdr;//Unused
 
     flags = get_flags(&data);
     interfaceIndex = get_long(&data);
     err = get_error_code(&data);
-    get_string(&data, domain, 256);
+    if (get_string(&data, domain, kDNSServiceMaxDomainName) < 0) str_error = 1;
+       if (!err && str_error) err = kDNSServiceErr_Unknown;
     ((DNSServiceDomainEnumReply)sdr->app_callback)(sdr, flags, interfaceIndex, err, domain, sdr->app_context);
     }
 
@@ -567,18 +628,18 @@ static void handle_regrecord_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char
 
 DNSServiceErrorType DNSServiceRegisterRecord
 (
- const DNSServiceRef                    sdRef,
- DNSRecordRef                           *RecordRef,  
- const DNSServiceFlags                  flags,
- const uint32_t                         interfaceIndex,
- const char                             *fullname,
- const uint16_t                         rrtype,
- const uint16_t                         rrclass,
- const uint16_t                         rdlen,
- const void                             *rdata,
- const uint32_t                         ttl,
- const DNSServiceRegisterRecordReply    callBack,
- void                                   *context
+ const DNSServiceRef                   sdRef,
+ DNSRecordRef                          *RecordRef,  
+ const DNSServiceFlags                 flags,
+ const uint32_t                        interfaceIndex,
+ const char                            *fullname,
+ const uint16_t                        rrtype,
+ const uint16_t                        rrclass,
+ const uint16_t                        rdlen,
+ const void                            *rdata,
+ const uint32_t                        ttl,
+ const DNSServiceRegisterRecordReply   callBack,
+ void                                  *context
  )
     {
     char *msg = NULL, *ptr;
@@ -591,7 +652,10 @@ DNSServiceErrorType DNSServiceRegisterRecord
         return kDNSServiceErr_BadReference;
     *RecordRef = NULL;
     
-    len = sizeof(DNSServiceFlags);
+       if (flags != kDNSServiceFlagsShared && flags != kDNSServiceFlagsUnique)
+               return kDNSServiceErr_BadReference;
+
+       len = sizeof(DNSServiceFlags);
     len += 2 * sizeof(uint32_t);  // interfaceIndex, ttl
     len += 3 * sizeof(uint16_t);  // rrtype, rrclass, rdlen
     len += strlen(fullname) + 1;
@@ -631,13 +695,13 @@ error:
 //sdRef returned by DNSServiceRegister()
 DNSServiceErrorType DNSServiceAddRecord
     (
-    const DNSServiceRef                 sdRef,
-    DNSRecordRef                        *RecordRef,
+    const DNSServiceRef                        sdRef,
+    DNSRecordRef                       *RecordRef,
     const DNSServiceFlags               flags,
-    const uint16_t                      rrtype,
-    const uint16_t                      rdlen,
-    const void                          *rdata,
-    const uint32_t                      ttl
+    const uint16_t                     rrtype,
+    const uint16_t                     rdlen,
+    const void                         *rdata,
+    const uint32_t                     ttl
     )
     {
     ipc_msg_hdr *hdr;
@@ -684,20 +748,19 @@ error:
 //DNSRecordRef returned by DNSServiceRegisterRecord or DNSServiceAddRecord
 DNSServiceErrorType DNSServiceUpdateRecord
     (
-    const DNSServiceRef                 sdRef,
-    DNSRecordRef                        RecordRef,
+    const DNSServiceRef                sdRef,
+    DNSRecordRef                       RecordRef,
     const DNSServiceFlags               flags,
-    const uint16_t                      rdlen,
-    const void                          *rdata,
-    const uint32_t                      ttl
+    const uint16_t                     rdlen,
+    const void                         *rdata,
+    const uint32_t                     ttl
     )
     {
     ipc_msg_hdr *hdr;
     int len = 0;
     char *ptr;
 
-    if (!sdRef || !RecordRef || !sdRef->max_index) 
-        return kDNSServiceErr_BadReference;
+       if (!sdRef) return kDNSServiceErr_BadReference;
     
     len += sizeof(uint16_t);
     len += rdlen;
@@ -719,7 +782,7 @@ DNSServiceErrorType DNSServiceUpdateRecord
 DNSServiceErrorType DNSServiceRemoveRecord
 (
  const DNSServiceRef            sdRef,
- const DNSRecordRef             RecordRef,
+ const DNSRecordRef                    RecordRef,
  const DNSServiceFlags          flags
  )
     {
@@ -780,74 +843,6 @@ void DNSServiceReconfirmRecord
     }
         
         
-int DNSServiceConstructFullName 
-    (
-    char                      *fullName,
-    const char                *service,      /* may be NULL */
-    const char                *regtype,
-    const char                *domain
-    )
-    {
-    int len;
-    u_char c;
-    char *fn = fullName;
-    const char *s = service;
-    const char *r = regtype;
-    const char *d = domain;
-    
-    if (service)
-        {
-        while(*s)
-            {
-            c = *s++;
-            if (c == '.' || (c == '\\')) *fn++ = '\\';          // escape dot and backslash literals
-            else if (c <= ' ')                                  // escape non-printable characters
-                {
-                *fn++ = '\\';
-                *fn++ = (char) ('0' + (c / 100));
-                *fn++ = (char) ('0' + (c / 10) % 10);
-                c = (u_char)('0' + (c % 10));
-                }
-                *fn++ = c;
-            }
-        *fn++ = '.';
-        }
-
-    if (!regtype) return -1;
-    len = strlen(regtype);
-    if (domain_ends_in_dot(regtype)) len--;
-    if (len < 4) return -1;                                     // regtype must end in _udp or _tcp
-    if (strncmp((regtype + len - 4), "_tcp", 4) && strncmp((regtype + len - 4), "_udp", 4)) return -1;
-    while(*r)
-        *fn++ = *r++;                                                                                                                                                                                        
-    if (!domain_ends_in_dot(regtype)) *fn++ = '.';
-                                                                                        
-    if (!domain) return -1;
-    len = strlen(domain);
-    if (!len) return -1;
-    while(*d) 
-        *fn++ = *d++;                                           
-    if (!domain_ends_in_dot(domain)) *fn++ = '.';
-    *fn = '\0';
-    return 0;
-    }
-        
-static int domain_ends_in_dot(const char *dom)
-    {
-    while(*dom && *(dom + 1))
-        {
-        if (*dom == '\\')       // advance past escaped byte sequence
-            {           
-            if (*(dom + 1) >= '0' && *(dom + 1) <= '9') dom += 4;
-            else dom += 2;
-            }
-        else dom++;             // else read one character
-        }
-        return (*dom == '.');
-    }
-
-
-
     // return a connected service ref (deallocate with DNSServiceRefDeallocate)
 static DNSServiceRef connect_to_server(void)
     {
@@ -858,19 +853,19 @@ static DNSServiceRef connect_to_server(void)
     if (!sdr) return NULL;
 
     if ((sdr->sockfd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0) 
-        {
+       {
         free(sdr);
         return NULL;
-        }
+       }
 
     saddr.sun_family = AF_LOCAL;
     strcpy(saddr.sun_path, MDNS_UDS_SERVERPATH);
     if (connect(sdr->sockfd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0)
-        {
+       {
         free(sdr);
         return NULL;
-        }
-    return sdr; 
+       }
+    return sdr;        
     }
 
 
@@ -878,7 +873,13 @@ static DNSServiceRef connect_to_server(void)
 
 int my_write(int sd, char *buf, int len)
     {
-    if (send(sd, buf, len, MSG_WAITALL) != len)   return -1;
+    while (len)
+       {
+       ssize_t num_written = send(sd, buf, len, 0);
+       if (num_written < 0 || num_written > len) return -1;
+       buf += num_written;
+       len -= num_written;
+       }
     return 0;
     }
 
@@ -910,15 +911,18 @@ DNSServiceErrorType deliver_request(void *msg, DNSServiceRef sdr, int reuse_sd)
 
         bzero(&caddr, sizeof(caddr));
         caddr.sun_family = AF_LOCAL;
-        caddr.sun_len = sizeof(struct sockaddr_un);
-        path = (char *)msg + sizeof(ipc_msg_hdr);
+#ifndef NOT_HAVE_SA_LEN                // According to Stevens (section 3.2), there is no portable way to 
+                                                       // determine whether sa_len is defined on a particular platform. 
+               caddr.sun_len = sizeof(struct sockaddr_un);
+#endif
+           path = (char *)msg + sizeof(ipc_msg_hdr);
         strcpy(caddr.sun_path, path);
         mask = umask(0);
         if (bind(listenfd, (struct sockaddr *)&caddr, sizeof(caddr)) < 0)
-          {
-            umask(mask);
+         {
+           umask(mask);
             goto cleanup;
-          }
+         }
         umask(mask);
         listen(listenfd, 1);
         }
@@ -943,7 +947,7 @@ DNSServiceErrorType deliver_request(void *msg, DNSServiceRef sdr, int reuse_sd)
         }
 cleanup:
     if (!reuse_sd && listenfd > 0) close(listenfd);
-    if (!reuse_sd && errsd > 0) close(errsd);   
+    if (!reuse_sd && errsd > 0) close(errsd);  
     if (!reuse_sd && path) unlink(path);
     if (msg) free(msg);
     return err;
@@ -971,10 +975,9 @@ static ipc_msg_hdr *create_hdr(int op, int *len, char **data_start, int reuse_so
 
     if (!reuse_socket)
         {
-        if (gettimeofday(&time, NULL) < 0) return NULL;
-        sprintf(ctrl_path, "%s%d-%.3x-%.6u", CTL_PATH_PREFIX, (int)getpid(), 
-                time.tv_sec & 0xFFF, time.tv_usec);
-
+           if (gettimeofday(&time, NULL) < 0) return NULL;
+           sprintf(ctrl_path, "%s%d-%.3lx-%.6lu", CTL_PATH_PREFIX, (int)getpid(), 
+                 (unsigned long)(time.tv_sec & 0xFFF), (unsigned long)(time.tv_usec));
         *len += strlen(ctrl_path) + 1;
         }
     
index 186f4d332a772100b6d34abab53ab3a93fa4949d..9f509a44a404dd71c35f0485149873f5ff3b32f3 100644 (file)
@@ -3,6 +3,8 @@
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
     Change History (most recent first):
 
 $Log: dnssd_ipc.c,v $
+Revision 1.9  2004/05/18 23:51:27  cheshire
+Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
+
+Revision 1.8  2003/11/05 22:44:57  ksekar
+<rdar://problem/3335230>: No bounds checking when reading data from client
+Reviewed by: Stuart Cheshire
+
 Revision 1.7  2003/08/12 19:56:25  cheshire
 Update to APSL 2.0
 
@@ -100,7 +109,6 @@ int put_string(const char *str, char **ptr)
     return 0;
     }
 
-// !!!KRS we don't properly handle the case where the string is longer than the buffer!!!      
 int get_string(char **ptr, char *buffer, int buflen)
     {
     int overrun;
index 2b7b323539a8b3177ffc1ae1b01530c5df1c8c4c..45852848a0148cd3c2fc7bc7c4b49d4439e4caec 100644 (file)
@@ -3,6 +3,8 @@
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
diff --git a/mDNSShared/mDNS.1 b/mDNSShared/mDNS.1
new file mode 100644 (file)
index 0000000..be51457
--- /dev/null
@@ -0,0 +1,184 @@
+.\" Copyright (c) 2004 Apple Computer, Inc. All Rights Reserved.
+.\" 
+.\" @APPLE_LICENSE_HEADER_START@
+.\" 
+.\" This file contains Original Code and/or Modifications of Original Code
+.\" as defined in and that are subject to the Apple Public Source License
+.\" Version 2.0 (the 'License'). You may not use this file except in
+.\" compliance with the License. Please obtain a copy of the License at
+.\" http://www.opensource.apple.com/apsl/ and read it before using this
+.\" file.
+.\" 
+.\" The Original Code and all software distributed under the License are
+.\" distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+.\" EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+.\" INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+.\" FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+.\" Please see the License for the specific language governing rights and
+.\" limitations under the License.
+.\" 
+.\" @APPLE_LICENSE_HEADER_END@
+.\"
+.\" $Log: mDNS.1,v $
+.\" Revision 1.3  2004/05/19 00:31:28  cheshire
+.\" Add missing "name type domain" for -L option
+.\"
+.\" Revision 1.2  2004/05/18 18:58:29  cheshire
+.\" Refinements from Soren Spies
+.\"
+.\" Revision 1.1  2004/04/22 02:52:53  cheshire
+.\" <rdar://problem/3597463>: mDNSResponder missing man pages: mDNS
+.\"
+.\"
+.\"
+.Dd April 2004              \" Date
+.Dt mDNS 1                  \" Document Title
+.Os Darwin                  \" Operating System
+.\"
+.Sh NAME
+.Nm mDNS
+.Nd Multicast DNS Service Discovery (mDNS-SD) Test Tool \" For whatis
+.\" 
+.Sh SYNOPSIS
+.Nm Fl R Ar name type domain port Op Ar key=value ...
+.Pp
+.Nm Fl B Ar      type domain
+.Pp
+.Nm Fl L Ar name type domain
+.\"
+.Sh DESCRIPTION
+The
+.Nm
+command is a network diagnostic tool, much like
+.Xr ping 8 or
+.Xr traceroute 8 .
+Unlike those tools, most of its functionality is implemented in library
+code that is available to any application. The API that it uses is
+described in
+.Pa /usr/include/dns_sd.h .
+.Pp
+The
+.Nm
+command is primarily intended for interactive use.
+Because its command-line arguments and output format are subject to change,
+invoking it from a shell script will generally be fragile. Additionally,
+the asynchronous nature of Multicast DNS Service Discovery does
+not lend itself easily to script-oriented programming. For example,
+calls like "browse" never complete; the action of performing a "browse"
+sets in motion machinery to notify the client whenever instances of
+that service type appear or disappear from the network. These
+notifications continue to be delivered indefinitely, for minutes,
+hours, or even days, as services come and go, until the client
+explicitly terminates the call. This style of asynchronous interaction
+works best with applications that are either multi-threaded, or use a
+main event-handling loop to receive keystrokes, network data, and other
+asynchronous event notifications as they happen.
+.Pp
+.Bl -tag -width R
+.It Fl R Ar name type domain port Op Ar key=value ...
+register (advertise) a service in the specified
+.Ar domain 
+with the given
+.Ar name
+and
+.Ar type
+as listening (on the current machine) on
+.Ar port.
+.Pp
+.Ar name
+can be arbitrary unicode text, containing any legal unicode characters
+(including dots, spaces, slashes, colons, etc. without restriction),
+up to 63 UTF-8 bytes long.
+.Ar type
+must be of the form "_app-proto._tcp" or "_app-proto._udp", where
+"app-proto" is an application protocol name registered at
+.Pa http://www.dns-sd.org/ServiceTypes.html .
+.Pp
+.Ar domain
+is the domain in which to register the service.
+In current implementations, only the local multicast domain "local" is
+supported. In the future, registering will be supported in any arbitrary
+domain that has a working DNS Update server [RFC 2136]. The
+.Ar domain
+"." is a synonym for "pick a sensible default" which today
+means "local".
+.Pp
+.Ar port
+is a number from 0 to 65535, and is the TCP or UDP port number upon
+which the service is listening.
+.Pp 
+Additional attributes of the service may optionally be described by
+key/value pairs, which are stored in the advertised service's DNS TXT
+record. Allowable keys and values are listed with the service
+registration at
+.Pa http://www.dns-sd.org/ServiceTypes.html .
+.It Fl B Ar type domain
+browse for instances of service
+.Ar type
+in
+.Ar domain .
+.Pp
+For valid 
+.Ar type Ns s
+see
+.Pa http://www.dns-sd.org/ServiceTypes.html
+as described above. Omitting the
+.Ar domain
+or using "." means "pick a sensible default."
+.It Fl L Ar name type domain
+look up and display the information necessary to contact and use the
+named service: the hostname of the machine where that service is
+available, the port number on which the service is listening, and (if
+present) TXT record attributes describing properties of the service.
+.Pp
+Note that in a typical application, browsing happens rarely, while lookup
+(or "resolving") happens every time the service is used. For example, a
+user browses the network to pick a default printer fairly rarely, but once
+a default printer has been picked, that named service is resolved to its
+current IP address and port number every time the user presses Cmd-P to
+print.
+.El
+.Sh EXAMPLES
+.Pp
+To advertise the existence of LPR printing service on port 515 on this
+machine, such that it will be discovered by the Mac OS X printing software
+and other mDNS-SD compatible printing clients, use:
+.Pp
+.Dl mDNS -R \&"My Test\&" _printer._tcp. \&. 515 pdl=application/postscript
+.Pp
+For this registration to be useful, you need to actually have LPR service
+available on port 515. Advertising a service that does not exist is not
+very useful, and will be confusing and annoying to other people on the
+network.
+.Pp
+Similarly, to advertise a web page being served by an HTTP
+server on port 80 on this machine, such that it will show up in the
+Rendezvous list in Safari and other mDNS-SD compatible Web clients, use:
+.Pp
+.Dl mDNS -R \&"My Test\&" _http._tcp \&. 80 path=/path-to-page.html
+.Pp
+To find the advertised web pages on the local network (the same list that
+Safari shows), use:
+.Pp
+.Dl mDNS -B _http._tcp
+.Pp
+While that command is running, in another window, try the "mDNS -R"
+example given above to advertise a web page, and you should see the
+"Add" event reported to the "mDNS -B" window. Now press Ctrl-C in the
+"mDNS -R" window and you should see the "Remove" event reported to the
+"mDNS -B" window.
+.Pp
+.Sh FILES
+.Pa /usr/bin/mDNS \" Pathname
+.\"
+.Sh SEE ALSO
+.Xr mDNSResponder 8
+.\"
+.Sh BUGS
+.Nm
+bugs are tracked in Apple Radar component "mDNSResponder".
+.\"
+.Sh HISTORY
+The
+.Nm
+command first appeared in Mac OS X 10.3 (Panther).
diff --git a/mDNSShared/mDNSDebug.c b/mDNSShared/mDNSDebug.c
new file mode 100644 (file)
index 0000000..9196f00
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+       File:           mDNSDebug.c
+
+       Contains:       Implementation of debugging utilities. Requires a POSIX environment.
+
+       Version:        1.0
+
+    Change History (most recent first):
+
+$Log: mDNSDebug.c,v $
+Revision 1.3  2004/01/28 21:14:23  cheshire
+Reconcile debug_mode and gDebugLogging into a single flag (mDNS_DebugMode)
+
+Revision 1.2  2003/12/09 01:30:40  rpantos
+Fix usage of ARGS... macros to build properly on Windows.
+
+Revision 1.1  2003/12/08 21:11:42;  rpantos
+Changes necessary to support mDNSResponder on Linux.
+
+*/
+
+#include "mDNSDebug.h"
+
+#include <stdio.h>
+#include <syslog.h>
+
+#include "mDNSClientAPI.h"
+
+#if MDNS_DEBUGMSGS
+mDNSexport int mDNS_DebugMode = mDNStrue;
+#else
+mDNSexport int mDNS_DebugMode = mDNSfalse;
+#endif
+
+// Note, this uses mDNS_vsnprintf instead of standard "vsnprintf", because mDNS_vsnprintf knows
+// how to print special data types like IP addresses and length-prefixed domain names
+#if MDNS_DEBUGMSGS
+mDNSexport void debugf_(const char *format, ...)
+       {
+       unsigned char buffer[512];
+       va_list ptr;
+       va_start(ptr,format);
+       buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0;
+       va_end(ptr);
+       fprintf(stderr,"%s\n", buffer);
+       fflush(stderr);
+       }
+#endif
+
+#if MDNS_DEBUGMSGS > 1
+mDNSexport void verbosedebugf_(const char *format, ...)
+       {
+       unsigned char buffer[512];
+       va_list ptr;
+       va_start(ptr,format);
+       buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0;
+       va_end(ptr);
+       fprintf(stderr,"%s\n", buffer);
+       fflush(stderr);
+       }
+#endif
+
+mDNSlocal void WriteLogMsg(const char *ident, const char *buffer, int logoptflags)
+       {
+       if (mDNS_DebugMode)     // In debug mode we write to stderr
+               {
+               fprintf(stderr,"%s\n", buffer);
+               fflush(stderr);
+               }
+       else                            // else, in production mode, we write to syslog
+               {
+               openlog(ident, LOG_CONS | LOG_PERROR | logoptflags, LOG_DAEMON);
+               syslog(LOG_ERR, "%s", buffer);
+               closelog();
+               }
+       }
+
+mDNSlocal void LogMsgWithIdent(const char *ident, const char *format, va_list ptr)
+       {
+       unsigned char buffer[512];
+       buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0;
+       WriteLogMsg(ident, buffer, ident && *ident ? LOG_PID : 0);
+       }
+
+mDNSexport void LogMsg(const char *format, ...)
+       {
+       unsigned char buffer[512];
+       va_list ptr;
+       va_start(ptr,format);
+       buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0;
+       va_end(ptr);
+       WriteLogMsg("mDNSResponder", buffer, 0);
+       }
+
+mDNSexport void LogMsgIdent(const char *ident, const char *format, ...)
+       {
+       va_list ptr;
+       va_start(ptr,format);
+       LogMsgWithIdent(ident, format, ptr);
+       va_end(ptr);
+       }
+
+mDNSexport void LogMsgNoIdent(const char *format, ...)
+       {
+       va_list ptr;
+       va_start(ptr,format);
+       LogMsgWithIdent("", format, ptr);
+       va_end(ptr);
+       }
diff --git a/mDNSShared/mDNSResponder.8 b/mDNSShared/mDNSResponder.8
new file mode 100644 (file)
index 0000000..cef8944
--- /dev/null
@@ -0,0 +1,108 @@
+.\" Copyright (c) 2003-2004 Apple Computer, Inc. All Rights Reserved.
+.\" 
+.\" @APPLE_LICENSE_HEADER_START@
+.\" 
+.\" This file contains Original Code and/or Modifications of Original Code
+.\" as defined in and that are subject to the Apple Public Source License
+.\" Version 2.0 (the 'License'). You may not use this file except in
+.\" compliance with the License. Please obtain a copy of the License at
+.\" http://www.opensource.apple.com/apsl/ and read it before using this
+.\" file.
+.\" 
+.\" The Original Code and all software distributed under the License are
+.\" distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+.\" EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+.\" INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+.\" FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+.\" Please see the License for the specific language governing rights and
+.\" limitations under the License.
+.\" 
+.\" @APPLE_LICENSE_HEADER_END@
+.\"
+.\" $Log: mDNSResponder.8,v $
+.\" Revision 1.4  2004/05/18 18:14:36  cheshire
+.\" Minor wording update
+.\"
+.\" Revision 1.3  2004/04/22 02:56:08  cheshire
+.\" <rdar://problem/3619494>: mDNSResponder man page format error
+.\"
+.\" Revision 1.2  2004/04/12 18:03:24  ksekar
+.\" <rdar://problem/3619494>: mDNSResponder man page format error
+.\"
+.\" Revision 1.1  2003/11/13 03:21:38  cheshire
+.\" <rdar://problem/3086886>: No man page for mDNSResponder
+.\"
+.\"
+.\"
+.Dd April 2004              \" Date
+.Dt mDNSResponder 8         \" Document Title
+.Os Darwin                  \" Operating System
+.\"
+.Sh NAME
+.Nm mDNSResponder
+.Nd Multicast DNS daemon    \" Name Description for whatis database
+.\" 
+.Sh SYNOPSIS
+.Nm
+.\"
+.Sh DESCRIPTION
+.Nm
+is a daemon invoked at boot time to implement Multicast DNS
+and DNS Service Discovery.
+.Pp
+.Nm
+listens UDP port 5353 for Multicast DNS Query packets.
+When it receives a query for which it knows an answer,
+.Nm
+issues the appropriate Multicast DNS Reply packet.
+.Pp
+.Nm
+also performs Multicast DNS Queries on behalf of client processes,
+and maintains a cache of the replies.
+.Pp
+.Nm
+has no user-specifiable command-line argument, and users should not run
+.Nm
+manually.
+.Pp
+To examine
+.Nm Ns 's internal state, for debugging and disagnostic purposes,
+send it a SIGINFO signal, and it will then dump a snapshot summary
+of its internal state to
+.Pa /var/log/system.log Ns , e.g.
+.Pp
+.Dl sudo killall -INFO mDNSResponder
+.Sh FILES
+.Pa /usr/sbin/mDNSResponder \" Pathname
+.\"
+.Sh SEE ALSO
+.Xr mDNS 1
+.Pp
+For information on Multicast DNS, see
+.Pa http://www.multicastdns.org/
+.Pp
+For information on DNS Service Discovery, see
+.Pa http://www.dns-sd.org/
+.Pp
+For information on how to use the Multicast DNS and the
+DNS Service Discovery APIs on Mac OS X and other platforms, see
+.Pa http://developer.apple.com/macosx/rendezvous/
+.Pp
+For the source code to
+.Nm , see
+.Pa http://developer.apple.com/darwin/projects/rendezvous/
+.\"
+.Sh BUGS
+.Nm
+bugs are tracked in Apple Radar component "mDNSResponder".
+.\"
+.Sh HISTORY
+The
+.Nm
+daemon first appeared in Mac OS X 10.2 (Jaguar).
+.Pp
+Also available from the Darwin open source repository
+(though not officially supported by Apple) are 
+.Nm
+daemons for other platforms, including Mac OS 9, Microsoft Windows,
+Linux, FreeBSD, NetBSD, Solaris, and other POSIX systems.
index 5cc63fc937f7181dda6b3814d25496247685f3c0..e393f69cfbb1eafdff77852b175164ebde15dbb2 100644 (file)
@@ -3,6 +3,8 @@
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
     Change History (most recent first):
 
 $Log: uds_daemon.c,v $
-Revision 1.22.2.1  2003/12/05 00:03:35  cheshire
-<rdar://problem/3487869> Use buffer size MAX_ESCAPED_DOMAIN_NAME instead of 256
+Revision 1.55.2.1  2004/06/13 22:32:24  ksekar
+WWDC Branch
+
+Revision 1.55  2004/06/05 00:04:27  cheshire
+<rdar://problem/3668639>: wide-area domains should be returned in reg. domain enumeration
+
+Revision 1.54  2004/06/01 22:22:52  ksekar
+<rdar://problem/3668635>: wide-area default registrations should be in
+.local too
+
+Revision 1.53  2004/05/28 23:42:37  ksekar
+<rdar://problem/3258021>: Feature: DNS server->client notification on record changes (#7805)
+
+Revision 1.52  2004/05/26 00:39:49  ksekar
+<rdar://problem/3667105>: wide-area rendezvous servers don't appear in
+Finder
+Use local-only InterfaceID for GetDomains calls for sockets-API
+
+Revision 1.51  2004/05/18 23:51:27  cheshire
+Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
+
+Revision 1.50  2004/05/14 16:39:47  ksekar
+Browse for iChat locally for now.
+
+Revision 1.49  2004/05/13 21:33:52  ksekar
+Clean up non-local registration control via config file.  Force iChat
+registrations to be local for now.
+
+Revision 1.48  2004/05/13 04:13:19  ksekar
+Updated SIGINFO handler for multi-domain browses
+
+Revision 1.47  2004/05/12 22:04:01  ksekar
+Implemented multi-domain browsing by default for uds_daemon.
+
+Revision 1.46  2004/05/06 18:42:58  ksekar
+General dns_sd.h API cleanup, including the following radars:
+<rdar://problem/3592068>: Remove flags with zero value
+<rdar://problem/3479569>: Passing in NULL causes a crash.
+
+Revision 1.45  2004/03/12 08:49:28  cheshire
+#include <sys/socket.h>
+
+Revision 1.44  2004/02/25 01:25:27  ksekar
+<rdar://problem/3569212>: DNSServiceRegisterRecord flags not error-checked
+
+Revision 1.43  2004/02/24 01:46:40  cheshire
+Manually reinstate lost checkin 1.36
+
+Revision 1.42  2004/02/05 19:39:29  cheshire
+Move creation of /var/run/mDNSResponder.pid to uds_daemon.c,
+so that all platforms get this functionality
+
+Revision 1.41  2004/02/03 18:59:02  cheshire
+Change "char *domain" parameter for format_enumeration_reply to "const char *domain"
+
+Revision 1.40  2004/01/28 03:41:00  cheshire
+<rdar://problem/3541946>: Need ability to do targeted queries as well as multicast queries
+
+Revision 1.39  2004/01/25 00:03:21  cheshire
+Change to use mDNSVal16() instead of private PORT_AS_NUM() macro
+
+Revision 1.38  2004/01/19 19:51:46  cheshire
+Fix compiler error (mixed declarations and code) on some versions of Linux
+
+Revision 1.37  2003/12/08 21:11:42  rpantos
+Changes necessary to support mDNSResponder on Linux.
+
+Revision 1.36  2003/12/04 23:40:57  cheshire
+<rdar://problem/3484766>: Security: Crashing bug in mDNSResponder
+Fix some more code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1005) instead of 256-byte buffers.
+
+Revision 1.35  2003/12/03 19:10:22  ksekar
+<rdar://problem/3498644>: malloc'd data not zero'd
+
+Revision 1.34  2003/12/03 02:00:01  ksekar
+<rdar://problem/3498644>: malloc'd data not zero'd
+
+Revision 1.33  2003/11/22 01:18:46  ksekar
+<rdar://problem/3486646>: config change handler not called for dns-sd services
+
+Revision 1.32  2003/11/20 21:46:12  ksekar
+<rdar://problem/3486635>: leak: DNSServiceRegisterRecord
+
+Revision 1.31  2003/11/20 20:33:05  ksekar
+<rdar://problem/3486635>: leak: DNSServiceRegisterRecord
+
+Revision 1.30  2003/11/20 02:10:55  ksekar
+<rdar://problem/3486643>: cleanup DNSServiceAdd/RemoveRecord
+
+Revision 1.29  2003/11/14 21:18:32  cheshire
+<rdar://problem/3484766>: Security: Crashing bug in mDNSResponder
+Fix code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1005) instead of 256-byte buffers.
+
+Revision 1.28  2003/11/08 22:18:29  cheshire
+<rdar://problem/3477870>: Don't need to show process ID in *every* mDNSResponder syslog message
+
+Revision 1.27  2003/11/05 22:44:57  ksekar
+<rdar://problem/3335230>: No bounds checking when reading data from client
+Reviewed by: Stuart Cheshire
+
+Revision 1.26  2003/10/23 17:51:04  ksekar
+<rdar://problem/3335216>: handle blocked clients more efficiently
+Changed gettimeofday() to mDNSPlatformTimeNow()
+
+Revision 1.25  2003/10/22 23:37:49  ksekar
+<rdar://problem/3459141>: crash/hang in abort_client
+
+Revision 1.24  2003/10/21 20:59:40  ksekar
+<rdar://problem/3335216>: handle blocked clients moreefficiently
+
+Revision 1.23  2003/09/23 02:12:43  cheshire
+Also include port number in list of services registered via new UDS API
 
 Revision 1.22  2003/08/19 16:03:55  ksekar
-Bug #: <rdar://problem/3380097>: ER: SIGINFO dump should include resolves started by DNSServiceQueryRecord
+<rdar://problem/3380097>: ER: SIGINFO dump should include resolves started by DNSServiceQueryRecord
 Check termination_context for NULL before dereferencing.
 
 Revision 1.21  2003/08/19 05:39:43  cheshire
@@ -45,17 +157,17 @@ We want to avoid touching the rdata pages, so we don't page them in.
    compute a hash of the rdata and store the hash in the ResourceRecord object.
 
 Revision 1.18  2003/08/15 00:38:00  ksekar
-Bug #: <rdar://problem/3377005>: Bug: buffer overrun when reading long rdata from client
+<rdar://problem/3377005>: Bug: buffer overrun when reading long rdata from client
 
 Revision 1.17  2003/08/14 02:18:21  cheshire
 <rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
 
 Revision 1.16  2003/08/13 23:58:52  ksekar
-Bug #: <rdar://problem/3374911>: Bug: UDS Sub-type browsing works, but not sub-type registration
+<rdar://problem/3374911>: Bug: UDS Sub-type browsing works, but not sub-type registration
 Fixed pointer increment error, moved subtype reading for-loop for easier error bailout.
 
 Revision 1.15  2003/08/13 17:30:33  ksekar
-Bug #: <rdar://problem/3374671>: DNSServiceAddRecord doesn't work
+<rdar://problem/3374671>: DNSServiceAddRecord doesn't work
 Fixed various problems with handling the AddRecord request and freeing the ExtraResourceRecords.
 
 Revision 1.14  2003/08/12 19:56:25  cheshire
@@ -63,16 +175,21 @@ Update to APSL 2.0
 
  */
 
-#include "mDNSClientAPI.h"
-#include "mDNSMacOSX.h"
-#include "dns_sd.h"
-#include "dnssd_ipc.h"
 #include <fcntl.h>
+#include <errno.h>
 #include <sys/ioctl.h>
 #include <sys/types.h>
 #include <sys/time.h>
 #include <sys/resource.h>
+#include <sys/socket.h>
 
+#include "mDNSClientAPI.h"
+#include "uds_daemon.h"
+#include "dns_sd.h"
+#include "dnssd_ipc.h"
+
+// convenience definition 
+#define        _UNUSED __attribute__ ((unused))
 // Types and Data Structures
 // ----------------------------------------------------------------------
 
@@ -94,10 +211,16 @@ typedef struct registered_record_entry
     AuthRecord *rr;
     struct registered_record_entry *next;
     } registered_record_entry;
+    
+typedef struct extra_record_entry
+    {
+    int key;
+    struct extra_record_entry *next;
+    ExtraResourceRecord e;
+    } extra_record_entry;
 
 typedef struct registered_service
     {
-    //struct registered_service *next;
     int autoname;
     int renameonconflict;
     int rename_on_memfree;     // set flag on config change when we deregister original name
@@ -105,8 +228,15 @@ typedef struct registered_service
     ServiceRecordSet *srs;
     struct request_state *request;
     AuthRecord *subtypes;
+    extra_record_entry *extras;
     } registered_service;
-    
+
+typedef struct
+       {
+    registered_service *local;
+    registered_service *global;
+       } servicepair_t;
+
 typedef struct 
     {
     mStatus err;
@@ -117,8 +247,6 @@ typedef struct
 typedef struct request_state
     {
     // connection structures
-    CFRunLoopSourceRef rls;
-    CFSocketRef sr;            
     int sd;    
     int errfd;         
                                 
@@ -133,6 +261,7 @@ typedef struct request_state
 
     // reply, termination, error, and client context info
     int no_reply;              // don't send asynchronous replies to client
+    int time_blocked;           // record time of a blocked client
     void *client_context;      // don't touch this - pointer only valid in client's addr space
     struct reply_state *replies;  // corresponding (active) reply list
     undelivered_error_t *u_err;
@@ -142,7 +271,7 @@ typedef struct request_state
     //!!!KRS toss these pointers in a union
     // registration context associated with this request (null if not applicable)
     registered_record_entry *reg_recs;  // muliple registrations for a connection-oriented request
-    registered_service *service;  // service record set and flags
+    servicepair_t servicepair;
     struct resolve_result_t *resolve_results;
     
     struct request_state *next;
@@ -218,10 +347,22 @@ typedef struct
     client_context_t client_context;
     } regrecord_callback_context;
 
+// for multi-domain browsing
+typedef struct qlist_t
+       {
+    DNSQuestion q;
+    struct qlist_t *next;
+       } qlist_t;
 
+typedef struct
+       {
+    qlist_t *qlist;
+    request_state *rstate;
+       } browse_termination_context;
 
 
 // globals
+static mDNS *gmDNS = NULL;
 static int listenfd = -1;  
 static request_state *all_requests = NULL;  
 //!!!KRS we should keep a separate list containing only the requests that need to be examined
@@ -229,14 +370,16 @@ static request_state *all_requests = NULL;
 
 
 #define MAX_OPENFILES 1024
-
+#define MAX_TIME_BLOCKED 60 * mDNSPlatformOneSecond   // try to send data to a blocked client for 60 seconds before
+                              // terminating connection
+#define MSG_PAD_BYTES 5       // pad message buffer (read from client) with n zero'd bytes to guarantee
+                              // n get_string() calls w/o buffer overrun    
 // private function prototypes
-static void connect_callback(CFSocketRef sr, CFSocketCallBackType t, CFDataRef dr, const void *c, void *i);
+static void connect_callback(void *info);
 static int read_msg(request_state *rs);
 static int send_msg(reply_state *rs);
 static void abort_request(request_state *rs);
-static void request_callback(CFSocketRef sr, CFSocketCallBackType t, CFDataRef dr, const void *c, void *i);
+static void request_callback(void *info);
 static void handle_resolve_request(request_state *rstate);
 static void question_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord);
 static void question_termination_callback(void *context);
@@ -255,14 +398,13 @@ static int build_domainname_from_strings(domainname *srv, char *name, char *regt
 static void enum_termination_callback(void *context);
 static void enum_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord);
 static void handle_query_request(request_state *rstate);
-static mStatus do_question(request_state *rstate, domainname *name, uint32_t ifi, uint16_t rrtype, int16_t rrclass);
-static reply_state *format_enumeration_reply(request_state *rstate, char *domain,                                              DNSServiceFlags flags, uint32_t ifi, DNSServiceErrorType err);
+static reply_state *format_enumeration_reply(request_state *rstate, const char *domain, DNSServiceFlags flags, uint32_t ifi, DNSServiceErrorType err);
 static void handle_enum_request(request_state *rstate);
 static void handle_regrecord_request(request_state *rstate);
 static void regrecord_callback(mDNS *const m, AuthRecord *const rr, mStatus result);
 static void connected_registration_termination(void *context);
 static void handle_reconfirm_request(request_state *rstate);
-static AuthRecord *read_rr_from_ipc_msg(char *msgbuf, int ttl);
+static AuthRecord *read_rr_from_ipc_msg(char *msgbuf, int ttl, int validate_flags);
 static void handle_removerecord_request(request_state *rstate);
 static void reset_connected_rstate(request_state *rstate);
 static int deliver_error(request_state *rstate, mStatus err);
@@ -274,21 +416,48 @@ static void my_perror(char *errmsg);
 static void unlink_request(request_state *rs);
 static void resolve_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord);
 static void resolve_termination_callback(void *context);
+static int validate_message(request_state *rstate);
+static mStatus remove_extra_rr_from_service(request_state *rstate);
+static mStatus remove_record(request_state *rstate);
+static void free_service_registration(registered_service *srv);
 
 // initialization, setup/teardown functions
 
-int udsserver_init(void)  
+// If a platform specifies its own PID file name, we use that
+#ifndef PID_FILE
+#define PID_FILE "/var/run/mDNSResponder.pid"
+#endif
+
+int udsserver_init( mDNS *globalInstance)  
     {
     mode_t mask;
     struct sockaddr_un laddr;
     struct rlimit maxfds;
 
+    if ( !globalInstance)
+        goto error;
+       gmDNS = globalInstance;
+
+       // If a particular platform wants to opt out of having a PID file, define PID_FILE to be ""
+       if (PID_FILE[0])
+               {
+               FILE *fp = fopen(PID_FILE, "w");
+               if (fp != NULL)
+                       {
+                       fprintf(fp, "%d\n", getpid());
+                       fclose(fp);
+                       }
+               }
+
     if ((listenfd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0) 
-            goto error;
+        goto error;
     unlink(MDNS_UDS_SERVERPATH);  //OK if this fails
     bzero(&laddr, sizeof(laddr));
     laddr.sun_family = AF_LOCAL;
+#ifndef NOT_HAVE_SA_LEN                // According to Stevens (section 3.2), there is no portable way to 
+                                                       // determine whether sa_len is defined on a particular platform. 
     laddr.sun_len = sizeof(struct sockaddr_un);
+#endif
     strcpy(laddr.sun_path, MDNS_UDS_SERVERPATH);
     mask = umask(0);
     if (bind(listenfd, (struct sockaddr *)&laddr, sizeof(laddr)) < 0)
@@ -302,6 +471,11 @@ int udsserver_init(void)
         }
     listen(listenfd, LISTENQ);
     
+    if (mStatus_NoError != udsSupportAddFDToEventLoop(listenfd, connect_callback, (void *) NULL))
+        {
+        my_perror("ERROR: could not add listen socket to event loop");
+        goto error;
+        }
     
     // set maximum file descriptor to 1024
     if (getrlimit(RLIMIT_NOFILE, &maxfds) < 0)
@@ -333,27 +507,6 @@ int udsserver_exit(void)
     }
 
 
-// add the named socket as a runloop source
-int udsserver_add_rl_source(void)
-    {
-    CFSocketContext context =  { 0, NULL, NULL, NULL, NULL };
-    CFSocketRef sr = CFSocketCreateWithNative(kCFAllocatorDefault, listenfd, kCFSocketReadCallBack, connect_callback, &context);
-    if (!sr)
-        {
-        debugf("ERROR: udsserver_add_rl_source - CFSocketCreateWithNative");
-        return -1;
-       }
-    CFRunLoopSourceRef rls = CFSocketCreateRunLoopSource(kCFAllocatorDefault, sr, 0);
-  
-    if (!rls)
-       {
-        debugf("ERROR: udsserver_add_rl_source - CFSocketCreateRunLoopSource");
-        return -1;
-       }
-    CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
-    return 0;
-    }
-
 mDNSs32 udsserver_idle(mDNSs32 nextevent)
     {
     request_state *req = all_requests, *tmp, *prev = NULL;
@@ -361,7 +514,6 @@ mDNSs32 udsserver_idle(mDNSs32 nextevent)
     transfer_state result; 
     mDNSs32 now = mDNSPlatformTimeNow();
 
-
     while(req)
         {
         result = t_uninitialized;
@@ -373,27 +525,34 @@ mDNSs32 udsserver_idle(mDNSs32 nextevent)
             while(req->replies)
                 {
                 if (req->replies->next) req->replies->rhdr->flags |= kDNSServiceFlagsMoreComing;
-                else req->replies->rhdr->flags |= kDNSServiceFlagsFinished;
                 result = send_msg(req->replies);
                 if (result == t_complete)
                     {
                     fptr = req->replies;
                     req->replies = req->replies->next;
                     freeL("udsserver_idle", fptr);
+                    req->time_blocked = 0;                              // reset failure counter after successful send
                     }
                 else if (result == t_terminated || result == t_error)
                     {
                     abort_request(req);
                     break;
                     }
-                else if (result == t_morecoming)                       // client's queues are full, move to next
-                    {
-                    if (nextevent - now > mDNSPlatformOneSecond)
-                        nextevent = now + mDNSPlatformOneSecond;
-                    break;                                     // start where we left off in a second
-                    }
+                else if (result == t_morecoming) break;                        // client's queues are full, move to next
                 }
             }
+        if (result == t_morecoming)
+        {      
+           if (!req->time_blocked) req->time_blocked = now;
+           debugf("udsserver_idle: client has been blocked for %d seconds", now - req->time_blocked);
+           if (now - req->time_blocked >= MAX_TIME_BLOCKED)
+               {
+               LogMsg("Could not write data to client after %d seconds - aborting connection", MAX_TIME_BLOCKED / mDNSPlatformOneSecond);
+               abort_request(req);
+               result = t_terminated;
+               }
+           else if (nextevent - now > mDNSPlatformOneSecond) nextevent = now + mDNSPlatformOneSecond;  // try again in a second
+       }
         if (result == t_terminated || result == t_error)  
         //since we're already doing a list traversal, we unlink the request manunally instead of calling unlink_request()
             {
@@ -415,57 +574,60 @@ mDNSs32 udsserver_idle(mDNSs32 nextevent)
 void udsserver_info(void)
     {
     request_state *req;
+       qlist_t *qlist;
     for (req = all_requests; req; req=req->next)
         {
         void *t = req->termination_context;
         if (!t) continue;
         if (req->terminate == regservice_termination_callback)
-            LogMsg("DNSServiceRegister         %##s", ((registered_service *)   t)->srs->RR_SRV.resrec.name.c);
+            LogMsgNoIdent("DNSServiceRegister         %##s %u", ((registered_service *)t)->srs->RR_SRV.resrec.name.c, SRS_PORT(((registered_service *)t)->srs));
         else if (req->terminate == browse_termination_callback)
-            LogMsg("DNSServiceBrowse           %##s", ((DNSQuestion *)          t)->qname.c);
+                       {
+                       for (qlist = ((browse_termination_context *)t)->qlist; qlist; qlist = qlist->next)
+                               LogMsgNoIdent("DNSServiceBrowse           %##s", qlist->q.qname.c);
+                       }
         else if (req->terminate == resolve_termination_callback)
-            LogMsg("DNSServiceResolve          %##s", ((resolve_termination_t *)t)->srv->question.qname.c);
+            LogMsgNoIdent("DNSServiceResolve          %##s", ((resolve_termination_t *)t)->srv->question.qname.c);
         else if (req->terminate == question_termination_callback)
-            LogMsg("DNSServiceQueryRecord      %##s", ((DNSQuestion *)          t)->qname.c);
+            LogMsgNoIdent("DNSServiceQueryRecord      %##s", ((DNSQuestion *)          t)->qname.c);
         else if (req->terminate == enum_termination_callback)
-            LogMsg("DNSServiceEnumerateDomains %##s", ((enum_termination_t *)   t)->all->question.qname.c);
+            LogMsgNoIdent("DNSServiceEnumerateDomains %##s", ((enum_termination_t *)   t)->all->question.qname.c);
         }
     }
 
+
+static void rename_service(registered_service *srv)
+       {
+    mStatus err;
+       
+       if (srv->autoname && !SameDomainLabel(srv->name.c, gmDNS->nicelabel.c))
+               {
+               srv->rename_on_memfree = 1;
+               err = mDNS_DeregisterService(gmDNS, srv->srs);
+               if (err) LogMsg("ERROR: udsserver_handle_configchange: DeregisterService returned error %d.  Continuing.", err);
+               // error should never occur - safest to log and continue
+               }       
+       }
+
 void udsserver_handle_configchange(void)
     {
-    registered_service *srv;
     request_state *req;
-    mStatus err;
+
     
     for (req = all_requests; req; req = req->next)
         {
-        srv = req->service;
-        if (srv->autoname && !SameDomainLabel(srv->name.c, mDNSStorage.nicelabel.c))
-            {
-            srv->rename_on_memfree = 1;
-            err = mDNS_DeregisterService(&mDNSStorage, srv->srs);
-            if (err) LogMsg("ERROR: udsserver_handle_configchange: DeregisterService returned error %d.  Continuing.", err);
-            // error should never occur - safest to log and continue
-            }
-        }
+               if (req->servicepair.local) rename_service(req->servicepair.local);
+               if (req->servicepair.global) rename_service(req->servicepair.global);
+               }
     }
-    
-    
-    
 
-// accept a connection on the named socket, adding the new descriptor to the runloop and passing the error
-// descriptor to the client
-static void connect_callback(CFSocketRef s, CFSocketCallBackType t, CFDataRef dr, const void *c, void *i)
+static void connect_callback(void *info _UNUSED)
     {
     int sd, clilen, optval;
     struct sockaddr_un cliaddr;
-    CFSocketContext context =  { 0, NULL, NULL, NULL, NULL     };
     request_state *rstate;
 //    int errpipe[2];
     
-    #pragma unused(s, t, dr, c, i)
-
     clilen = sizeof(cliaddr);
     sd = accept(listenfd, (struct sockaddr *)&cliaddr, &clilen);
 
@@ -476,12 +638,15 @@ static void connect_callback(CFSocketRef s, CFSocketCallBackType t, CFDataRef dr
         return;
        }
     optval = 1;
+#ifdef SO_NOSIGPIPE
+       // Some environments (e.g. OS X) support turning off SIGPIPE for a socket
     if (setsockopt(sd, SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)) < 0)
        {
         my_perror("ERROR: setsockopt - SOL_NOSIGPIPE - aborting client");  
         close(sd);
         return;
        }
+#endif
 
     if (fcntl(sd, F_SETFL, O_NONBLOCK) < 0)
        {
@@ -525,57 +690,21 @@ static void connect_callback(CFSocketRef s, CFSocketCallBackType t, CFDataRef dr
     rstate->sd = sd;
     //rstate->errfd = errpipe[1];
     
-    //now create CFSocket wrapper and add to run loop
-    context.info = rstate;
-    rstate->sr = CFSocketCreateWithNative(kCFAllocatorDefault, sd, kCFSocketReadCallBack, request_callback, &context);
-    if (!rstate->sr)
-       {
-        debugf("ERROR: connect_callback - CFSocketCreateWithNative");
-        freeL("connect_callback", rstate);
-        close(sd);
+    if ( mStatus_NoError != udsSupportAddFDToEventLoop( sd, request_callback, rstate))
         return;
-       }
-    rstate->rls = CFSocketCreateRunLoopSource(kCFAllocatorDefault, rstate->sr, 0);
-    if (!rstate->rls)
-       {
-        debugf("ERROR: connect_callback - CFSocketCreateRunLoopSource");
-        CFSocketInvalidate(rstate->sr);  // automatically closes socket
-        CFRelease(rstate->sr);
-        freeL("connect_callback", rstate);
-        return;
-       }
-    CFRunLoopAddSource(CFRunLoopGetCurrent(), rstate->rls, kCFRunLoopDefaultMode);
-    if (!CFRunLoopContainsSource(CFRunLoopGetCurrent(), rstate->rls, kCFRunLoopDefaultMode))
-        {
-        LogMsg("ERROR: connect_callback, CFRunLoopAddSource");
-        abort_request(rstate);
-        return;
-        }
     rstate->next = all_requests;
     all_requests = rstate;
     }
 
 
-// main client request handling routine.  reads request and calls the appropriate request-specific
 // handler
-static void request_callback(CFSocketRef sr, CFSocketCallBackType t, CFDataRef dr, const void *context, void *info)
+static void request_callback(void *info)
     {
     request_state *rstate = info;
     transfer_state result;
     struct sockaddr_un cliaddr;
     char ctrl_path[MAX_CTLPATH];
     
-    #pragma unused(sr, t, dr, context)
-
-    int native = CFSocketGetNative(sr);
-    if (native != rstate->sd)
-        {
-        LogMsg("ERROR: request_callback - CFSocket's native descriptor does not match rstate member descriptor.");
-        abort_request(rstate);
-        unlink_request(rstate);
-        return;
-        }
-
     result = read_msg(rstate);
     if (result == t_morecoming)
        {
@@ -603,6 +732,16 @@ static void request_callback(CFSocketRef sr, CFSocketCallBackType t, CFDataRef d
         return;
     }
     
+    if (validate_message(rstate) < 0)
+       {
+       // note that we cannot deliver an error message if validation fails, since the path to the error socket
+       // may be contained in the (invalid) message body for some message types
+       abort_request(rstate);
+       unlink_request(rstate);
+       LogMsg("Invalid message sent by client - may indicate a malicious program running on this machine!");
+       return;
+       }    
+    
     // check if client wants silent operation
     if (rstate->hdr.flags & IPC_FLAGS_NOREPLY) rstate->no_reply = 1;
 
@@ -668,13 +807,14 @@ static void request_callback(CFSocketRef sr, CFSocketCallBackType t, CFDataRef d
 static void handle_query_request(request_state *rstate)
     {
     DNSServiceFlags flags;
-    uint32_t interfaceIndex;
+    uint32_t ifi;
     char name[256];
     uint16_t rrtype, rrclass;
     char *ptr;
-    domainname dname;
     mStatus result;
-    
+    mDNSInterfaceID InterfaceID;
+       DNSQuestion *q;
+       
     if (rstate->ts != t_complete)
         {
         LogMsg("ERROR: handle_query_request - transfer state != t_complete");
@@ -686,13 +826,37 @@ static void handle_query_request(request_state *rstate)
         LogMsg("ERROR: handle_query_request - NULL msgdata");
         goto error;
         }
+       
     flags = get_flags(&ptr);
-    interfaceIndex = get_long(&ptr);
+    ifi = get_long(&ptr);
     if (get_string(&ptr, name, 256) < 0) goto bad_param;
     rrtype = get_short(&ptr);
     rrclass = get_short(&ptr);
-    if (!MakeDomainNameFromDNSNameString(&dname, name)) goto bad_param;
-    result = do_question(rstate, &dname, interfaceIndex, rrtype, rrclass);
+       InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS, ifi);
+    if (ifi && !InterfaceID) goto bad_param;
+
+    q = mallocL("DNSQuestion", sizeof(DNSQuestion));
+    if (!q)
+       {
+        my_perror("ERROR: handle_query - malloc");
+        exit(1);
+       }
+    bzero(q, sizeof(DNSQuestion));     
+
+    if (!MakeDomainNameFromDNSNameString(&q->qname, name)) { freeL("DNSQuestion", q); goto bad_param; }        
+    q->QuestionContext = rstate;
+    q->QuestionCallback = question_result_callback;
+    q->qtype = rrtype;
+    q->qclass = rrclass;
+    q->InterfaceID = InterfaceID;
+    q->Target = zeroAddr;
+       if (flags & kDNSServiceFlagsLongLivedQuery) q->LongLived = mDNStrue;
+    rstate->termination_context = q;
+    rstate->terminate = question_termination_callback;
+
+    result = mDNS_StartQuery(gmDNS, q);
+    if (result != mStatus_NoError) LogMsg("ERROR: mDNS_StartQuery: %d", (int)result);
+       
     if (result) rstate->terminate = NULL;
     if (deliver_error(rstate, result) < 0) goto error;
     return;
@@ -710,7 +874,8 @@ static void handle_resolve_request(request_state *rstate)
     {
     DNSServiceFlags flags;
     uint32_t interfaceIndex;
-    char name[256], regtype[MAX_ESCAPED_DOMAIN_NAME], domain[MAX_ESCAPED_DOMAIN_NAME];  
+    mDNSInterfaceID InterfaceID;
+    char name[256], regtype[MAX_ESCAPED_DOMAIN_NAME], domain[MAX_ESCAPED_DOMAIN_NAME];
     char *ptr;  // message data pointer
     domainname fqdn;
     resolve_t *srv, *txt;
@@ -736,7 +901,7 @@ static void handle_resolve_request(request_state *rstate)
         }
     flags = get_flags(&ptr);
     interfaceIndex = get_long(&ptr);
-    mDNSInterfaceID InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex);
+    InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS, interfaceIndex);
     if (interfaceIndex && !InterfaceID) goto bad_param;
     if (get_string(&ptr, name, 256) < 0 ||
         get_string(&ptr, regtype, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
@@ -766,6 +931,7 @@ static void handle_resolve_request(request_state *rstate)
     srv->question.qtype = kDNSType_SRV;
     srv->question.qclass = kDNSClass_IN;
     srv->question.InterfaceID = InterfaceID;
+    srv->question.Target      = zeroAddr;
 
     txt->question.QuestionContext = rstate;
     txt->question.QuestionCallback = resolve_result_callback;
@@ -773,6 +939,7 @@ static void handle_resolve_request(request_state *rstate)
     txt->question.qtype = kDNSType_TXT;
     txt->question.qclass = kDNSClass_IN;
     txt->question.InterfaceID = InterfaceID;
+    txt->question.Target      = zeroAddr;
 
     // set up termination info
     term = mallocL("handle_resolve_request", sizeof(resolve_termination_t));
@@ -789,8 +956,8 @@ static void handle_resolve_request(request_state *rstate)
     bzero(rstate->resolve_results, sizeof(resolve_result_t));
 
     // ask the questions
-    err = mDNS_StartQuery(&mDNSStorage, &srv->question);
-    if (!err) err = mDNS_StartQuery(&mDNSStorage, &txt->question);
+    err = mDNS_StartQuery(gmDNS, &srv->question);
+    if (!err) err = mDNS_StartQuery(gmDNS, &txt->question);
 
     if (err)
         {
@@ -830,8 +997,8 @@ static void resolve_termination_callback(void *context)
         }
     rs = term->rstate;
     
-    mDNS_StopQuery(&mDNSStorage, &term->txt->question);
-    mDNS_StopQuery(&mDNSStorage, &term->srv->question);
+    mDNS_StopQuery(gmDNS, &term->txt->question);
+    mDNS_StopQuery(gmDNS, &term->srv->question);
     
     freeL("resolve_termination_callback", term->txt);
     freeL("resolve_termination_callback", term->srv);
@@ -843,7 +1010,7 @@ static void resolve_termination_callback(void *context)
     
     
 
-static void resolve_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
+static void resolve_result_callback(mDNS *const m _UNUSED, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
 {
     int len = 0;
     char fullname[MAX_ESCAPED_DOMAIN_NAME], target[MAX_ESCAPED_DOMAIN_NAME];
@@ -852,7 +1019,6 @@ static void resolve_result_callback(mDNS *const m, DNSQuestion *question, const
     reply_state *rep;
     request_state *rs = question->QuestionContext;
     resolve_result_t *res = rs->resolve_results;
-    #pragma unused(m)
     
        if (!AddRecord)
                {
@@ -881,7 +1047,7 @@ static void resolve_result_callback(mDNS *const m, DNSQuestion *question, const
     // allocate/init reply header
     rep =  create_reply(resolve_reply, len, rs);
     rep->rhdr->flags = 0;
-    rep->rhdr->ifi =  mDNSPlatformInterfaceIndexfromInterfaceID(&mDNSStorage, answer->InterfaceID);
+    rep->rhdr->ifi =  mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS, answer->InterfaceID);
     rep->rhdr->error = kDNSServiceErr_NoError;
     data = rep->sdata;
     
@@ -902,44 +1068,9 @@ static void resolve_result_callback(mDNS *const m, DNSQuestion *question, const
     else if (result == t_complete) freeL("resolve_result_callback", rep);
     else append_reply(rs, rep);
     }
-
-
-
-
-// common query issuing routine for resolve and query requests
-static mStatus do_question(request_state *rstate, domainname *name, uint32_t ifi, uint16_t rrtype, int16_t rrclass)
-    {
-    DNSQuestion *q;
-    mStatus result;
-    mDNSInterfaceID InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, ifi);
-    if (ifi && !InterfaceID) return(mStatus_BadParamErr);
-
-    q = mallocL("do_question", sizeof(DNSQuestion));
-    if (!q)
-       {
-        my_perror("ERROR: do_question - malloc");
-        exit(1);
-       }
-    bzero(q, sizeof(DNSQuestion));     
-
-    q->QuestionContext = rstate;
-    q->QuestionCallback = question_result_callback;
-    memcpy(&q->qname, name, MAX_DOMAIN_NAME);
-    q->qtype = rrtype;
-    q->qclass = rrclass;
-    q->InterfaceID = InterfaceID;
-
-
-    rstate->termination_context = q;
-    rstate->terminate = question_termination_callback;
-
-    result = mDNS_StartQuery(&mDNSStorage, q);
-    if (result != mStatus_NoError) LogMsg("ERROR: mDNS_StartQuery: %d", (int)result);
-    return result;
-    }
-    
 // what gets called when a resolve is completed and we need to send the data back to the client
-static void question_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
+static void question_result_callback(mDNS *const m _UNUSED, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
     {
     char *data;
     char name[MAX_ESCAPED_DOMAIN_NAME];
@@ -947,7 +1078,6 @@ static void question_result_callback(mDNS *const m, DNSQuestion *question, const
     reply_state *rep;
     int len;
 
-    #pragma unused(m)
     //mDNS_StopQuery(m, question);
     req = question->QuestionContext;
     
@@ -961,8 +1091,8 @@ static void question_result_callback(mDNS *const m, DNSQuestion *question, const
     len += strlen(name) + 1;
     
     rep =  create_reply(query_reply, len, req);
-    rep->rhdr->flags = AddRecord ? kDNSServiceFlagsAdd : kDNSServiceFlagsRemove;
-    rep->rhdr->ifi =  mDNSPlatformInterfaceIndexfromInterfaceID(&mDNSStorage, answer->InterfaceID);
+    rep->rhdr->flags = AddRecord ? kDNSServiceFlagsAdd : 0;
+    rep->rhdr->ifi =  mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS, answer->InterfaceID);
     rep->rhdr->error = kDNSServiceErr_NoError;
     data = rep->sdata;
     
@@ -982,7 +1112,7 @@ static void question_termination_callback(void *context)
     DNSQuestion *q = context;
 
 
-    mDNS_StopQuery(&mDNSStorage, q);  // no need to error check
+    mDNS_StopQuery(gmDNS, q);  // no need to error check
     freeL("question_termination_callback", q);
     }
 
@@ -991,12 +1121,15 @@ static void handle_browse_request(request_state *request)
     {
     DNSServiceFlags flags;
     uint32_t interfaceIndex;
+    mDNSInterfaceID InterfaceID;
     char regtype[MAX_ESCAPED_DOMAIN_NAME], domain[MAX_ESCAPED_DOMAIN_NAME];
-    DNSQuestion *q;
-    domainname typedn, domdn;
+       qlist_t *qlist = NULL, *qlist_elem;
+    domainname typedn;
     char *ptr;
     mStatus result;
-
+       DNameListElem *search_domain_list, *sdom, tmp;
+       browse_termination_context *term;
+       
     if (request->ts != t_complete)
         {
         LogMsg("ERROR: handle_browse_request - transfer state != t_complete");
@@ -1004,13 +1137,6 @@ static void handle_browse_request(request_state *request)
         unlink_request(request);
         return;
         }
-    q = mallocL("handle_browse_request", sizeof(DNSQuestion));
-    if (!q)
-       {
-        my_perror("ERROR: handle_browse_request - malloc");
-        exit(1);
-       }
-    bzero(q, sizeof(DNSQuestion));
 
     // extract data from message
     ptr = request->msgdata;
@@ -1018,23 +1144,72 @@ static void handle_browse_request(request_state *request)
     interfaceIndex = get_long(&ptr);
     if (get_string(&ptr, regtype, MAX_ESCAPED_DOMAIN_NAME) < 0 || 
         get_string(&ptr, domain, MAX_ESCAPED_DOMAIN_NAME) < 0)
-        goto bad_param;
-        
+        goto bad_param;        
     freeL("handle_browse_request", request->msgbuf);
     request->msgbuf = NULL;
 
-    mDNSInterfaceID InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex);
+    InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS, interfaceIndex);
     if (interfaceIndex && !InterfaceID) goto bad_param;
-    q->QuestionContext = request;
-    q->QuestionCallback = browse_result_callback;
-    if (!MakeDomainNameFromDNSNameString(&typedn, regtype) ||
-        !MakeDomainNameFromDNSNameString(&domdn, domain[0] ? domain : "local."))
-        goto bad_param;
-    request->termination_context = q;
+
+       if (!MakeDomainNameFromDNSNameString(&typedn, regtype)) goto bad_param;
+
+       //!!!KRS browse locally for ichat
+       if (!domain[0] && (!strcmp(regtype, "_ichat._tcp.") || !strcmp(regtype, "_presence._tcp.")))
+               strcpy(domain,"local.");
+       
+       if (domain[0])
+               {
+               // generate a fake list of one elem to reduce number of code paths
+               if (!MakeDomainNameFromDNSNameString(&tmp.name, domain)) goto bad_param;
+               tmp.next = NULL;
+               search_domain_list = &tmp;
+               }
+       else search_domain_list = mDNSPlatformGetSearchDomainList();
+
+       for (sdom = search_domain_list; sdom; sdom = sdom->next)
+               {
+               qlist_elem = mallocL("handle_browse_request", sizeof(qlist_t));
+               if (!qlist_elem)
+                       {
+                       my_perror("ERROR: handle_browse_request - malloc");
+                       exit(1);
+                       }
+               bzero(qlist_elem, sizeof(qlist_t));
+               qlist_elem->q.QuestionContext = request;
+               qlist_elem->q.QuestionCallback = browse_result_callback;
+               qlist_elem->next = qlist;
+               qlist = qlist_elem;
+               }
+       
+       // setup termination context
+       term = (browse_termination_context *)mallocL("handle_browse_request", sizeof(browse_termination_context));
+       if (!term)
+       {
+        my_perror("ERROR: handle_browse_request - malloc");
+        exit(1);
+       }
+       term->qlist = qlist;
+       term->rstate = request;
+       request->termination_context = term;
     request->terminate = browse_termination_callback;
-    result = mDNS_StartBrowse(&mDNSStorage, q, &typedn, &domdn, InterfaceID, browse_result_callback, request);
-    deliver_error(request, result);
-    return;
+       
+       // start the browses
+       sdom = search_domain_list;
+       for (qlist_elem = qlist; qlist_elem; qlist_elem = qlist_elem->next)
+               {               
+               result = mDNS_StartBrowse(gmDNS, &qlist_elem->q, &typedn, &sdom->name, InterfaceID, browse_result_callback, request);
+               if (result)
+                       {
+                       // bail here on error.  questions not yet issued are in no core lists, so they can be deallocated lazily
+                       if (search_domain_list != &tmp) mDNS_FreeDNameList(search_domain_list);
+                       deliver_error(request, result);
+                       return;
+                       }
+               sdom = sdom->next;
+               }
+       if (search_domain_list != &tmp) mDNS_FreeDNameList(search_domain_list);
+       deliver_error(request, mStatus_NoError);
+       return;
     
 bad_param:
     deliver_error(request, mStatus_BadParamErr);
@@ -1042,13 +1217,12 @@ bad_param:
     unlink_request(request);
     }
 
-static void browse_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
+static void browse_result_callback(mDNS *const m _UNUSED, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
     {
     request_state *req;
     reply_state *rep;
     mStatus err;
         
-    #pragma unused(m)
     req = question->QuestionContext;
 
     err = gen_rr_response(&answer->rdata->u.name, answer->InterfaceID, req, &rep);
@@ -1068,11 +1242,78 @@ static void browse_result_callback(mDNS *const m, DNSQuestion *question, const R
 
 static void browse_termination_callback(void *context)
     {
-    DNSQuestion *q = context;
+       browse_termination_context *t = context;
+       qlist_t *ptr, *fptr;
+       
+       if (!t) return;
+
+       ptr = t->qlist;
+       t->qlist = NULL;
+
+       while(ptr)
+               {
+               mDNS_StopBrowse(gmDNS, &ptr->q);  // no need to error-check result
+               fptr = ptr;
+               ptr = ptr->next;
+               freeL("browse_termination_callback", fptr);
+               }
+       t->rstate->termination_context = NULL;
+       freeL("browse_termination_callback", t);
+       }
+
+static mStatus register_service(request_state *request, registered_service **srv_ptr, DNSServiceFlags flags,
+       uint16_t txtlen, void *txtdata, mDNSIPPort port, domainlabel *n, char *type_as_string,
+    domainname *t, domainname *d, domainname *h, mDNSBool autoname, int num_subtypes, mDNSInterfaceID InterfaceID)
+       {
+       registered_service *r_srv;
+    int srs_size, i;
+       char *sub;
+       mStatus result; 
+       *srv_ptr = NULL;
+       
+       r_srv = mallocL("handle_regservice_request", sizeof(registered_service));
+    if (!r_srv) goto malloc_error;
+    srs_size = sizeof(ServiceRecordSet) + (sizeof(RDataBody) > txtlen ? 0 : txtlen - sizeof(RDataBody));
+    r_srv->srs = mallocL("handle_regservice_request", srs_size);
+    if (!r_srv->srs) goto malloc_error;
+    if (num_subtypes > 0)
+        {
+        r_srv->subtypes = mallocL("handle_regservice_request", num_subtypes * sizeof(AuthRecord));
+        if (!r_srv->subtypes) goto malloc_error;
+        sub = type_as_string + strlen(type_as_string) + 1;
+        for (i = 0; i < num_subtypes; i++)
+            {
+            if (!MakeDomainNameFromDNSNameString(&(r_srv->subtypes + i)->resrec.name, sub))
+                {
+                               free_service_registration(r_srv);
+                return mStatus_BadParamErr;
+                }
+            sub += strlen(sub) + 1;
+            }
+        }
+    else r_srv->subtypes = NULL;
+    r_srv->request = request;
+    
+    r_srv->extras = NULL;
+    r_srv->autoname = autoname;
+    r_srv->rename_on_memfree = 0;
+    r_srv->renameonconflict = !(flags & kDNSServiceFlagsNoAutoRename);
+       memcpy(r_srv->name.c, n->c, n->c[0]);
+
+    result = mDNS_RegisterService(gmDNS, r_srv->srs, n, t, d, h, port,
+       txtdata, txtlen, r_srv->subtypes, num_subtypes, InterfaceID, regservice_callback, r_srv);
+
+       if (result)
+               free_service_registration(r_srv);
+       else *srv_ptr = r_srv;
+
+       return result;
+
+malloc_error:
+    my_perror("ERROR: malloc");
+    exit(1);
+       }
 
-    mDNS_StopBrowse(&mDNSStorage, q);  // no need to error-check result
-    freeL("browse_termination_callback", q);
-    }
 
 // service registration
 static void handle_regservice_request(request_state *request)
@@ -1083,18 +1324,15 @@ static void handle_regservice_request(request_state *request)
     uint16_t txtlen;
     mDNSIPPort port;
     void *txtdata;
-    char *ptr;
+    char *ptr, *sub;
     domainlabel n;
-    domainname t, d, h, srv;
-    registered_service *r_srv;
-    int srs_size;
+    domainname d, h, t, srv;
     mStatus result;
-
-    char *sub, *rtype_ptr;
-    int i, num_subtypes;
-    
+    mDNSInterfaceID InterfaceID;
+       int num_subtypes;
+    char *rtype_ptr;
     
-    if (request->ts != t_complete)
+       if (request->ts != t_complete)
         {
         LogMsg("ERROR: handle_regservice_request - transfer state != t_complete");
         abort_request(request);
@@ -1106,7 +1344,7 @@ static void handle_regservice_request(request_state *request)
     ptr = request->msgdata;
     flags = get_flags(&ptr);
     ifi = get_long(&ptr);
-    mDNSInterfaceID InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, ifi);
+    InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS, ifi);
     if (ifi && !InterfaceID) goto bad_param;
     if (get_string(&ptr, name, 256) < 0 ||
         get_string(&ptr, regtype, MAX_ESCAPED_DOMAIN_NAME) < 0 || 
@@ -1118,56 +1356,37 @@ static void handle_regservice_request(request_state *request)
     txtlen = get_short(&ptr);
     txtdata = get_rdata(&ptr, txtlen);
 
+    if (!*regtype || !MakeDomainNameFromDNSNameString(&t, regtype)) goto bad_param;
+
     // count subtypes, replacing commas w/ whitespace
     rtype_ptr = regtype;
     num_subtypes = -1;
     while((sub = strsep(&rtype_ptr, ",")))
         if (*sub) num_subtypes++;
         
-    if (!name[0]) n = (&mDNSStorage)->nicelabel;
+    if (!name[0]) n = (gmDNS)->nicelabel;
     else if (!MakeDomainLabelFromLiteralString(&n, name))  
         goto bad_param;
-    if ((!regtype[0] || !MakeDomainNameFromDNSNameString(&t, regtype)) ||
-    (!MakeDomainNameFromDNSNameString(&d, *domain ? domain : "local.")) ||
-    (!ConstructServiceName(&srv, &n, &t, &d)))
+       
+    if ((!MakeDomainNameFromDNSNameString(&d, *domain ? domain : "local.")) ||
+               (!ConstructServiceName(&srv, &n, &t, &d)))
         goto bad_param;
-    if (host[0] && !MakeDomainNameFromDNSNameString(&h, host)) goto bad_param;
 
-    r_srv = mallocL("handle_regservice_request", sizeof(registered_service));
-    if (!r_srv) goto malloc_error;
-    srs_size = sizeof(ServiceRecordSet) + (sizeof(RDataBody) > txtlen ? 0 : txtlen - sizeof(RDataBody));
-    r_srv->srs = mallocL("handle_regservice_request", srs_size);
-    if (!r_srv->srs) goto malloc_error;
-    if (num_subtypes > 0)
-        {
-        r_srv->subtypes = mallocL("handle_regservice_request", num_subtypes * sizeof(AuthRecord));
-        if (!r_srv->subtypes) goto malloc_error;
-        sub = regtype + strlen(regtype) + 1;
-        for (i = 0; i < num_subtypes; i++)
-            {
-            if (!MakeDomainNameFromDNSNameString(&(r_srv->subtypes + i)->resrec.name, sub))
-                {
-                freeL("handle_regservice_request", r_srv->subtypes);
-                freeL("handle_regservice_request", r_srv);
-                r_srv = NULL;
-                goto bad_param;
-                }
-            sub += strlen(sub) + 1;
-            }
-        }
-    else r_srv->subtypes = NULL;
-    r_srv->request = request;
-    
-    r_srv->autoname = (!name[0]);
-    r_srv->rename_on_memfree = 0;
-    r_srv->renameonconflict = !(flags & kDNSServiceFlagsNoAutoRename);
-    r_srv->name = n;
-    request->termination_context = r_srv;
+       if (host[0] && !MakeDomainNameFromDNSNameString(&h, host)) goto bad_param;
+
+       result = register_service(request, &request->servicepair.local, flags, txtlen, txtdata, port, &n,  &regtype[0], &t, &d, host[0] ? &h : NULL, !name[0], num_subtypes, InterfaceID);
+
+       //!!!KRS if we got a dynamic reg domain from the config file, use it for default (except for iChat)
+       if (!domain[0] && gmDNS->uDNS_info.ServiceRegDomain[0] && strcmp(regtype, "_presence._tcp.") && strcmp(regtype, "_ichat._tcp."))
+               {
+               MakeDomainNameFromDNSNameString(&d, gmDNS->uDNS_info.ServiceRegDomain);
+               register_service(request, &request->servicepair.global, flags, txtlen, txtdata, port, &n, &regtype[0], &t, &d, host[0] ? &h : NULL, !name[0], num_subtypes, InterfaceID);
+               // don't return default global errors - it will confuse legacy clients, and we want .local to still work for them
+               }
+               
+    request->termination_context = &request->servicepair;
     request->terminate = regservice_termination_callback;
-    request->service = r_srv;
     
-    result = mDNS_RegisterService(&mDNSStorage, r_srv->srs, &n, &t, &d, host[0] ? &h : NULL, port,
-       txtdata, txtlen, r_srv->subtypes, num_subtypes, InterfaceID, regservice_callback, r_srv);
     deliver_error(request, result);
     if (result != mStatus_NoError) 
         {
@@ -1175,34 +1394,28 @@ static void handle_regservice_request(request_state *request)
         unlink_request(request);
         }
     else 
-        {
         reset_connected_rstate(request);  // reset to receive add/remove messages
-        }
+
     return;
 
 bad_param:
     deliver_error(request, mStatus_BadParamErr);
     abort_request(request);
     unlink_request(request);
-return;
-
-malloc_error:
-    my_perror("ERROR: malloc");
-    exit(1);
     }
-    
+
+
+
+
 // service registration callback performs three duties - frees memory for deregistered services,
 // handles name conflicts, and delivers completed registration information to the client (via
 // process_service_registraion())
 
-static void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, mStatus result)
+static void regservice_callback(mDNS *const m _UNUSED, ServiceRecordSet *const srs, mStatus result)
     {
     mStatus err;
-    ExtraResourceRecord *extra;
     registered_service *r_srv = srs->ServiceContext;
     request_state *rs = r_srv->request;
-
-    #pragma unused(m)
     
     if (!rs && (result != mStatus_MemFree && !r_srv->rename_on_memfree))
         {     
@@ -1218,23 +1431,14 @@ static void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, mSta
         if (r_srv->rename_on_memfree)
             {
             r_srv->rename_on_memfree = 0;
-            r_srv->name = mDNSStorage.nicelabel;
-            err = mDNS_RenameAndReregisterService(&mDNSStorage, srs, &r_srv->name);
+            r_srv->name = gmDNS->nicelabel;
+            err = mDNS_RenameAndReregisterService(gmDNS, srs, &r_srv->name);
             if (err) LogMsg("ERROR: regservice_callback - RenameAndReregisterService returned %d", err);
             // error should never happen - safest to log and continue
             }
         else 
             {
-            while (r_srv->srs->Extras)
-                {
-                extra = r_srv->srs->Extras;
-                r_srv->srs->Extras = r_srv->srs->Extras->next;
-                freeL("regservice_callback", extra);
-                }
-            freeL("regservice_callback", r_srv->srs);
-            if (r_srv->subtypes) freeL("regservice_callback", r_srv->subtypes);
-            if (r_srv->request) r_srv->request->service = NULL;
-            freeL("regservice_callback", r_srv);
+                       free_service_registration(r_srv);
             return;
             }
         }
@@ -1242,17 +1446,13 @@ static void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, mSta
        {
         if (r_srv->autoname || r_srv->renameonconflict)
             {
-            mDNS_RenameAndReregisterService(&mDNSStorage, srs, mDNSNULL);
+            mDNS_RenameAndReregisterService(gmDNS, srs, mDNSNULL);
             return;
             }
         else
             {
-            freeL("regservice_callback", r_srv);
-            freeL("regservice_callback", r_srv->srs);
-            if (r_srv->subtypes) freeL("regservice_callback", r_srv->subtypes);
-            if (r_srv->request) r_srv->request->service = NULL;
-            freeL("regservice_callback", r_srv);
-             if (deliver_async_error(rs, reg_service_reply, result) < 0) 
+                       free_service_registration(r_srv);
+                       if (deliver_async_error(rs, reg_service_reply, result) < 0) 
                 {
                 abort_request(rs);
                 unlink_request(rs);
@@ -1262,7 +1462,7 @@ static void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, mSta
        } 
     else 
         {
-        LogMsg("ERROR: unknown result in regservice_callback");
+        LogMsg("ERROR: unknown result in regservice_callback: %d", result);
         if (deliver_async_error(rs, reg_service_reply, result) < 0) 
             {
             abort_request(rs);
@@ -1271,25 +1471,61 @@ static void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, mSta
         return;
         }
     }
+
+static mStatus add_record_to_service(request_state *rstate, registered_service *r_srv, uint16_t rrtype, uint16_t rdlen, char *rdata, uint32_t ttl)
+       {
+       ServiceRecordSet *srs = r_srv->srs;
+    ExtraResourceRecord *extra;
+    extra_record_entry *ere;
+       mStatus result;
+       int size;
+       
+       if (rdlen > sizeof(RDataBody)) size = rdlen;
+    else size = sizeof(RDataBody);
+       
+    ere = mallocL("hanle_add_request", sizeof(extra_record_entry) - sizeof(RDataBody) + size);
+    if (!ere)
+        {
+        my_perror("ERROR: malloc");
+        exit(1);
+        }
         
+    bzero(ere, sizeof(ExtraResourceRecord));  // OK if oversized rdata not zero'd
+    extra = &ere->e;
+    extra->r.resrec.rrtype = rrtype;
+    extra->r.rdatastorage.MaxRDLength = size;
+    extra->r.resrec.rdlength = rdlen;
+    memcpy(&extra->r.rdatastorage.u.data, rdata, rdlen);
+
+    result =  mDNS_AddRecordToService(gmDNS, srs , extra, &extra->r.rdatastorage, ttl);
+       if (result) { freeL("handle_add_request", ere); return result; }
+
+    ere->key = rstate->hdr.reg_index;
+    ere->next = r_srv->extras;
+    r_srv->extras = ere;
+       return result;
+       }
+
+
 static void handle_add_request(request_state *rstate)
     {
-    registered_record_entry *re;
-    ExtraResourceRecord *extra;
-    uint32_t size, ttl;
+    uint32_t ttl;
     uint16_t rrtype, rdlen;
     char *ptr, *rdata;
     mStatus result;
     DNSServiceFlags flags;
-    ServiceRecordSet *srs = rstate->service->srs;
-    
-    if (!srs)
+       registered_service *local, *global;
+
+       local = rstate->servicepair.local;
+       global = rstate->servicepair.global;
+
+       if (!local)
         {
-        LogMsg("ERROR: handle_add_request - no service record set in request state");
+        LogMsg("ERROR: handle_add_request - no service registered");
         deliver_error(rstate, mStatus_UnknownErr);
         return;
-        }
-        
+        }      
+
     ptr = rstate->msgdata;
     flags = get_flags(&ptr);
     rrtype = get_short(&ptr);
@@ -1297,95 +1533,108 @@ static void handle_add_request(request_state *rstate)
     rdata = get_rdata(&ptr, rdlen);
     ttl = get_long(&ptr);
     
-    if (rdlen > sizeof(RDataBody)) size = rdlen;
-    else size = sizeof(RDataBody);
-    
-    extra = mallocL("hanle_add_request", sizeof(ExtraResourceRecord) - sizeof(RDataBody) + size);
-    if (!extra)
-        {
-        my_perror("ERROR: malloc");
-        exit(1);
-        }
-        
-    bzero(extra, sizeof(ExtraResourceRecord));  // OK if oversized rdata not zero'd
-    extra->r.resrec.rrtype = rrtype;
-    extra->r.rdatastorage.MaxRDLength = size;
-    extra->r.resrec.rdlength = rdlen;
-    memcpy(&extra->r.rdatastorage.u.data, rdata, rdlen);
-    result =  mDNS_AddRecordToService(&mDNSStorage, srs , extra, &extra->r.rdatastorage, ttl);
+       result = add_record_to_service(rstate, local, rrtype, rdlen, rdata, ttl);
+       if (global) add_record_to_service(rstate, global, rrtype, rdlen, rdata, ttl); // don't report global errors to client
+       
     deliver_error(rstate, result);
     reset_connected_rstate(rstate);
-    if (result) 
-        {
-        freeL("handle_add_request", rstate->msgbuf);
-        rstate->msgbuf = NULL;
-        freeL("handle_add_request", extra);
-        return;
-        }
-    re = mallocL("handle_add_request", sizeof(registered_record_entry));
-    if (!re)
+    }
+
+static mStatus update_record(AuthRecord *rr, uint16_t rdlen, char *rdata, uint32_t ttl)
+       {       
+       int rdsize;
+       RData *newrd;
+       mStatus result;
+       
+       if (rdlen > sizeof(RDataBody)) rdsize = rdlen;
+    else rdsize = sizeof(RDataBody);
+    newrd = mallocL("handle_update_request", sizeof(RData) - sizeof(RDataBody) + rdsize);
+    if (!newrd)
         {
         my_perror("ERROR: malloc");
         exit(1);
         }
-    re->key = rstate->hdr.reg_index;
-    re->rr = &extra->r;
-    re->next = rstate->reg_recs;
-    rstate->reg_recs = re;
-    }
-    
+    newrd->MaxRDLength = rdsize;
+    memcpy(&newrd->u, rdata, rdlen);
+    result = mDNS_Update(gmDNS, rr, ttl, rdlen, newrd, update_callback);
+       if (result) { LogMsg("ERROR: mDNS_Update - %d", result); freeL("handle_update_request", newrd); }
+       return result;
+       }
+
+static mStatus find_extras_by_key(request_state *rstate, AuthRecord **lRR, AuthRecord **gRR)   
+       {
+       extra_record_entry *e;
+       
+       // find the extra record for the local service
+       for (e = rstate->servicepair.local->extras; e; e = e->next)
+               if (e->key == rstate->hdr.reg_index) break;
+       if (!e) return mStatus_BadReferenceErr;
+
+       *lRR = &e->e.r;
+
+       // find the corresponding global record, if it exists
+       if (rstate->servicepair.global)
+               {
+               for (e = rstate->servicepair.global->extras; e; e = e->next)
+                       if (e->key == rstate->hdr.reg_index) break;
+               if (e) *gRR = &e->e.r;
+               else *gRR = NULL;
+               }
+       return mStatus_NoError;
+       }
+
 static void handle_update_request(request_state *rstate)
     {
     registered_record_entry *reptr;
-    AuthRecord *rr;
-    RData *newrd;
-    uint16_t rdlen, rdsize;
+    AuthRecord *lRR, *gRR = NULL;
+    uint16_t rdlen;
     char *ptr, *rdata;
     uint32_t ttl;
     mStatus result;
-    
+       
     if (rstate->hdr.reg_index == TXT_RECORD_INDEX)
         {
-        if (!rstate->service)
+               if (!rstate->servicepair.local)
             {
             deliver_error(rstate, mStatus_BadParamErr);
             return;
             }
-        rr  = &rstate->service->srs->RR_TXT;
+               lRR = &rstate->servicepair.local->srs->RR_TXT;
+               if (rstate->servicepair.global) gRR = &rstate->servicepair.global->srs->RR_TXT;
         }
     else
         {
-        reptr = rstate->reg_recs;
-        while(reptr && reptr->key != rstate->hdr.reg_index) reptr = reptr->next;
-        if (!reptr) deliver_error(rstate, mStatus_BadReferenceErr); 
-        rr = reptr->rr;
-        }
+               if (rstate->servicepair.local) // registered service
+                       {
+                       if (find_extras_by_key(rstate, &lRR, &gRR))
+                               { deliver_error(rstate, mStatus_BadReferenceErr); return; }
+                       }
+               else
+                       {
+                       // record created via RegisterRecord                    
+                       reptr = rstate->reg_recs;
+                       while(reptr && reptr->key != rstate->hdr.reg_index) reptr = reptr->next;                        
+                       if (!reptr) { deliver_error(rstate, mStatus_BadReferenceErr); return; }
+                       lRR = reptr->rr;
+                       }
+               }
 
-    ptr = rstate->msgdata;
+       // get the message data
+       ptr = rstate->msgdata;
     get_flags(&ptr);   // flags unused
     rdlen = get_short(&ptr);
     rdata = get_rdata(&ptr, rdlen);
     ttl = get_long(&ptr);
 
-    if (rdlen > sizeof(RDataBody)) rdsize = rdlen;
-    else rdsize = sizeof(RDataBody);
-    newrd = mallocL("handle_update_request", sizeof(RData) - sizeof(RDataBody) + rdsize);
-    if (!newrd)
-        {
-        my_perror("ERROR: malloc");
-        exit(1);
-        }
-    newrd->MaxRDLength = rdsize;
-    memcpy(&newrd->u, rdata, rdlen);
-    result = mDNS_Update(&mDNSStorage, rr, ttl, rdlen, newrd, update_callback);
+       result = update_record(lRR, rdlen, rdata, ttl);
+       if (gRR) update_record(gRR, rdlen, rdata, ttl);  // don't report errors for global registration
+       
     deliver_error(rstate, result);
     reset_connected_rstate(rstate);
     }
     
-static void update_callback(mDNS *const m, AuthRecord *const rr, RData *oldrd)
-    {
-    #pragma unused(m)
-    
+static void update_callback(mDNS *const m _UNUSED, AuthRecord *const rr, RData *oldrd)
+    {    
     if (oldrd != &rr->rdatastorage) freeL("update_callback", oldrd);
     }
     
@@ -1419,19 +1668,53 @@ static void process_service_registration(ServiceRecordSet *const srs)
     else append_reply(req, rep);
     }
 
+static void free_service_registration(registered_service *srv)
+       {
+       request_state *rstate = srv->request;
+       extra_record_entry *extra;
+       
+       // clear pointers from parent struct
+       if (rstate)
+               {
+               if (rstate->servicepair.local == srv) rstate->servicepair.local = NULL;
+               else if (rstate->servicepair.global == srv) rstate->servicepair.global = NULL;
+               }
+
+       while (srv->extras)
+               {
+               extra = srv->extras;
+               srv->extras = srv->extras->next;
+               if (extra->e.r.resrec.rdata != &extra->e.r.rdatastorage)
+                       freeL("free_service_registration", extra->e.r.resrec.rdata);
+               freeL("regservice_callback", extra);
+               }
+       
+       if (srv->subtypes) { freeL("regservice_callback", srv->subtypes); srv->subtypes = NULL; }
+       freeL("regservice_callback", srv->srs);
+       srv->srs = NULL;
+       freeL("regservice_callback", srv);
+       }
+
 static void regservice_termination_callback(void *context)
     {
-    registered_service *srv = context;
+    servicepair_t *pair = context;
+
+       if (!pair->local && !pair->global) { LogMsg("ERROR: regservice_termination_callback called with null services"); return; }
 
+       // clear service pointers to parent request state
+       if (pair->local) pair->local->request = NULL;
+       if (pair->global) pair->global->request = NULL;
+       
     // only safe to free memory if registration is not valid, ie deregister fails
-    if (mDNS_DeregisterService(&mDNSStorage, srv->srs) != mStatus_NoError)
-        {
-        freeL("regservice_callback", srv->srs);
-        if (srv->subtypes) freeL("regservice_callback", srv->subtypes);
-        freeL("regservice_callback", srv);
-        freeL("regservice_termination_callback", srv);
-        }
-    }
+    if (pair->local && mDNS_DeregisterService(gmDNS, pair->local->srs) != mStatus_NoError)
+               free_service_registration(pair->local);
+       if (pair->global && mDNS_DeregisterService(gmDNS, pair->global->srs) != mStatus_NoError)
+               free_service_registration(pair->global);
+
+       // clear pointers to services - they'll get cleaned by MemFree callback
+       pair->local = NULL;
+       pair->global = NULL;    
+       }
 
 
 static void handle_regrecord_request(request_state *rstate)
@@ -1449,13 +1732,13 @@ static void handle_regrecord_request(request_state *rstate)
         return;
         }
         
-    rr = read_rr_from_ipc_msg(rstate->msgdata, 1);
+    rr = read_rr_from_ipc_msg(rstate->msgdata, 1, 1);
     if (!rr) 
         {
         deliver_error(rstate, mStatus_BadParamErr);
         return;
         }
-
+       
     rcc = mallocL("hanlde_regrecord_request", sizeof(regrecord_callback_context));
     if (!rcc) goto malloc_error;
     rcc->rstate = rstate;
@@ -1477,7 +1760,7 @@ static void handle_regrecord_request(request_state *rstate)
         rstate->termination_context = rstate;
        }
     
-    result = mDNS_Register(&mDNSStorage, rr);
+    result = mDNS_Register(gmDNS, rr);
     deliver_error(rstate, result); 
     reset_connected_rstate(rstate);
     return;
@@ -1487,17 +1770,20 @@ malloc_error:
     return;
     }
 
-static void regrecord_callback(mDNS *const m, AuthRecord *const rr, mStatus result)
+static void regrecord_callback(mDNS *const m _UNUSED, AuthRecord *const rr, mStatus result)
     {
-    regrecord_callback_context *rcc;
+    regrecord_callback_context *rcc = rr->RecordContext;
     int len;
     reply_state *reply;
     transfer_state ts;
 
-    #pragma unused(m)
-
-    if (result == mStatus_MemFree)     { freeL("regrecord_callback", rr);  return; }
-    rcc = rr->RecordContext;
+    if (result == mStatus_MemFree)     
+        { 
+        freeL("regrecord_callback", rcc);
+        rr->RecordContext = NULL;        
+        freeL("regrecord_callback", rr);
+        return; 
+        }
 
     // format result, add to the list for the request, including the client context in the header
     len = sizeof(DNSServiceFlags);
@@ -1507,7 +1793,7 @@ static void regrecord_callback(mDNS *const m, AuthRecord *const rr, mStatus resu
     reply = create_reply(reg_record_reply, len, rcc->rstate);
     reply->mhdr->client_context = rcc->client_context;
     reply->rhdr->flags = 0;
-    reply->rhdr->ifi = mDNSPlatformInterfaceIndexfromInterfaceID(&mDNSStorage, rr->resrec.InterfaceID);
+    reply->rhdr->ifi = mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS, rr->resrec.InterfaceID);
     reply->rhdr->error = result;
 
     ts = send_msg(reply);
@@ -1522,55 +1808,127 @@ static void regrecord_callback(mDNS *const m, AuthRecord *const rr, mStatus resu
 
 static void connected_registration_termination(void *context)
     {
+    int shared;
     registered_record_entry *fptr, *ptr = ((request_state *)context)->reg_recs;
     while(ptr)
-       {
-        mDNS_Deregister(&mDNSStorage, ptr->rr);
+        {
         fptr = ptr;
         ptr = ptr->next;
+        shared = fptr->rr->resrec.RecordType == kDNSRecordTypeShared;
+        mDNS_Deregister(gmDNS, fptr->rr);
+        if (!shared)
+            // shared records free'd via callback w/ mStatus_MemFree
+            {
+            freeL("connected_registration_termination", fptr->rr->RecordContext);
+            fptr->rr->RecordContext = NULL;            
+            freeL("connected_registration_termination", fptr->rr);
+            fptr->rr = NULL;
+            }
         freeL("connected_registration_termination", fptr);
-       }
+        }
     }
     
 
 
 static void handle_removerecord_request(request_state *rstate)
     {
-    registered_record_entry *reptr, *prev = NULL;
-    mStatus err = mStatus_UnknownErr;
+    mStatus err;
     char *ptr;
-    reptr = rstate->reg_recs;
 
     ptr = rstate->msgdata;
     get_flags(&ptr);   // flags unused
 
+    if (rstate->servicepair.local) err = remove_extra_rr_from_service(rstate);
+    else err = remove_record(rstate);
+
+    reset_connected_rstate(rstate);
+    if (deliver_error(rstate, err) < 0)
+        {
+        abort_request(rstate);
+        unlink_request(rstate);
+        }
+    }
+
+// remove a resource record registered via DNSServiceRegisterRecord()
+static mStatus remove_record(request_state *rstate)
+    {
+    int shared;
+    registered_record_entry *reptr, *prev = NULL;
+    mStatus err = mStatus_UnknownErr;
+    reptr = rstate->reg_recs;
+
     while(reptr)
        {
         if (reptr->key == rstate->hdr.reg_index)  // found match
             {
             if (prev) prev->next = reptr->next;
             else rstate->reg_recs = reptr->next;
-            err  = mDNS_Deregister(&mDNSStorage, reptr->rr);
-            freeL("handle_removerecord_request", reptr);  //rr gets freed by callback
+            shared = reptr->rr->resrec.RecordType == kDNSRecordTypeShared;
+            err  = mDNS_Deregister(gmDNS, reptr->rr);
+               if (err) 
+                   {
+                   LogMsg("ERROR: remove_record, mDNS_Deregister: %d", err);
+                   return err; // this should not happen.  don't try to free memory if there's an error
+                   }
+            if (!shared)
+                   // shared records free'd via callback w/ mStatus_MemFree            
+                   {
+                freeL("remove_record", reptr->rr->RecordContext);
+                reptr->rr->RecordContext = NULL;
+                   freeL("remove_record", reptr->rr);
+                   reptr->rr = NULL;
+                   }
+            freeL("remove_record", reptr);         
             break;
             }
         prev = reptr;
         reptr = reptr->next;
        }
-    reset_connected_rstate(rstate);
-    if (deliver_error(rstate, err) < 0)
-        {
-        abort_request(rstate);
-        unlink_request(rstate);
-        }
+    return err;
+    }
+
+
+static mStatus remove_extra(request_state *rstate, registered_service *serv)
+       {
+       mStatus err = mStatus_BadReferenceErr;
+       extra_record_entry *ptr, *prev = NULL;
+    
+    ptr = serv->extras;
+    while (ptr)
+               {
+               if (ptr->key == rstate->hdr.reg_index) // found match
+                       {
+                       if (prev) prev->next = ptr->next;
+                       else serv->extras = ptr->next;
+                       err = mDNS_RemoveRecordFromService(gmDNS, serv->srs, &ptr->e);
+                       if (err) return err;
+                       freeL("remove_extra_rr_from_service", ptr);
+                       break;
+                       }
+               prev = ptr;
+               ptr = ptr->next;
+               }
+       return err;
+       }
+
+static mStatus remove_extra_rr_from_service(request_state *rstate)
+    {
+    mStatus err = mStatus_UnknownErr;
+
+       err = remove_extra(rstate, rstate->servicepair.local);
+       if (rstate->servicepair.global) remove_extra(rstate, rstate->servicepair.global); // don't return error for global
+
+       return err;
     }
 
 
+
 // domain enumeration
 static void handle_enum_request(request_state *rstate)
     {
     DNSServiceFlags flags, add_default;
     uint32_t ifi;
+    mDNSInterfaceID InterfaceID;
     char *ptr = rstate->msgdata;
     domain_enum_t *def, *all;
     enum_termination_t *term;
@@ -1589,7 +1947,7 @@ static void handle_enum_request(request_state *rstate)
         
     flags = get_flags(&ptr);
     ifi = get_long(&ptr);
-    mDNSInterfaceID InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, ifi);
+    InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS, ifi);
     if (ifi && !InterfaceID)
        {
                deliver_error(rstate, mStatus_BadParamErr);
@@ -1622,11 +1980,14 @@ static void handle_enum_request(request_state *rstate)
     all->question.QuestionContext = all;
     all->type = (flags & kDNSServiceFlagsRegistrationDomains) ? 
         mDNS_DomainTypeRegistration : mDNS_DomainTypeBrowse;
-    
+
+       // if the caller hasn't specified an explicit interface, we use local-only to get the system-wide list.
+       if (!InterfaceID) InterfaceID = mDNSInterface_LocalOnly;
+       
     // make the calls
-    err = mDNS_GetDomains(&mDNSStorage, &all->question, all->type, InterfaceID, enum_result_callback, all);
+    err = mDNS_GetDomains(gmDNS, &all->question, all->type, NULL, InterfaceID, enum_result_callback, all);
     if (err == mStatus_NoError)
-        err = mDNS_GetDomains(&mDNSStorage, &def->question, def->type, InterfaceID, enum_result_callback, def);
+        err = mDNS_GetDomains(gmDNS, &def->question, def->type, NULL, InterfaceID, enum_result_callback, def);
     result = deliver_error(rstate, err);  // send error *before* returning local domain
     
     if (result < 0 || err)
@@ -1637,7 +1998,7 @@ static void handle_enum_request(request_state *rstate)
         }
 
     // provide local. as the first domain automatically
-    add_default = kDNSServiceFlagsDefault | kDNSServiceFlagsAdd | kDNSServiceFlagsFinished;
+    add_default = kDNSServiceFlagsDefault | kDNSServiceFlagsAdd;
     reply = format_enumeration_reply(rstate, "local.", add_default, ifi, 0);
     tr = send_msg(reply);
     if (tr == t_error || tr == t_terminated) 
@@ -1652,14 +2013,13 @@ static void handle_enum_request(request_state *rstate)
     if (tr == t_morecoming) append_reply(rstate, reply); // couldn't send whole reply because client is blocked - link into list
     }
 
-static void enum_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
+static void enum_result_callback(mDNS *const m _UNUSED, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
     {
     char domain[MAX_ESCAPED_DOMAIN_NAME];
     domain_enum_t *de = question->QuestionContext;
     DNSServiceFlags flags = 0;
     reply_state *reply;
 
-    #pragma unused(m)
     if (answer->rrtype != kDNSType_PTR) return;
     if (AddRecord)
        {
@@ -1667,12 +2027,8 @@ static void enum_result_callback(mDNS *const m, DNSQuestion *question, const Res
         if (de->type == mDNS_DomainTypeRegistrationDefault || de->type == mDNS_DomainTypeBrowseDefault)
             flags |= kDNSServiceFlagsDefault;
        }
-    else
-       {
-        flags |= kDNSServiceFlagsRemove;
-       }
     ConvertDomainNameToCString(&answer->rdata->u.name, domain);
-    reply = format_enumeration_reply(de->rstate, domain, flags, mDNSPlatformInterfaceIndexfromInterfaceID(&mDNSStorage, answer->InterfaceID), kDNSServiceErr_NoError);
+    reply = format_enumeration_reply(de->rstate, domain, flags, mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS, answer->InterfaceID), kDNSServiceErr_NoError);
     if (!reply)
        {
         LogMsg("ERROR: enum_result_callback, format_enumeration_reply");
@@ -1683,7 +2039,7 @@ static void enum_result_callback(mDNS *const m, DNSQuestion *question, const Res
     return;
     }
 
-static reply_state *format_enumeration_reply(request_state *rstate, char *domain, DNSServiceFlags flags, uint32_t ifi, DNSServiceErrorType err)
+static reply_state *format_enumeration_reply(request_state *rstate, const char *domain, DNSServiceFlags flags, uint32_t ifi, DNSServiceErrorType err)
     {
     int len;
     reply_state *reply;
@@ -1707,7 +2063,7 @@ static reply_state *format_enumeration_reply(request_state *rstate, char *domain
 static void enum_termination_callback(void *context)
     {
     enum_termination_t *t = context;
-    mDNS *coredata = &mDNSStorage;
+    mDNS *coredata = gmDNS;
 
     mDNS_StopGetDomains(coredata, &t->all->question);
     mDNS_StopGetDomains(coredata, &t->def->question);
@@ -1721,9 +2077,9 @@ static void handle_reconfirm_request(request_state *rstate)
     {
     AuthRecord *rr;
 
-    rr = read_rr_from_ipc_msg(rstate->msgdata, 0);
+    rr = read_rr_from_ipc_msg(rstate->msgdata, 0, 1);
     if (!rr) return;
-    mDNS_ReconfirmByValue(&mDNSStorage, &rr->resrec);
+    mDNS_ReconfirmByValue(gmDNS, &rr->resrec);
     abort_request(rstate);
     unlink_request(rstate);
     freeL("handle_reconfirm_request", rr);
@@ -1746,7 +2102,7 @@ static void reset_connected_rstate(request_state *rstate)
 // returns a resource record (allocated w/ malloc) containing the data found in an IPC message
 // data must be in format flags, interfaceIndex, name, rrtype, rrclass, rdlen, rdata, (optional)ttl
 // (ttl only extracted/set if ttl argument is non-zero).  returns NULL for a bad-parameter error
-static AuthRecord *read_rr_from_ipc_msg(char *msgbuf, int ttl)
+static AuthRecord *read_rr_from_ipc_msg(char *msgbuf, int ttl, int validate_flags)
     {
     char *rdata, name[256];
     AuthRecord *rr;
@@ -1756,7 +2112,15 @@ static AuthRecord *read_rr_from_ipc_msg(char *msgbuf, int ttl)
     int storage_size;
 
     flags = get_flags(&msgbuf);
-    interfaceIndex = get_long(&msgbuf);
+       if (validate_flags &&
+               !((flags & kDNSServiceFlagsShared) == kDNSServiceFlagsShared) &&
+               !((flags & kDNSServiceFlagsUnique) == kDNSServiceFlagsUnique))
+               {
+               LogMsg("ERROR: Bad resource record flags (must be kDNSServiceFlagsShared or kDNSServiceFlagsUnique)");
+               return NULL;
+               }
+       
+       interfaceIndex = get_long(&msgbuf);
     if (get_string(&msgbuf, name, 256) < 0)
         {
         LogMsg("ERROR: read_rr_from_ipc_msg - get_string");
@@ -1777,7 +2141,7 @@ static AuthRecord *read_rr_from_ipc_msg(char *msgbuf, int ttl)
         }
     bzero(rr, sizeof(AuthRecord));  // ok if oversized rdata not zero'd
     rr->resrec.rdata = &rr->rdatastorage;
-    rr->resrec.InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex);
+    rr->resrec.InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS, interfaceIndex);
     if (!MakeDomainNameFromDNSNameString(&rr->resrec.name, name))
        {
         LogMsg("ERROR: bad name: %s", name);
@@ -1785,7 +2149,7 @@ static AuthRecord *read_rr_from_ipc_msg(char *msgbuf, int ttl)
         return NULL;
        }
     rr->resrec.rrtype = type;
-    if ((flags & kDNSServiceFlagsShared) == kDNSServiceFlagsShared)
+       if ((flags & kDNSServiceFlagsShared) == kDNSServiceFlagsShared)
         rr->resrec.RecordType = kDNSRecordTypeShared;
     if ((flags & kDNSServiceFlagsUnique) == kDNSServiceFlagsUnique)
         rr->resrec.RecordType = kDNSRecordTypeUnique;
@@ -1835,7 +2199,7 @@ static mStatus gen_rr_response(domainname *servicename, mDNSInterfaceID id, requ
     
     *rep = create_reply(query_reply, len, request);
     (*rep)->rhdr->flags = 0;
-    (*rep)->rhdr->ifi = mDNSPlatformInterfaceIndexfromInterfaceID(&mDNSStorage, id);
+    (*rep)->rhdr->ifi = mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS, id);
     (*rep)->rhdr->error = kDNSServiceErr_NoError;    
     data = (*rep)->sdata;
     
@@ -1935,7 +2299,7 @@ static int read_msg(request_state *rs)
         
         if (!rs->msgbuf)  // allocate the buffer first time through
             {
-            rs->msgbuf = mallocL("read_msg", rs->hdr.datalen);
+            rs->msgbuf = mallocL("read_msg", rs->hdr.datalen + MSG_PAD_BYTES);
             if (!rs->msgbuf)
                {
                 my_perror("ERROR: malloc");
@@ -1944,6 +2308,7 @@ static int read_msg(request_state *rs)
                }
             rs->msgdata = rs->msgbuf;
             }
+            bzero(rs->msgbuf, rs->hdr.datalen + MSG_PAD_BYTES);
         nleft = rs->hdr.datalen - rs->data_bytes;
         nread = recv(rs->sd, rs->msgbuf + rs->data_bytes, nleft, 0);
         if (nread == 0)        { rs->ts = t_terminated;  return t_terminated;  }
@@ -2160,11 +2525,7 @@ static void abort_request(request_state *rs)
 
     if (rs->terminate) rs->terminate(rs->termination_context);  // terminate field may not be set yet
     if (rs->msgbuf) freeL("abort_request", rs->msgbuf);
-    CFRunLoopRemoveSource(CFRunLoopGetCurrent(), rs->rls, kCFRunLoopDefaultMode);
-    CFRunLoopSourceInvalidate(rs->rls);
-    CFRelease(rs->rls);
-    CFSocketInvalidate(rs->sr);
-    CFRelease(rs->sr);
+    udsSupportRemoveFDFromEventLoop(rs->sd);
     rs->sd = -1;
     if (rs->errfd >= 0) close(rs->errfd);
     rs->errfd = -1;
@@ -2214,4 +2575,64 @@ static void my_perror(char *errmsg)
     LogMsg("%s: %s", errmsg, strerror(errno));
     }
 
+// check that the message delivered by the client is sufficiently long to extract the required data from the buffer
+// without overrunning it.
+// returns 0 on success, -1 on error.
+
+static int validate_message(request_state *rstate)
+    {
+    uint32_t min_size;
+    
+    switch(rstate->hdr.op.request_op)
+       {
+        case resolve_request: min_size =       sizeof(DNSServiceFlags) +       // flags
+                                               sizeof(uint32_t) +              // interface
+                                               (3 * sizeof(char));             // name, regtype, domain
+                                               break;  
+        case query_request: min_size =                 sizeof(DNSServiceFlags) +       // flags
+                                               sizeof(uint32_t) +              // interface
+                                               sizeof(char) +                  // fullname
+                                               (2 * sizeof(uint16_t));         // type, class
+                                               break;
+        case browse_request: min_size =        sizeof(DNSServiceFlags) +       // flags
+                                               sizeof(uint32_t) +              // interface
+                                               (2 * sizeof(char));             // regtype, domain
+                                               break;
+        case reg_service_request: min_size =   sizeof(DNSServiceFlags) +       // flags
+                                               sizeof(uint32_t) +              // interface
+                                               (4 * sizeof(char)) +            // name, type, domain, host
+                                               (2 * sizeof(uint16_t));         // port, textlen        
+                                               break;  
+        case enumeration_request: min_size =   sizeof(DNSServiceFlags) +       // flags
+                                               sizeof(uint32_t);               // interface
+                                               break;
+        case reg_record_request: min_size =    sizeof(DNSServiceFlags) +       // flags
+                                               sizeof(uint32_t) +              // interface
+                                               sizeof(char) +                  // fullname
+                                               (3 * sizeof(uint16_t)) +        // type, class, rdlen
+                                               sizeof(uint32_t);               // ttl
+                                               break;
+        case add_record_request: min_size =    sizeof(DNSServiceFlags) +       // flags
+                                               (2 * sizeof(uint16_t)) +        // type, rdlen
+                                               sizeof(uint32_t);               // ttl
+                                               break;
+        case update_record_request: min_size = sizeof(DNSServiceFlags) +       // flags
+                                               sizeof(uint16_t) +              // rdlen
+                                               sizeof(uint32_t);               // ttl
+                                               break;
+        case remove_record_request: min_size = sizeof(DNSServiceFlags);        // flags
+                                               break;
+        case reconfirm_record_request: min_size=sizeof(DNSServiceFlags) +      // flags
+                                               sizeof(uint32_t) +              // interface
+                                               sizeof(char) +                  // fullname
+                                               (3 * sizeof(uint16_t));         // type, class, rdlen
+        default:
+            LogMsg("ERROR: validate_message - unsupported request type: %d", rstate->hdr.op.request_op);           
+           return -1;
+       }    
+    
+       return (rstate->data_bytes >= min_size ? 0 : -1);
+    
+    }
+
 
diff --git a/mDNSShared/uds_daemon.h b/mDNSShared/uds_daemon.h
new file mode 100644 (file)
index 0000000..0e25022
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+       File:           uds_daemon.h
+
+       Contains:       Interfaces necessary to talk to uds_daemon.c.
+
+       Version:        1.0
+
+    Change History (most recent first):
+
+$Log: uds_daemon.h,v $
+Revision 1.3  2004/01/25 00:03:21  cheshire
+Change to use mDNSVal16() instead of private PORT_AS_NUM() macro
+
+Revision 1.2  2004/01/24 08:46:26  bradley
+Added InterfaceID<->Index platform interfaces since they are now used by all platforms for the DNS-SD APIs.
+
+Revision 1.1  2003/12/08 21:11:42  rpantos;
+Changes necessary to support mDNSResponder on Linux.
+
+*/
+
+#include "mDNSClientAPI.h"
+
+
+/* Client interface: */
+
+#define SRS_PORT(S) mDNSVal16((S)->RR_SRV.resrec.rdata->u.srv.port)
+
+extern int udsserver_init( mDNS *globalInstance);
+
+// takes the next scheduled event time, does idle work, and returns the updated nextevent time
+extern mDNSs32 udsserver_idle(mDNSs32 nextevent);
+
+extern void udsserver_info(void);      // print out info about current state
+
+extern void udsserver_handle_configchange(void);
+
+extern int udsserver_exit(void);       // should be called prior to app exit
+
+
+/* Routines that uds_daemon expects to link against: */
+
+typedef        void (*udsEventCallback)(void *context);
+
+extern mStatus udsSupportAddFDToEventLoop( int fd, udsEventCallback callback, void *context);
+extern mStatus udsSupportRemoveFDFromEventLoop( int fd);
index eb6683e37ae9ba85eccc6f6150004ce9bf19749d..049f41c64819130f59b0487032d10cb60c9d3e5d 100644 (file)
@@ -3,6 +3,8 @@
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
 
        Contains:       mDNS platform plugin for VxWorks.
 
-       Copyright:  Copyright (C) 2002-2003 Apple Computer, Inc., All Rights Reserved.
+       Copyright:  Copyright (C) 2002-2004 Apple Computer, Inc., All Rights Reserved.
 
        Change History (most recent first):
 
 $Log: mDNSVxWorks.c,v $
-Revision 1.7.2.2  2004/04/09 17:57:31  cheshire
-Make sure to set the TxAndRx field so that duplicate suppression works correctly
+Revision 1.16  2004/04/22 05:11:28  bradley
+Added mDNSPlatformUTC for TSIG signed dynamic updates.
+
+Revision 1.15  2004/04/21 02:49:12  cheshire
+To reduce future confusion, renamed 'TxAndRx' to 'McastTxRx'
+
+Revision 1.14  2004/04/09 17:43:04  cheshire
+Make sure to set the McastTxRx field so that duplicate suppression works correctly
+
+Revision 1.13  2004/01/27 20:15:24  cheshire
+<rdar://problem/3541288>: Time to prune obsolete code for listening on port 53
 
-Revision 1.7.2.1  2004/04/03 21:31:20  bradley
-Integrated changes from TOT to remove legacy port 53 support.
+Revision 1.12  2004/01/24 09:12:37  bradley
+Avoid TOS socket options to workaround a TOS routing problem with VxWorks and multiple interfaces
+when sending unicast responses, which resulted in packets going out the wrong interface.
+
+Revision 1.11  2004/01/24 04:59:16  cheshire
+Fixes so that Posix/Linux, OS9, Windows, and VxWorks targets build again
+
+Revision 1.10  2003/11/14 21:27:09  cheshire
+<rdar://problem/3484766>: Security: Crashing bug in mDNSResponder
+Fix code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1005) instead of 256-byte buffers.
+
+Revision 1.9  2003/11/14 20:59:09  cheshire
+Clients can't use AssignDomainName macro because mDNSPlatformMemCopy is defined in mDNSPlatformFunctions.h.
+Best solution is just to combine mDNSClientAPI.h and mDNSPlatformFunctions.h into a single file.
 
 Revision 1.8  2003/10/28 10:08:27  bradley
 Removed legacy port 53 support as it is no longer needed.
@@ -110,7 +133,6 @@ mDNS platform plugin for VxWorks.
 #endif
 
 #include       "mDNSClientAPI.h"
-#include       "mDNSPlatformFunctions.h"
 
 #include       "mDNSVxWorks.h"
 
@@ -442,7 +464,6 @@ mStatus
                const DNSMessage * const        inMsg, 
                const mDNSu8 * const            inMsgEnd, 
                mDNSInterfaceID                         inInterfaceID, 
-               mDNSIPPort                                      inSrcPort, 
                const mDNSAddr *                        inDstIP, 
                mDNSIPPort                                      inDstPort )
 {
@@ -451,8 +472,6 @@ mStatus
        struct sockaddr_in              addr;
        int                                             n;
        
-       DEBUG_UNUSED( inSrcPort );
-       
        dlog( kDebugLevelChatty, DEBUG_NAME "platform send UDP\n" );
        
        // Check parameters.
@@ -509,6 +528,43 @@ 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 int mDNSPlatformReadTCP(int sd, void *buf, int buflen)
+       {
+       (void)sd;                       // Unused
+       (void)buf;                      // Unused
+       (void)buflen;                   // Unused
+       return(0);
+       }
+
+mDNSexport int mDNSPlatformWriteTCP(int sd, const char *msg, int len)
+       {
+       (void)sd;                       // Unused
+       (void)msg;                      // Unused
+       (void)len;                      // Unused
+       return(0);
+       }
+
 //===========================================================================================================================
 //     mDNSPlatformLock
 //===========================================================================================================================
@@ -668,6 +724,15 @@ mDNSs32    mDNSPlatformTimeNow( void )
        return( (mDNSs32) tickGet() );
 }
 
+//===========================================================================================================================
+//     mDNSPlatformUTC
+//===========================================================================================================================
+
+mDNSexport mDNSs32     mDNSPlatformUTC( void )
+{
+       return( -1 );
+}
+
 //===========================================================================================================================
 //     mDNSPlatformInterfaceNameToID
 //===========================================================================================================================
@@ -990,7 +1055,7 @@ mDNSlocal mStatus  SetupInterface( mDNS * const inMDNS, const struct ifaddrs *inA
        item->hostSet.ip.type                           = mDNSAddrType_IPv4;
        item->hostSet.ip.ip.v4.NotAnInteger     = ipv4->sin_addr.s_addr;
        item->hostSet.Advertise                 = inMDNS->AdvertiseLocalAddresses;
-       item->hostSet.TxAndRx                   = mDNStrue;
+       item->hostSet.McastTxRx                 = mDNStrue;
 
        err = mDNS_RegisterInterface( inMDNS, &item->hostSet );
        require_noerr( err, exit );
index de026a47dcbedb22f2b6f6b48e5758283710b3bf..537c0eedcc7576c146cef683478057af02ea4962 100644 (file)
@@ -3,6 +3,8 @@
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
diff --git a/mDNSWindows/Applications/DLL/dllmain.c b/mDNSWindows/Applications/DLL/dllmain.c
new file mode 100644 (file)
index 0000000..db9906e
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+    
+$Log: dllmain.c,v $
+Revision 1.1  2004/02/21 04:16:50  bradley
+DLL wrapper for DNS-SD API.
+
+*/
+
+#include       "DNSSD.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 );
+}
diff --git a/mDNSWindows/Applications/DLL/dnssd.def b/mDNSWindows/Applications/DLL/dnssd.def
new file mode 100644 (file)
index 0000000..587489e
--- /dev/null
@@ -0,0 +1,57 @@
+;
+; Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
+;
+; @APPLE_LICENSE_HEADER_START@
+; 
+; This file contains Original Code and/or Modifications of Original Code
+; as defined in and that are subject to the Apple Public Source License
+; Version 2.0 (the 'License'). You may not use this file except in
+; compliance with the License. Please obtain a copy of the License at
+; http://www.opensource.apple.com/apsl/ and read it before using this
+; file.
+; 
+; The Original Code and all software distributed under the License are
+; distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+; EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+; INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+; FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+; Please see the License for the specific language governing rights and
+; limitations under the License.
+; 
+; @APPLE_LICENSE_HEADER_END@
+;
+;      Change History (most recent first):
+;    
+; $Log: dnssd.def,v $
+; Revision 1.2  2004/03/19 10:07:14  bradley
+; Export all DNS-SD API symbols from the DLL so they can be used by clients.
+;
+; Revision 1.1  2004/02/21 04:16:50  bradley
+; DLL wrapper for DNS-SD API.
+;
+;
+;
+
+LIBRARY                DNSSD
+
+EXPORTS
+       DNSServiceInitialize
+       DNSServiceFinalize
+       DNSServiceCheckVersion
+       DNSServiceCopyProperty
+       DNSServiceReleaseProperty
+       DNSServiceRefSockFD
+       DNSServiceProcessResult
+       DNSServiceRefDeallocate
+       DNSServiceEnumerateDomains
+       DNSServiceRegister
+       DNSServiceAddRecord
+       DNSServiceUpdateRecord
+       DNSServiceRemoveRecord
+       DNSServiceBrowse
+       DNSServiceResolve
+       DNSServiceConstructFullName
+       DNSServiceCreateConnection
+       DNSServiceRegisterRecord
+       DNSServiceQueryRecord
+       DNSServiceReconfirmRecord
diff --git a/mDNSWindows/Applications/DLL/dnssd.vcproj b/mDNSWindows/Applications/DLL/dnssd.vcproj
new file mode 100644 (file)
index 0000000..ad7c1d1
--- /dev/null
@@ -0,0 +1,156 @@
+<?xml version="1.0" encoding = "Windows-1252"?>
+<VisualStudioProject
+       ProjectType="Visual C++"
+       Version="7.00"
+       Name="DNSSD"
+       ProjectGUID="{D18D23EC-5284-4E28-A924-626EAAE1D883}"
+       Keyword="Win32Proj">
+       <Platforms>
+               <Platform
+                       Name="Win32"/>
+       </Platforms>
+       <Configurations>
+               <Configuration
+                       Name="Debug|Win32"
+                       OutputDirectory="Debug"
+                       IntermediateDirectory="Debug"
+                       ConfigurationType="2"
+                       CharacterSet="2">
+                       <Tool
+                               Name="VCCLCompilerTool"
+                               Optimization="0"
+                               AdditionalIncludeDirectories="..\..\..\mDNSCore;..\..\"
+                               PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;DNSSD_EXPORTS;DEBUG=1;DNS_SD_DIRECT_ENABLED=0"
+                               MinimalRebuild="TRUE"
+                               ExceptionHandling="FALSE"
+                               BasicRuntimeChecks="3"
+                               RuntimeLibrary="1"
+                               BufferSecurityCheck="TRUE"
+                               UsePrecompiledHeader="0"
+                               BrowseInformation="1"
+                               WarningLevel="4"
+                               WarnAsError="FALSE"
+                               Detect64BitPortabilityProblems="TRUE"
+                               DebugInformationFormat="4"
+                               CompileAs="0"/>
+                       <Tool
+                               Name="VCCustomBuildTool"/>
+                       <Tool
+                               Name="VCLinkerTool"
+                               AdditionalDependencies="ws2_32.lib"
+                               OutputFile="$(OutDir)/DNSSD.dll"
+                               LinkIncremental="2"
+                               ModuleDefinitionFile="./$(ProjectName).def"
+                               GenerateDebugInformation="TRUE"
+                               ProgramDatabaseFile="$(OutDir)/DNSSD.pdb"
+                               SubSystem="2"
+                               ImportLibrary="$(OutDir)/DNSSD.lib"
+                               TargetMachine="1"/>
+                       <Tool
+                               Name="VCMIDLTool"/>
+                       <Tool
+                               Name="VCPostBuildEventTool"/>
+                       <Tool
+                               Name="VCPreBuildEventTool"/>
+                       <Tool
+                               Name="VCPreLinkEventTool"/>
+                       <Tool
+                               Name="VCResourceCompilerTool"/>
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"/>
+                       <Tool
+                               Name="VCWebDeploymentTool"/>
+               </Configuration>
+               <Configuration
+                       Name="Release|Win32"
+                       OutputDirectory="Release"
+                       IntermediateDirectory="Release"
+                       ConfigurationType="2"
+                       CharacterSet="1">
+                       <Tool
+                               Name="VCCLCompilerTool"
+                               Optimization="2"
+                               InlineFunctionExpansion="2"
+                               FavorSizeOrSpeed="2"
+                               OmitFramePointers="TRUE"
+                               AdditionalIncludeDirectories="..\..\..\mDNSCore;..\..\"
+                               PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;DNSSD_EXPORTS;DNS_SD_DIRECT_ENABLED=0"
+                               StringPooling="TRUE"
+                               ExceptionHandling="FALSE"
+                               RuntimeLibrary="0"
+                               BufferSecurityCheck="FALSE"
+                               EnableFunctionLevelLinking="TRUE"
+                               UsePrecompiledHeader="0"
+                               WarningLevel="4"
+                               WarnAsError="FALSE"
+                               Detect64BitPortabilityProblems="TRUE"
+                               DebugInformationFormat="3"
+                               CompileAs="0"/>
+                       <Tool
+                               Name="VCCustomBuildTool"/>
+                       <Tool
+                               Name="VCLinkerTool"
+                               AdditionalDependencies="ws2_32.lib"
+                               OutputFile="$(OutDir)/DNSSD.dll"
+                               LinkIncremental="1"
+                               ModuleDefinitionFile="./$(ProjectName).def"
+                               GenerateDebugInformation="TRUE"
+                               SubSystem="2"
+                               OptimizeReferences="2"
+                               EnableCOMDATFolding="2"
+                               ImportLibrary="$(OutDir)/DNSSD.lib"
+                               TargetMachine="1"/>
+                       <Tool
+                               Name="VCMIDLTool"/>
+                       <Tool
+                               Name="VCPostBuildEventTool"/>
+                       <Tool
+                               Name="VCPreBuildEventTool"/>
+                       <Tool
+                               Name="VCPreLinkEventTool"/>
+                       <Tool
+                               Name="VCResourceCompilerTool"/>
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"/>
+                       <Tool
+                               Name="VCWebDeploymentTool"/>
+               </Configuration>
+       </Configurations>
+       <Files>
+               <File
+                       RelativePath="..\..\CommonServices.h">
+               </File>
+               <File
+                       RelativePath="DLLMain.c">
+               </File>
+               <File
+                       RelativePath="..\..\DNSSD.c">
+               </File>
+               <File
+                       RelativePath="DNSSD.def">
+               </File>
+               <File
+                       RelativePath="..\..\DNSSD.h">
+               </File>
+               <File
+                       RelativePath="..\..\DebugServices.c">
+               </File>
+               <File
+                       RelativePath="..\..\DebugServices.h">
+               </File>
+               <File
+                       RelativePath="..\..\RMxClient.c">
+               </File>
+               <File
+                       RelativePath="..\..\RMxClient.h">
+               </File>
+               <File
+                       RelativePath="..\..\RMxCommon.c">
+               </File>
+               <File
+                       RelativePath="..\..\RMxCommon.h">
+               </File>
+       </Files>
+       <Globals>
+       </Globals>
+</VisualStudioProject>
index fe6ce777125274056908b3b882718aa3507992cc..5ce1a0a2f9ddef0af6a43960ddca4297668698ab 100644 (file)
@@ -3,15 +3,12 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Application", "ApplicationV
 EndProject
 Global
        GlobalSection(SolutionConfiguration) = preSolution
-               ConfigName.0 = All
-               ConfigName.1 = Debug
-               ConfigName.2 = Release
+               ConfigName.0 = Debug
+               ConfigName.1 = Release
        EndGlobalSection
        GlobalSection(ProjectDependencies) = postSolution
        EndGlobalSection
        GlobalSection(ProjectConfiguration) = postSolution
-               {EDE4B529-4CF5-4A49-9B6F-C10F0EA24278}.All.ActiveCfg = All|Win32
-               {EDE4B529-4CF5-4A49-9B6F-C10F0EA24278}.All.Build.0 = All|Win32
                {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
index 89316d2c162f3ca2b2bf790ac60ea8cd1f2d4a30..5d72e3010aa70ee91ee5091583cec99805bbc113 100644 (file)
                        IntermediateDirectory="Debug"
                        ConfigurationType="1"
                        UseOfMFC="1"
-                       CharacterSet="2">
+                       CharacterSet="1">
                        <Tool
                                Name="VCCLCompilerTool"
                                Optimization="0"
-                               AdditionalIncludeDirectories=".\Resources;..\;..\..\..\..\mDNSCore;..\..\..\mDNSWindows;..\..\..\DNSServices"
-                               PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;DEBUG"
+                               AdditionalIncludeDirectories=".\Resources;..\;..\..\..\;..\..\..\..\mDNSCore;..\..\..\DNSServices"
+                               PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;DEBUG=1"
                                StringPooling="TRUE"
                                MinimalRebuild="FALSE"
                                BasicRuntimeChecks="3"
                                SuppressStartupBanner="TRUE"
                                Detect64BitPortabilityProblems="TRUE"
                                DebugInformationFormat="3"
-                               CompileAs="0"/>
+                               CompileAs="2"/>
                        <Tool
                                Name="VCCustomBuildTool"/>
                        <Tool
                                Name="VCLinkerTool"
-                               AdditionalOptions="/MACHINE:I386"
-                               AdditionalDependencies="ws2_32.lib nafxcwd.lib LIBCMTD.lib"
+                               AdditionalOptions="/MACHINE:I386 /IGNORE:4089"
+                               AdditionalDependencies="ws2_32.lib"
                                OutputFile="Rendezvous Browser Debug.exe"
                                LinkIncremental="1"
                                SuppressStartupBanner="TRUE"
-                               IgnoreDefaultLibraryNames="wsock32.lib;nafxcwd.lib;LIBCMTD.lib"
+                               IgnoreDefaultLibraryNames="wsock32.lib"
                                GenerateDebugInformation="TRUE"
                                ProgramDatabaseFile=".\Debug/Application.pdb"
                                SubSystem="2"/>
                        IntermediateDirectory=".\Release"
                        ConfigurationType="1"
                        UseOfMFC="1"
-                       CharacterSet="2"
+                       CharacterSet="1"
                        WholeProgramOptimization="FALSE">
                        <Tool
                                Name="VCCLCompilerTool"
-                               Optimization="1"
+                               Optimization="2"
                                GlobalOptimizations="TRUE"
                                InlineFunctionExpansion="0"
                                FavorSizeOrSpeed="2"
-                               OmitFramePointers="FALSE"
+                               OmitFramePointers="TRUE"
                                OptimizeForWindowsApplication="FALSE"
-                               AdditionalIncludeDirectories=".\Resources;..\;..\..\..\..\mDNSCore;..\..\..\mDNSWindows;..\..\..\DNSServices"
+                               AdditionalIncludeDirectories=".\Resources;..\;..\..\..\;..\..\..\..\mDNSCore;..\..\..\DNSServices"
                                PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS"
                                StringPooling="TRUE"
                                MinimalRebuild="FALSE"
                                WarnAsError="TRUE"
                                SuppressStartupBanner="TRUE"
                                Detect64BitPortabilityProblems="TRUE"
-                               CompileAs="0"/>
+                               CompileAs="2"/>
                        <Tool
                                Name="VCCustomBuildTool"/>
                        <Tool
                                Name="VCLinkerTool"
-                               AdditionalOptions="/MACHINE:I386"
-                               AdditionalDependencies="ws2_32.lib nafxcw.lib LIBCMT.lib"
+                               AdditionalOptions="/MACHINE:I386 /IGNORE:4089"
+                               AdditionalDependencies="ws2_32.lib"
                                OutputFile="Rendezvous Browser.exe"
                                LinkIncremental="1"
                                SuppressStartupBanner="TRUE"
-                               IgnoreDefaultLibraryNames="wsock32.lib;nafxcw.lib;LIBCMT.lib"
+                               IgnoreDefaultLibraryNames="wsock32.lib"
                                ProgramDatabaseFile=".\Release/Application.pdb"
                                SubSystem="2"
                                OptimizeReferences="2"
                        <Tool
                                Name="VCWebDeploymentTool"/>
                </Configuration>
-               <Configuration
-                       Name="All|Win32"
-                       OutputDirectory="All"
-                       IntermediateDirectory="All"
-                       ConfigurationType="1">
-                       <Tool
-                               Name="VCCLCompilerTool"
-                               AdditionalIncludeDirectories=""/>
-                       <Tool
-                               Name="VCCustomBuildTool"/>
-                       <Tool
-                               Name="VCLinkerTool"/>
-                       <Tool
-                               Name="VCMIDLTool"/>
-                       <Tool
-                               Name="VCPostBuildEventTool"/>
-                       <Tool
-                               Name="VCPreBuildEventTool"/>
-                       <Tool
-                               Name="VCPreLinkEventTool"/>
-                       <Tool
-                               Name="VCResourceCompilerTool"/>
-                       <Tool
-                               Name="VCWebServiceProxyGeneratorTool"/>
-                       <Tool
-                               Name="VCWebDeploymentTool"/>
-               </Configuration>
        </Configurations>
        <Files>
                <Filter
                        <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>
                </Filter>
                <Filter
-                       Name="Rendezvous"
+                       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>
index 0bdb334e4afcff5025bca941d9209891eb2920a6..bdaaa3be9f1db88c737500ae9023cfeceb61a95d 100644 (file)
@@ -5,13 +5,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Application", "ApplicationV
 EndProject
 Global
        GlobalSection(SolutionConfiguration) = preSolution
-               All = All
                Debug = Debug
                Release = Release
        EndGlobalSection
        GlobalSection(ProjectConfiguration) = postSolution
-               {EDE4B529-4CF5-4A49-9B6F-C10F0EA24278}.All.ActiveCfg = All|Win32
-               {EDE4B529-4CF5-4A49-9B6F-C10F0EA24278}.All.Build.0 = All|Win32
                {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
index 4f9b2bdbf94dcdd08db02c8b87ad0d35885ba20b..f3b4e9a15cac86a4fe85e3df2609202b6a76fdef 100644 (file)
                        IntermediateDirectory="Debug"
                        ConfigurationType="1"
                        UseOfMFC="1"
-                       CharacterSet="2">
+                       CharacterSet="1">
                        <Tool
                                Name="VCCLCompilerTool"
                                Optimization="0"
-                               AdditionalIncludeDirectories=".\Resources;..\;..\..\..\..\mDNSCore;..\..\..\mDNSWindows;..\..\..\DNSServices"
-                               PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;DEBUG"
+                               AdditionalIncludeDirectories=".\Resources;..\;..\..\..\;..\..\..\..\mDNSCore;..\..\..\DNSServices"
+                               PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;DEBUG=1"
                                StringPooling="TRUE"
                                MinimalRebuild="FALSE"
                                BasicRuntimeChecks="3"
                                Name="VCCustomBuildTool"/>
                        <Tool
                                Name="VCLinkerTool"
-                               AdditionalOptions="/MACHINE:I386"
-                               AdditionalDependencies="ws2_32.lib nafxcwd.lib LIBCMTD.lib"
+                               AdditionalOptions="/MACHINE:I386 /IGNORE:4089"
+                               AdditionalDependencies="ws2_32.lib"
                                OutputFile="Rendezvous Browser Debug.exe"
                                LinkIncremental="1"
                                SuppressStartupBanner="TRUE"
-                               IgnoreDefaultLibraryNames="wsock32.lib;nafxcwd.lib;LIBCMTD.lib"
+                               IgnoreDefaultLibraryNames="wsock32.lib"
                                GenerateDebugInformation="TRUE"
                                ProgramDatabaseFile=".\Debug/Application.pdb"
                                SubSystem="2"/>
                        IntermediateDirectory=".\Release"
                        ConfigurationType="1"
                        UseOfMFC="1"
-                       CharacterSet="2"
+                       CharacterSet="1"
                        WholeProgramOptimization="FALSE">
                        <Tool
                                Name="VCCLCompilerTool"
-                               Optimization="1"
+                               Optimization="2"
                                GlobalOptimizations="TRUE"
                                InlineFunctionExpansion="0"
                                FavorSizeOrSpeed="2"
-                               OmitFramePointers="FALSE"
+                               OmitFramePointers="TRUE"
                                OptimizeForWindowsApplication="FALSE"
-                               AdditionalIncludeDirectories=".\Resources;..\;..\..\..\..\mDNSCore;..\..\..\mDNSWindows;..\..\..\DNSServices"
+                               AdditionalIncludeDirectories=".\Resources;..\;..\..\..\;..\..\..\..\mDNSCore;..\..\..\DNSServices"
                                PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS"
                                StringPooling="TRUE"
                                MinimalRebuild="FALSE"
                                Name="VCCustomBuildTool"/>
                        <Tool
                                Name="VCLinkerTool"
-                               AdditionalOptions="/MACHINE:I386"
-                               AdditionalDependencies="ws2_32.lib nafxcw.lib LIBCMT.lib"
+                               AdditionalOptions="/MACHINE:I386 /IGNORE:4089"
+                               AdditionalDependencies="ws2_32.lib"
                                OutputFile="Rendezvous Browser.exe"
                                LinkIncremental="1"
                                SuppressStartupBanner="TRUE"
-                               IgnoreDefaultLibraryNames="wsock32.lib;nafxcw.lib;LIBCMT.lib"
+                               IgnoreDefaultLibraryNames="wsock32.lib"
                                ProgramDatabaseFile=".\Release/Application.pdb"
                                SubSystem="2"
                                OptimizeReferences="2"
                        <Tool
                                Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
                </Configuration>
-               <Configuration
-                       Name="All|Win32"
-                       OutputDirectory="All"
-                       IntermediateDirectory="All"
-                       ConfigurationType="1">
-                       <Tool
-                               Name="VCCLCompilerTool"
-                               AdditionalIncludeDirectories=""/>
-                       <Tool
-                               Name="VCCustomBuildTool"/>
-                       <Tool
-                               Name="VCLinkerTool"/>
-                       <Tool
-                               Name="VCMIDLTool"/>
-                       <Tool
-                               Name="VCPostBuildEventTool"/>
-                       <Tool
-                               Name="VCPreBuildEventTool"/>
-                       <Tool
-                               Name="VCPreLinkEventTool"/>
-                       <Tool
-                               Name="VCResourceCompilerTool"/>
-                       <Tool
-                               Name="VCWebServiceProxyGeneratorTool"/>
-                       <Tool
-                               Name="VCXMLDataGeneratorTool"/>
-                       <Tool
-                               Name="VCWebDeploymentTool"/>
-                       <Tool
-                               Name="VCManagedWrapperGeneratorTool"/>
-                       <Tool
-                               Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
-               </Configuration>
        </Configurations>
        <References>
        </References>
                        <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>
                </Filter>
                <Filter
-                       Name="Rendezvous"
+                       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>
index a992327973c4f716e13ba43b7803f59885b99069..b0a86399055437af8f9244e39c5938ab534824d7 100644 (file)
Binary files a/mDNSWindows/Applications/DNSServiceBrowser/Windows/Resources/Application.ico and b/mDNSWindows/Applications/DNSServiceBrowser/Windows/Resources/Application.ico differ
index 1d9c2eb660f0d5efddce5a4f6bdf2f8e77405a08..cf2f2927b58af83cb1d124568a7ad3e4ebabfe0c 100644 (file)
@@ -73,51 +73,72 @@ IDR_MAIN_ICON           ICON                    "Application.ico"
 // Dialog
 //
 
-IDD_CHOOSER_DIALOG DIALOGEX 0, 0, 332, 252
-STYLE DS_SETFONT | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | 
-    WS_SYSMENU
+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 "Rendezvous Browser for Windows"
+CAPTION "Rendezvous Browser"
 MENU IDR_CHOOSER_DIALOG_MENU
-FONT 8, "MS Sans Serif", 0, 0, 0x0
+FONT 8, "MS Shell Dlg", 0, 0, 0x0
 BEGIN
-    CONTROL         "",IDC_CHOOSER_LIST,"SysListView32",LVS_REPORT | 
-                    LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | 
-                    LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,116,8,208,136
     CONTROL         "",IDC_SERVICE_LIST,"SysListView32",LVS_REPORT | 
                     LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | 
-                    LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,8,8,100,136
+                    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,152,100,92
-    GROUPBOX        "Information",IDC_STATIC,116,148,208,96
-    RTEXT           "Name:",IDC_STATIC,122,164,38,8
-    LTEXT           "My Device",IDC_INFO_NAME_TEXT,164,164,152,10,SS_SUNKEN
-    RTEXT           "Text:",IDC_STATIC,122,203,38,8
-    LTEXT           "Information About My Device",IDC_INFO_TEXT_TEXT,164,203,
-                    152,34,SS_NOPREFIX | SS_SUNKEN
-    RTEXT           "IP address:",IDC_STATIC,122,177,38,8
-    LTEXT           "123.124.125.126:1234",IDC_INFO_IP_TEXT,164,177,152,10,
-                    SS_SUNKEN
-    RTEXT           "Interface:",IDC_STATIC,122,190,38,8
-    LTEXT           "123.124.125.126",IDC_INFO_INTERFACE_TEXT,164,190,152,10,
-                    SS_SUNKEN
+                    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 | WS_POPUP | WS_CAPTION
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION
 CAPTION "About Rendezvous Browser"
-FONT 8, "MS Sans Serif", 0, 0, 0x0
+FONT 8, "MS Shell Dlg", 0, 0, 0x0
 BEGIN
     ICON            IDR_MAIN_ICON,IDC_ABOUT_APP_ICON,12,12,20,20
-    LTEXT           "Rendezvous Browser for Windows",IDC_ABOUT_APP_NAME_TEXT,
-                    44,11,192,12
-    LTEXT           "Version 1.0d2",IDC_ABOUT_APP_VERSION_TEXT,44,25,192,8
-    LTEXT           "Copyright (C) 2002-2003 Apple Computer, Inc.",
+    LTEXT           "Rendezvous Browser",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
+
 
 /////////////////////////////////////////////////////////////////////////////
 //
@@ -141,12 +162,11 @@ BEGIN
     BEGIN
         BLOCK "040904b0"
         BEGIN
-            VALUE "Comments", "Quick & Dirty 1 day hack by Bob Bradley"
             VALUE "CompanyName", "Apple Computer, Inc."
             VALUE "FileDescription", "Rendezvous Browser for Windows"
             VALUE "FileVersion", "1, 0, 0, 1"
             VALUE "InternalName", "Rendezvous Browser for Windows"
-            VALUE "LegalCopyright", "Copyright (C) Apple Computer, Inc. 2001"
+            VALUE "LegalCopyright", "Copyright (C) 2002-2004 Apple Computer, Inc."
             VALUE "OriginalFilename", "RendezvousBrowser.exe"
             VALUE "ProductName", "Rendezvous Browser for Windows"
             VALUE "ProductVersion", "1, 0, 0, 1"
@@ -237,6 +257,27 @@ BEGIN
 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
@@ -247,9 +288,10 @@ BEGIN
     IDS_ABOUTBOX            "&About Rendezvous Browser"
     IDS_CHOOSER_DOMAIN_COLUMN_NAME "Domains"
     IDP_SOCKETS_INIT_FAILED "Windows sockets initialization failed."
-    IDS_CHOOSER_SERVICE_COLUMN_NAME "Services"
+    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
index bf1983feb8fb9957c03aaa4c87b20a8124ec31c1..9c767662c505ffa584178a8773ba671a1bd6d039 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -23,6 +23,9 @@
     Change History (most recent first):
 
 $Log: Application.rc2,v $
+Revision 1.2  2004/01/30 02:56:33  bradley
+Updated to support full Unicode display. Added support for all services on www.dns-sd.org.
+
 Revision 1.1  2003/08/21 02:06:46  bradley
 Moved Rendezvous Browser for non-Windows CE into Windows sub-folder.
 
index 5329fc14d2a83b9675f733103f927ac62d1eac2d..62602a4fc90af61d6d10bf53a98bb6682167fbe8 100644 (file)
@@ -6,8 +6,10 @@
 #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_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
@@ -30,6 +35,9 @@
 #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
 
@@ -39,7 +47,7 @@
 #ifndef APSTUDIO_READONLY_SYMBOLS
 #define _APS_NEXT_RESOURCE_VALUE        164
 #define _APS_NEXT_COMMAND_VALUE         32809
-#define _APS_NEXT_CONTROL_VALUE         1182
+#define _APS_NEXT_CONTROL_VALUE         1185
 #define _APS_NEXT_SYMED_VALUE           101
 #endif
 #endif
index cd8cafb1a963519ca6e448ea1e344ad878e5efb6..50142c2cc43ed578ef1ba6544d2682fed233b375 100644 (file)
@@ -1,8 +1,10 @@
 /*
- * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
@@ -23,6 +25,9 @@
     Change History (most recent first):
     
 $Log: AboutDialog.cpp,v $
+Revision 1.2  2004/01/30 02:56:32  bradley
+Updated to support full Unicode display. Added support for all services on www.dns-sd.org.
+
 Revision 1.1  2003/08/21 02:06:47  bradley
 Moved Rendezvous Browser for non-Windows CE into Windows sub-folder.
 
index 11c9149ddacd28ea0a43e59ff5b7c5e15e71d565..ee977319f7f9dee91a57e94e1084fb72cc592167 100644 (file)
@@ -1,8 +1,10 @@
 /*
- * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
@@ -23,6 +25,9 @@
     Change History (most recent first):
     
 $Log: AboutDialog.h,v $
+Revision 1.2  2004/01/30 02:56:32  bradley
+Updated to support full Unicode display. Added support for all services on www.dns-sd.org.
+
 Revision 1.1  2003/08/21 02:06:47  bradley
 Moved Rendezvous Browser for non-Windows CE into Windows sub-folder.
 
index 396b7e9fd5c06a555278806fbd6f7abfcf85ade0..1fb0723f0d2bab40101f9b1910c593db1f6e0d59 100644 (file)
@@ -1,8 +1,10 @@
 /*
- * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
@@ -23,6 +25,9 @@
     Change History (most recent first):
     
 $Log: Application.cpp,v $
+Revision 1.2  2004/01/30 02:56:32  bradley
+Updated to support full Unicode display. Added support for all services on www.dns-sd.org.
+
 Revision 1.1  2003/08/21 02:06:47  bradley
 Moved Rendezvous Browser for non-Windows CE into Windows sub-folder.
 
@@ -45,6 +50,8 @@ Rendezvous Browser for Windows
 
 #include       <assert.h>
 
+#include       "StdAfx.h"
+
 #include       "DNSServices.h"
 
 #include       "Application.h"
@@ -94,14 +101,6 @@ BOOL        Application::InitInstance()
 {
        DNSStatus               err;
        
-       // WinSock initialization.
-       
-       if( !AfxSocketInit() )
-       {
-               AfxMessageBox( IDP_SOCKETS_INIT_FAILED );
-               return( FALSE );
-       }
-
        // Standard MFC initialization.
 
 #if( !defined( AFX_DEPRECATED ) )
index e174e4f06a7c278fdafa4d207f95f79ae1b183bd..30705d37b2e93bcac91d3796502ac1653fdd9181 100644 (file)
@@ -1,8 +1,10 @@
 /*
- * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
@@ -23,6 +25,9 @@
     Change History (most recent first):
     
 $Log: Application.h,v $
+Revision 1.2  2004/01/30 02:56:32  bradley
+Updated to support full Unicode display. Added support for all services on www.dns-sd.org.
+
 Revision 1.1  2003/08/21 02:06:47  bradley
 Moved Rendezvous Browser for non-Windows CE into Windows sub-folder.
 
index ddd81f901a83d3fd0f196aa6b924fe399b1ae91e..162acdac40fd09cbe6bcc861a458c19e6d51346d 100644 (file)
@@ -1,8 +1,10 @@
 /*
- * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
     Change History (most recent first):
     
 $Log: ChooserDialog.cpp,v $
+Revision 1.10  2004/04/23 01:19:41  bradley
+Changed TXT record new line delimiter from \n to \r\n so it works now that it is an edit text.
+
+Revision 1.9  2004/03/07 05:51:04  bradley
+Updated service type list table to include all service types from dns-sd.org as of 2004-03-06.
+Added separate Service Type and Service Description columns so both are show in the window.
+
+Revision 1.8  2004/01/30 02:56:32  bradley
+Updated to support full Unicode display. Added support for all services on www.dns-sd.org.
+
+Revision 1.7  2003/12/25 03:42:04  bradley
+Added login dialog to get username/password when going to FTP sites. Added more services.
+
+Revision 1.6  2003/10/31 12:18:30  bradley
+Added display of the resolved host name. Show separate TXT record entries on separate lines.
+
+Revision 1.5  2003/10/16 09:21:56  bradley
+Ignore non-IPv4 resolves until mDNS on Windows supports IPv6.
+
+Revision 1.4  2003/10/10 03:41:29  bradley
+Changed HTTP double-click handling to work with or without the path= prefix in the TXT record.
+
+Revision 1.3  2003/10/09 19:50:40  bradley
+Sort service type list by description.
+
+Revision 1.2  2003/10/09 19:41:29  bradley
+Changed quit handling to go through normal close path so dialog is freed on quit. Integrated changes
+from Andrew van der Stock for the addition of an _rfb._tcp service type for a VNC Remote Framebuffer
+Server for KDE support. Widened service type list to handle larger service type descriptions.
+
 Revision 1.1  2003/08/21 02:06:47  bradley
 Moved Rendezvous Browser for non-Windows CE into Windows sub-folder.
 
@@ -65,6 +97,7 @@ Rendezvous Browser for Windows
 
 #include       "Application.h"
 #include       "AboutDialog.h"
+#include       "LoginDialog.h"
 #include       "Resource.h"
 
 #include       "ChooserDialog.h"
@@ -93,29 +126,25 @@ enum
 
 // Domain List
        
-#define kDomainListDefaultDomainColumnIndex                    0
-#define kDomainListDefaultDomainColumnWidth                    140 
+#define kDomainListDefaultDomainColumnWidth                            164 
        
 // Service List
-       
-#define kServiceListDefaultServiceColumnIndex          0
-#define kServiceListDefaultServiceColumnWidth          140
+
+#define kServiceListDefaultServiceColumnTypeWidth              146
+#define kServiceListDefaultServiceColumnDescWidth              230
        
 // Chooser List
        
-#define kChooserListDefaultNameColumnIndex                     0
-#define kChooserListDefaultNameColumnWidth                     162
-       
-#define kChooserListDefaultIPColumnIndex                       1
-#define kChooserListDefaultIPColumnWidth                       126
+#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 )
+#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 ==
@@ -135,18 +164,138 @@ struct   KnownServiceEntry
 
 static const KnownServiceEntry         kKnownServiceTable[] =
 {
-       { "_airport._tcp.",     "AirPort Base Station",                         "acp://",       false }, 
-       { "_afpovertcp._tcp.",  "AppleShare Server",                            "afp://",       false },
-       { "_ftp._tcp.",                 "File Transfer (FTP)",                          "ftp://",       false }, 
-       { "_ichat._tcp.",               "iChat",                                                        "ichat://", false }, 
-       { "_printer._tcp.",     "Printer (LPD)",                                        "ldp://",       false }, 
-       { "_eppc._tcp.",                "Remote AppleEvents",                           "eppc://",      false }, 
-       { "_ssh._tcp.",                 "Secure Shell (SSH)",                           "ssh://",       false }, 
-       { "_tftp._tcp.",                "Trivial File Transfer (TFTP)",         "tftp://",      false }, 
-       { "_http._tcp.",                "Web Server (HTTP)",                            "http://",      true  }, 
-       { "_smb._tcp.",                 "Windows File Sharing",                         "smb://",       false }, 
-       { "_xserveraid._tcp.",  "Xserve RAID",                                          "xsr://",       false }, 
-       { NULL,                                 NULL,                                                           NULL,           false }, 
+       { "_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 },
+       { "_rendezvouspong._tcp",               "RendezvousPong",                                                                                       "",                     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
@@ -191,6 +340,7 @@ static void
 static char *  DNSNetworkAddressToString( const DNSNetworkAddress *inAddr, char *outString );
 
 static DWORD   UTF8StringToStringObject( const char *inUTF8, CString &inObject );
+static DWORD   StringObjectToUTF8String( CString &inObject, std::string &outUTF8 );
 
 #if 0
 #pragma mark == Message Map ==
@@ -282,6 +432,7 @@ void ChooserDialog::DoDataExchange( CDataExchange *pDX )
 
 BOOL   ChooserDialog::OnInitDialog( void )
 {
+       HICON                   icon;
        BOOL                    result;
        CString                 tempString;
        DNSStatus               err;
@@ -289,7 +440,17 @@ BOOL       ChooserDialog::OnInitDialog( void )
        // 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 );
@@ -298,9 +459,13 @@ BOOL       ChooserDialog::OnInitDialog( void )
        
        // Set up the Service List.
        
-       result = tempString.LoadString( IDS_CHOOSER_SERVICE_COLUMN_NAME );
+       result = tempString.LoadString( IDS_CHOOSER_SERVICE_COLUMN_TYPE );
        assert( result );
-       mServiceList.InsertColumn( 0, tempString, LVCFMT_LEFT, kServiceListDefaultServiceColumnWidth );
+       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();
        
@@ -411,7 +576,7 @@ void        ChooserDialog::OnInitMenuPopup( CMenu *pPopupMenu, UINT nIndex, BOOL bSysMe
 
 void ChooserDialog::OnExit() 
 {
-       AfxPostQuitMessage( 0 );
+       OnClose();
 }
 
 //===========================================================================================================================
@@ -494,13 +659,17 @@ void      ChooserDialog::OnServiceListChanged( NMHDR *pNMHDR, LRESULT *pResult )
        
        if( ( selectedType >= 0 ) && ( selectedDomain >= 0 ) )
        {
-               CString         type;
-               CString         domain;
-               
-               type    = mServiceTypes[ selectedType ].serviceType.c_str();
-               domain  = mDomainList.GetItemText( selectedDomain, 0 );
+               CString                         s;
+               std::string                     utf8;
+               const char *            type;
                
-               StartBrowsing( type, domain );
+               s = mDomainList.GetItemText( selectedDomain, 0 );
+               StringObjectToUTF8String( s, utf8 );
+               type = mServiceTypes[ selectedType ].serviceType.c_str();
+               if( *type != '\0' )
+               {
+                       StartBrowsing( type, utf8.c_str() );
+               }
        }
        
        if( pResult )
@@ -554,25 +723,81 @@ void      ChooserDialog::OnChooserListDoubleClick( NMHDR *pNMHDR, LRESULT *pResult )
                }
                if( service->serviceType )
                {
-                       // Create a URL representing the service instance. Special case for SMB (no port number).
+                       const char *            text;
                        
-                       if( strcmp( service->serviceType, "_smb._tcp" ) == 0 )
+                       // Create a URL representing the service instance.
+                       
+                       if( strcmp( service->serviceType, "_smb._tcp." ) == 0 )
                        {
-                               url.Format( "%s%s/", service->urlScheme, (const char *) p->ip.c_str() ); 
+                               // Special case for SMB (no port number).
+                               
+                               url.Format( TEXT( "%s%s/" ), service->urlScheme, (const char *) p->ip.c_str() ); 
                        }
-                       else
+                       else if( strcmp( service->serviceType, "_ftp._tcp." ) == 0 )
                        {
-                               const char *            text;
+                               // 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() : "";
-                               url.Format( "%s%s/%s", service->urlScheme, (const char *) p->ip.c_str(), text ); 
+                               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.
                        
-                       ShellExecute( NULL, "open", url, "", "c:\\", SW_SHOWNORMAL );
+                       {
+                               CWaitCursor             waitCursor;
+                               
+                               ShellExecute( NULL, TEXT( "open" ), url, TEXT( "" ), TEXT( "c:\\" ), SW_SHOWNORMAL );
+                       }
                }
        }
+
+exit:
        *pResult = 0;
 }
 
@@ -592,7 +817,9 @@ void ChooserDialog::OnCancel()
 void   ChooserDialog::PopulateServicesList( void )
 {
        ServiceTypeVector::iterator             i;
-       CString                                                 name;
+       CString                                                 type;
+       CString                                                 desc;
+       std::string                                             tmp;
        
        // Add a fixed list of known services.
        
@@ -615,8 +842,22 @@ void       ChooserDialog::PopulateServicesList( void )
        
        for( i = mServiceTypes.begin(); i != mServiceTypes.end(); ++i )
        {
-               UTF8StringToStringObject( ( *i ).description.c_str(), name );
-               mServiceList.InsertItem( mServiceList.GetItemCount(), name );
+               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.
@@ -633,13 +874,16 @@ void      ChooserDialog::PopulateServicesList( void )
 
 void   ChooserDialog::UpdateInfoDisplay( void )
 {
-       int                             selectedItem;
-       std::string             name;
-       CString                 s;
-       std::string             ip;
-       std::string             ifIP;
-       std::string             text;
-       CWnd *                  item;
+       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.
        
@@ -651,14 +895,16 @@ void      ChooserDialog::UpdateInfoDisplay( void )
                assert( selectedItem < (int) mServiceInstances.size() );
                p = &mServiceInstances[ selectedItem ];
                
-               name    = p->name;
-               ip              = p->ip;
-               ifIP    = p->ifIP;
-               text    = p->text;
-               
+               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).
                
-               mChooserList.SetItemText( selectedItem, 1, ip.c_str() );
+               UTF8StringToStringObject( ip.c_str(), s );
+               mChooserList.SetItemText( selectedItem, 1, s );
        }
        
        // Name
@@ -672,23 +918,39 @@ void      ChooserDialog::UpdateInfoDisplay( void )
        
        item = (CWnd *) this->GetDlgItem( IDC_INFO_IP_TEXT );
        assert( item );
-       item->SetWindowText( ip.c_str() );
+       UTF8StringToStringObject( ip.c_str(), s );
+       item->SetWindowText( s );
        
        // Interface
        
        item = (CWnd *) this->GetDlgItem( IDC_INFO_INTERFACE_TEXT );
        assert( item );
-       item->SetWindowText( ifIP.c_str() );
+       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
        
-       if( text.size() > 255 )
-       {
-               text.resize( 255 );
-       }
        item = (CWnd *) this->GetDlgItem( IDC_INFO_TEXT_TEXT );
        assert( item );
-       item->SetWindowText( text.c_str() );
+       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
@@ -914,7 +1176,9 @@ LONG       ChooserDialog::OnResolve( WPARAM inWParam, LPARAM inLParam )
                mServiceInstances.push_back( *p );
                UTF8StringToStringObject( p->name.c_str(), s );
                mChooserList.InsertItem( n, s );
-               mChooserList.SetItemText( n, 1, p->ip.c_str() );
+               
+               UTF8StringToStringObject( p->ip.c_str(), s );
+               mChooserList.SetItemText( n, 1, s );
                
                // If this is the only item, select it.
                
@@ -1065,29 +1329,31 @@ static void
                        // Resolves
                        
                        case kDNSBrowserEventTypeResolved:
-                       {
-                               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, s );
-                               serviceInstance->ifIP   = DNSNetworkAddressToString( &inEvent->data.resolved->interfaceIP, s );
-                               serviceInstance->text   = inEvent->data.resolved->textRecord;
-                               
-                               posted = ::PostMessage( dialog->GetSafeHwnd(), WM_USER_RESOLVE, 0, (LPARAM) serviceInstance );
-                               assert( posted );
-                               if( posted )
+                               if( inEvent->data.resolved->address.addressType == kDNSNetworkAddressTypeIPv4  )
                                {
-                                       serviceInstanceAutoPtr.release();
+                                       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, s );
+                                       serviceInstance->ifIP           = DNSNetworkAddressToString( &inEvent->data.resolved->interfaceIP, 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;
@@ -1169,3 +1435,60 @@ exit:
        }
        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 );
+}
index 7acb0b512a1be39de67aa0228c2b499cdeaaf054..a98e5b6db77510c9688ad65fdd681308231cf46e 100644 (file)
@@ -1,8 +1,10 @@
 /*
- * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
     Change History (most recent first):
     
 $Log: ChooserDialog.h,v $
+Revision 1.3  2004/01/30 02:56:32  bradley
+Updated to support full Unicode display. Added support for all services on www.dns-sd.org.
+
+Revision 1.2  2003/10/31 12:18:30  bradley
+Added display of the resolved host name. Show separate TXT record entries on separate lines.
+
 Revision 1.1  2003/08/21 02:06:47  bradley
 Moved Rendezvous Browser for non-Windows CE into Windows sub-folder.
 
@@ -68,6 +76,7 @@ struct        ServiceInstanceInfo
        std::string             ip;
        std::string             text;
        std::string             ifIP;
+       std::string             hostName;
 };
 
 struct ServiceTypeInfo
diff --git a/mDNSWindows/Applications/DNSServiceBrowser/Windows/Sources/LoginDialog.cpp b/mDNSWindows/Applications/DNSServiceBrowser/Windows/Sources/LoginDialog.cpp
new file mode 100644 (file)
index 0000000..b35e76b
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+    
+$Log: LoginDialog.cpp,v $
+Revision 1.2  2004/01/30 02:56:32  bradley
+Updated to support full Unicode display. Added support for all services on www.dns-sd.org.
+
+Revision 1.1  2003/12/25 03:47:28  bradley
+Login dialog to get the username/password from the user.
+
+*/
+
+#include       <assert.h>
+#include       <stdlib.h>
+
+#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/Applications/DNSServiceBrowser/Windows/Sources/LoginDialog.h b/mDNSWindows/Applications/DNSServiceBrowser/Windows/Sources/LoginDialog.h
new file mode 100644 (file)
index 0000000..2b31e6a
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+    
+$Log: LoginDialog.h,v $
+Revision 1.2  2004/01/30 02:56:32  bradley
+Updated to support full Unicode display. Added support for all services on www.dns-sd.org.
+
+Revision 1.1  2003/12/25 03:47:28  bradley
+Login dialog to get the username/password from the user.
+
+*/
+
+#ifndef        __LOGIN_DIALOG__
+#define        __LOGIN_DIALOG__
+
+#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__
index a26a1e759b68fda74fe0281d5f9fc8df7c43fc0c..f1932eb59d5ffcb978e2cdf2e608e75e84856015 100644 (file)
@@ -1,8 +1,10 @@
 /*
- * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
@@ -23,6 +25,9 @@
     Change History (most recent first):
     
 $Log: StdAfx.cpp,v $
+Revision 1.2  2004/01/30 02:56:32  bradley
+Updated to support full Unicode display. Added support for all services on www.dns-sd.org.
+
 Revision 1.1  2003/08/21 02:06:47  bradley
 Moved Rendezvous Browser for non-Windows CE into Windows sub-folder.
 
index 3c16ff761f4a3b88ca416c6b2adc742c5d14b7c3..35fee48c944afc8167c5a2546bd03d51c60bf814 100644 (file)
@@ -1,8 +1,10 @@
 /*
- * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
     Change History (most recent first):
     
 $Log: StdAfx.h,v $
+Revision 1.3  2004/01/30 02:56:32  bradley
+Updated to support full Unicode display. Added support for all services on www.dns-sd.org.
+
+Revision 1.2  2003/10/09 02:31:55  bradley
+Define WINVER if not already defined to avoid warning with Visual Studio .NET 2003.
+
 Revision 1.1  2003/08/21 02:06:47  bradley
 Moved Rendezvous Browser for non-Windows CE into Windows sub-folder.
 
@@ -49,17 +57,18 @@ Rendezvous Browser for Windows
 
 #define VC_EXTRALEAN           // Exclude rarely-used stuff from Windows headers
 
-#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 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
+       #include        <afxcmn.h>      // MFC support for Windows Common Controls
 #endif // _AFX_NO_AFXCMN_SUPPORT
 
-#include <afxsock.h>           // MFC socket extensions
-
-//{{AFX_INSERT_LOCATION}}
-// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
+#include       <winsock2.h>
 
 #include       <stdlib.h>
 
index 7f624797f1c7a92378e9d9bd9a0e5af00bea3acb..9c735677c0176611d8cac5440ba061bc2e246553 100644 (file)
@@ -52,7 +52,7 @@ RSC=rc.exe
 # 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 /I "Resources" /I "Sources" /I "..\..\..\DNSServices" /I "..\..\..\..\mDNSCore" /I "..\..\..\..\mDNSCore\PlatformSupport" /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" /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
@@ -86,7 +86,7 @@ RSC=rc.exe
 # 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 UNDER_CE=$(CEVersion) /D _WIN32_WCE=$(CEVersion) /D "$(CePlatform)" /D "UNICODE" /D "_UNICODE" /D "_X86_" /D "x86" /D "_WIN32_WCE_CEPC" /D "_AFXDLL" /FR /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
@@ -119,7 +119,7 @@ RSC=rc.exe
 # 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 /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 "NDEBUG" /D "_AFXDLL" /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
@@ -153,7 +153,7 @@ RSC=rc.exe
 # 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 /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" /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
@@ -230,6 +230,7 @@ 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"\
@@ -247,6 +248,7 @@ DEP_CPP_BROWS=\
 !ELSEIF  "$(CFG)" == "Application - Win32 (WCE ARMV4) Release"
 
 DEP_CPP_BROWS=\
+       "..\..\..\DNSServices\DNSServices.h"\
        ".\Sources\Application.h"\
        ".\Sources\BrowserDialog.h"\
        ".\Sources\StdAfx.h"\
@@ -255,6 +257,7 @@ DEP_CPP_BROWS=\
 !ELSEIF  "$(CFG)" == "Application - Win32 (WCE ARMV4) Debug"
 
 DEP_CPP_BROWS=\
+       "..\..\..\DNSServices\DNSServices.h"\
        ".\Sources\Application.h"\
        ".\Sources\BrowserDialog.h"\
        ".\Sources\StdAfx.h"\
@@ -345,47 +348,334 @@ SOURCE=.\Resources\newres.h
 SOURCE=.\Resources\Resource.h
 # End Source File
 # End Group
-# Begin Group "Rendezvous"
+# 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=\
-       "..\..\..\DNSServices\DNSServices.h"\
        "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
        "..\..\..\..\mDNSCore\mDNSDebug.h"\
-       "..\..\..\..\mDNSCore\mDNSPlatformFunctions.h"\
+       "..\..\..\DNSServices\DNSServices.h"\
        
 
 !ELSEIF  "$(CFG)" == "Application - Win32 (WCE emulator) Debug"
 
 DEP_CPP_DNSSE=\
-       "..\..\..\DNSServices\DNSServices.h"\
        "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
        "..\..\..\..\mDNSCore\mDNSDebug.h"\
-       "..\..\..\..\mDNSCore\mDNSPlatformFunctions.h"\
+       "..\..\..\DNSServices\DNSServices.h"\
        
 
 !ELSEIF  "$(CFG)" == "Application - Win32 (WCE ARMV4) Release"
 
 DEP_CPP_DNSSE=\
-       "..\..\..\DNSServices\DNSServices.h"\
        "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
        "..\..\..\..\mDNSCore\mDNSDebug.h"\
-       "..\..\..\..\mDNSCore\mDNSPlatformFunctions.h"\
+       "..\..\..\DNSServices\DNSServices.h"\
        
 
 !ELSEIF  "$(CFG)" == "Application - Win32 (WCE ARMV4) Debug"
 
 DEP_CPP_DNSSE=\
-       "..\..\..\DNSServices\DNSServices.h"\
        "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
        "..\..\..\..\mDNSCore\mDNSDebug.h"\
-       "..\..\..\..\mDNSCore\mDNSPlatformFunctions.h"\
+       "..\..\..\DNSServices\DNSServices.h"\
        
 
 !ENDIF 
@@ -402,33 +692,37 @@ SOURCE=..\..\..\..\mDNSCore\mDNS.c
 !IF  "$(CFG)" == "Application - Win32 (WCE emulator) Release"
 
 DEP_CPP_MDNS_=\
+       "..\..\..\..\mDNSCore\DNSCommon.h"\
        "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
        "..\..\..\..\mDNSCore\mDNSDebug.h"\
-       "..\..\..\..\mDNSCore\mDNSPlatformFunctions.h"\
+       "..\..\..\..\mDNSCore\uDNS.h"\
        
 
 !ELSEIF  "$(CFG)" == "Application - Win32 (WCE emulator) Debug"
 
 DEP_CPP_MDNS_=\
+       "..\..\..\..\mDNSCore\DNSCommon.h"\
        "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
        "..\..\..\..\mDNSCore\mDNSDebug.h"\
-       "..\..\..\..\mDNSCore\mDNSPlatformFunctions.h"\
+       "..\..\..\..\mDNSCore\uDNS.h"\
        
 
 !ELSEIF  "$(CFG)" == "Application - Win32 (WCE ARMV4) Release"
 
 DEP_CPP_MDNS_=\
+       "..\..\..\..\mDNSCore\DNSCommon.h"\
        "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
        "..\..\..\..\mDNSCore\mDNSDebug.h"\
-       "..\..\..\..\mDNSCore\mDNSPlatformFunctions.h"\
+       "..\..\..\..\mDNSCore\uDNS.h"\
        
 
 !ELSEIF  "$(CFG)" == "Application - Win32 (WCE ARMV4) Debug"
 
 DEP_CPP_MDNS_=\
+       "..\..\..\..\mDNSCore\DNSCommon.h"\
        "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
        "..\..\..\..\mDNSCore\mDNSDebug.h"\
-       "..\..\..\..\mDNSCore\mDNSPlatformFunctions.h"\
+       "..\..\..\..\mDNSCore\uDNS.h"\
        
 
 !ENDIF 
@@ -444,10 +738,6 @@ SOURCE=..\..\..\..\mDNSCore\mDNSDebug.h
 # End Source File
 # Begin Source File
 
-SOURCE=..\..\..\..\mDNSCore\mDNSPlatformFunctions.h
-# End Source File
-# Begin Source File
-
 SOURCE=..\..\..\mDNSWin32.c
 
 !IF  "$(CFG)" == "Application - Win32 (WCE emulator) Release"
@@ -455,8 +745,16 @@ SOURCE=..\..\..\mDNSWin32.c
 DEP_CPP_MDNSW=\
        "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
        "..\..\..\..\mDNSCore\mDNSDebug.h"\
-       "..\..\..\..\mDNSCore\mDNSPlatformFunctions.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"
@@ -464,8 +762,16 @@ DEP_CPP_MDNSW=\
 DEP_CPP_MDNSW=\
        "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
        "..\..\..\..\mDNSCore\mDNSDebug.h"\
-       "..\..\..\..\mDNSCore\mDNSPlatformFunctions.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
 
@@ -474,8 +780,16 @@ DEP_CPP_MDNSW=\
 DEP_CPP_MDNSW=\
        "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
        "..\..\..\..\mDNSCore\mDNSDebug.h"\
-       "..\..\..\..\mDNSCore\mDNSPlatformFunctions.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"
@@ -483,8 +797,16 @@ DEP_CPP_MDNSW=\
 DEP_CPP_MDNSW=\
        "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
        "..\..\..\..\mDNSCore\mDNSDebug.h"\
-       "..\..\..\..\mDNSCore\mDNSPlatformFunctions.h"\
+       "..\..\..\CommonServices.h"\
+       "..\..\..\DebugServices.h"\
        "..\..\..\mDNSWin32.h"\
+       {$(INCLUDE)}"ipexport.h"\
+       {$(INCLUDE)}"Iphlpapi.h"\
+       {$(INCLUDE)}"iptypes.h"\
+       
+NODEP_CPP_MDNSW=\
+       "..\..\..\logLib.h"\
+       "..\..\..\vxWorks.h"\
        
 
 !ENDIF 
@@ -494,6 +816,53 @@ DEP_CPP_MDNSW=\
 
 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
index 51a182ea7cb7ad75ea832d1119ab539537ae2ac6..50fb08fcd4c459f28088db2fd9c5134021a1b21b 100644 (file)
Binary files a/mDNSWindows/Applications/DNSServiceBrowser/WindowsCE/Resources/Application.ico and b/mDNSWindows/Applications/DNSServiceBrowser/WindowsCE/Resources/Application.ico differ
index c453f272fa9d3b5e20fb78ca28630e9e7db86782..71af68d8c64fd37841659c8eb698e9c2cd15d204 100644 (file)
@@ -116,7 +116,7 @@ BEGIN
             VALUE "FileDescription", "Rendezvous Browser for Windows CE\0"
             VALUE "FileVersion", "1, 0, 0, 1\0"
             VALUE "InternalName", "Application\0"
-            VALUE "LegalCopyright", "Copyright Â© 2003 Apple Computer, Inc.\0"
+            VALUE "LegalCopyright", "Copyright (C) 2003-2004 Apple Computer, Inc.\0"
             VALUE "LegalTrademarks", "\0"
             VALUE "OriginalFilename", "Application.exe\0"
             VALUE "PrivateBuild", "\0"
index ba28f412b32572e06e1e9bae165ab7fafe9b148b..9bcde04081fdf8abfdad1499f5a509adfdf5ee1d 100644 (file)
@@ -1,8 +1,10 @@
 /*
- * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
@@ -23,6 +25,9 @@
     Change History (most recent first):
     
 $Log: Application.cpp,v $
+Revision 1.2  2004/01/30 02:56:33  bradley
+Updated to support full Unicode display. Added support for all services on www.dns-sd.org.
+
 Revision 1.1  2003/08/21 02:16:10  bradley
 Rendezvous Browser for HTTP services for Windows CE/PocketPC.
 
@@ -80,12 +85,6 @@ BOOL Application::InitInstance()
        BOOL                            dnsInitialized;
        
        dnsInitialized = FALSE;
-
-       if( !AfxSocketInit() )
-       {
-               AfxMessageBox( IDP_SOCKETS_INIT_FAILED );
-               goto exit;
-       }
        
        err = DNSServicesInitialize( kDNSFlagAdvertise, 0 );
        if( err )
index 1f4fe133816f955cb4f09d80b1d8861faa56f3d4..5e5b5079967b14ca87318114a7a84d336a3b65bf 100644 (file)
@@ -1,8 +1,10 @@
 /*
- * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
@@ -23,6 +25,9 @@
     Change History (most recent first):
     
 $Log: Application.h,v $
+Revision 1.2  2004/01/30 02:56:33  bradley
+Updated to support full Unicode display. Added support for all services on www.dns-sd.org.
+
 Revision 1.1  2003/08/21 02:16:10  bradley
 Rendezvous Browser for HTTP services for Windows CE/PocketPC.
 
index 991fc08b97ae6815528e53aa6c330483ed25ab77..63208aaa7a44888407e1d28f338aff48b679506c 100644 (file)
@@ -1,8 +1,10 @@
 /*
- * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
     Change History (most recent first):
     
 $Log: BrowserDialog.cpp,v $
+Revision 1.5  2004/01/30 02:56:33  bradley
+Updated to support full Unicode display. Added support for all services on www.dns-sd.org.
+
+Revision 1.4  2003/10/16 09:21:56  bradley
+Ignore non-IPv4 resolves until mDNS on Windows supports IPv6.
+
+Revision 1.3  2003/10/14 03:28:50  bradley
+Insert services in sorted order to make them easier to find. Defer service adds/removes to the main
+thread to avoid potential problems with multi-threaded MFC message map access. Added some asserts.
+
+Revision 1.2  2003/10/10 03:43:34  bradley
+Added support for launching a web browser to go to the browsed web site on a single-tap.
+
 Revision 1.1  2003/08/21 02:16:10  bradley
 Rendezvous Browser for HTTP services for Windows CE/PocketPC.
 
@@ -42,12 +57,22 @@ Rendezvous Browser for HTTP services for Windows CE/PocketPC.
 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()
 
@@ -67,6 +92,7 @@ BrowserDialog::BrowserDialog( CWnd *inParent )
        // Note that LoadIcon does not require a subsequent DestroyIcon in Win32.
        
        mIcon = AfxGetApp()->LoadIcon( IDR_MAINFRAME );
+       ASSERT( mIcon );
 }
 
 //===========================================================================================================================
@@ -110,14 +136,14 @@ BOOL      BrowserDialog::OnInitDialog()
 
        DNSStatus               err;
 
-       err = DNSBrowserCreate( 0, BrowserCallBack, this, &mBrowser );
+       err = DNSBrowserCreate( 0, OnBrowserCallBack, this, &mBrowser );
        if( err )
        {
                AfxMessageBox( IDP_SOCKETS_INIT_FAILED );
                goto exit;
        }
        
-       err = DNSBrowserStartServiceSearch( mBrowser, 0, "_http._tcp", NULL );
+       err = DNSBrowserStartServiceSearch( mBrowser, kDNSBrowserFlagAutoResolve, "_http._tcp", NULL );
        if( err )
        {
                AfxMessageBox( IDP_SOCKETS_INIT_FAILED );
@@ -128,30 +154,124 @@ exit:
        return( TRUE );
 }
 
+
 //===========================================================================================================================
-//     BrowserCallBack [static]
+//     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::BrowserCallBack( 
+       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 kDNSBrowserEventTypeAddService:
-                       dialog->BrowserAddService( inEvent->data.addService.name );
+               case kDNSBrowserEventTypeResolved:
+                       if( inEvent->data.resolved->address.addressType == kDNSNetworkAddressTypeIPv4  )
+                       {
+                               char            ip[ 64 ];
+
+                               sprintf( 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:
-                       dialog->BrowserRemoveService( inEvent->data.removeService.name );
+                       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:
@@ -163,58 +283,103 @@ void
 //     BrowserAddService
 //===========================================================================================================================
 
-void   BrowserDialog::BrowserAddService( const char *inName )
+LONG   BrowserDialog::OnServiceAdd( WPARAM inWParam, LPARAM inLParam )
 {
-       BrowserEntry            newEntry;
-       INT_PTR                         n;
-       INT_PTR                         i;
+       BrowserEntry *          entry;
+       INT_PTR                         lo;
+       INT_PTR                         hi;
+       INT_PTR                         mid;
+       int                                     result;
        
-       UTF8StringToStringObject( inName, newEntry.name );
-
-       n = mBrowserEntries.GetSize();
-       for( i = 0; i < n; ++i )
+       (void) inWParam;        // Unused
+       
+       entry = reinterpret_cast < BrowserEntry * > ( inLParam );
+       ASSERT( entry );
+       
+       result  = -1;
+       mid             = 0;
+       lo              = 0;
+       hi              = mBrowserEntries.GetSize() - 1;
+       while( lo <= hi )
        {
-               BrowserEntry &          entry = mBrowserEntries.ElementAt( i );
-
-               if( entry.name.CompareNoCase( newEntry.name ) == 0 )
+               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( i >= n )
+       if( result == 0 )
        {
-               mBrowserEntries.Add( newEntry );
-               mBrowserList.InsertItem( i, newEntry.name );
+               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 );
 }
 
 //===========================================================================================================================
-//     BrowserRemoveService
+//     OnServiceRemove
 //===========================================================================================================================
 
-void   BrowserDialog::BrowserRemoveService( const char *inName )
+LONG   BrowserDialog::OnServiceRemove( WPARAM inWParam, LPARAM inLParam )
 {
-       BrowserEntry            newEntry;
-       INT_PTR                         n;
-       INT_PTR                         i;
-       
-       UTF8StringToStringObject( inName, newEntry.name );
+       BrowserEntry *          entry;
+       INT_PTR                         hi;
+       INT_PTR                         lo;
+       INT_PTR                         mid;
+       int                                     result;
 
-       n = mBrowserEntries.GetSize();
-       for( i = 0; i < n; ++i )
+       (void) inWParam;        // Unused
+       
+       entry = reinterpret_cast < BrowserEntry * > ( inLParam );
+       ASSERT( entry );
+       
+       result  = -1;
+       mid             = 0;
+       lo              = 0;
+       hi              = mBrowserEntries.GetSize() - 1;
+       while( lo <= hi )
        {
-               BrowserEntry &          entry = mBrowserEntries.ElementAt( i );
-
-               if( entry.name.CompareNoCase( newEntry.name ) == 0 )
+               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( i < n )
+       if( result == 0 )
        {
-               mBrowserEntries.RemoveAt( i );
-               mBrowserList.DeleteItem( i );
+               mBrowserList.DeleteItem( mid );
+               mBrowserEntries.RemoveAt( mid );
        }
+       delete entry;
+       return( 0 );
 }
 
 #if 0
index 77775105d88e217313d0571970e29c9a4db8cb34..e2f56c91a0d18296863bee3cc6d7520df28ee24a 100644 (file)
@@ -1,8 +1,10 @@
 /*
- * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
     Change History (most recent first):
     
 $Log: BrowserDialog.h,v $
+Revision 1.4  2004/01/30 02:56:33  bradley
+Updated to support full Unicode display. Added support for all services on www.dns-sd.org.
+
+Revision 1.3  2003/10/14 03:28:50  bradley
+Insert services in sorted order to make them easier to find. Defer service adds/removes to the main
+thread to avoid potential problems with multi-threaded MFC message map access. Added some asserts.
+
+Revision 1.2  2003/10/10 03:43:34  bradley
+Added support for launching a web browser to go to the browsed web site on a single-tap.
+
 Revision 1.1  2003/08/21 02:16:10  bradley
 Rendezvous Browser for HTTP services for Windows CE/PocketPC.
 
@@ -62,23 +74,21 @@ class       BrowserDialog : public CDialog
                //}}AFX_VIRTUAL
                
                static void
-                       BrowserCallBack( 
+                       OnBrowserCallBack( 
                                void *                                  inContext, 
                                DNSBrowserRef                   inRef, 
                                DNSStatus                               inStatusCode,  
                                const DNSBrowserEvent * inEvent );
                
-               void    BrowserAddService( const char *inName );
-               void    BrowserRemoveService( const char *inName );
-               
        protected:
                
                struct  BrowserEntry
                {
                        CString         name;
+                       CString         ip;
+                       CString         text;
                };
                
-               
                HICON                                                                           mIcon;
                DNSBrowserRef                                                           mBrowser;
                CArray < BrowserEntry, BrowserEntry >           mBrowserEntries;
@@ -86,6 +96,9 @@ class BrowserDialog : public CDialog
                // 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()
 };
index 6622a5dd2d1b53baf16dd772eddda1eba412b7c9..33ea0a37f866797e943527e1ba14df5f09f66610 100644 (file)
@@ -1,8 +1,10 @@
 /*
- * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
@@ -23,6 +25,9 @@
     Change History (most recent first):
     
 $Log: StdAfx.cpp,v $
+Revision 1.2  2004/01/30 02:56:33  bradley
+Updated to support full Unicode display. Added support for all services on www.dns-sd.org.
+
 Revision 1.1  2003/08/21 02:16:10  bradley
 Rendezvous Browser for HTTP services for Windows CE/PocketPC.
 
index 3672152459ed954d69746d50ca97362325ce8d7d..e3be1968eaad0653cc13cae2a9ed54bbd2dcf1db 100644 (file)
@@ -1,8 +1,10 @@
 /*
- * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
@@ -23,6 +25,9 @@
     Change History (most recent first):
     
 $Log: StdAfx.h,v $
+Revision 1.2  2004/01/30 02:56:33  bradley
+Updated to support full Unicode display. Added support for all services on www.dns-sd.org.
+
 Revision 1.1  2003/08/21 02:16:10  bradley
 Rendezvous Browser for HTTP services for Windows CE/PocketPC.
 
@@ -50,7 +55,8 @@ Rendezvous Browser for HTTP services for Windows CE/PocketPC.
 #include <afxcmn.h>                    // MFC support for Windows Common Controls
 #endif // _AFX_NO_AFXCMN_SUPPORT
 
-#include <afxsock.h>           // MFC socket extensions
+#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.
index 7e49566e1d1f4cbac12812184d72edec03334c29..46e8e0c025cc74a4166bfbcb2c20ea6c8b13b703 100644 (file)
@@ -1,8 +1,10 @@
 /*
- * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
     Change History (most recent first):
        
 $Log: Tool.c,v $
+Revision 1.12  2004/04/09 21:03:15  bradley
+Changed port numbers to use network byte order for consistency with other platforms.
+
+Revision 1.11  2004/01/30 03:04:32  bradley
+Updated for latest changes to mDNSWindows.
+
+Revision 1.10  2003/10/31 12:18:31  bradley
+Added display of the resolved host name. Show separate TXT record entries on separate lines.
+
+Revision 1.9  2003/10/22 02:00:20  bradley
+Fixed proxy IP setup to be in network byte order so it works on Mac and Windows.
+
+Revision 1.8  2003/10/04 04:47:08  bradley
+Changed DNSServiceRegistrationCreate to treat the port in network byte order for end-to-end consistency.
+
 Revision 1.7  2003/08/20 07:06:34  bradley
 Update to APSL 2.0. Updated change history to match other mDNSResponder files.
 
@@ -289,7 +306,7 @@ static int ProcessArgs( int argc, char* argv[] )
        const char *                                    name;
        const char *                                    type;
        const char *                                    domain;
-       int                                                             port;
+       uint16_t                                                port;
        const char *                                    text;
        size_t                                                  textSize;
        DNSBrowserRef                                   browser;
@@ -433,10 +450,10 @@ static int ProcessArgs( int argc, char* argv[] )
                        name            = argv[ i++ ];
                        type            = argv[ i++ ];
                        domain          = argv[ i++ ];
-                       port            = atoi( argv[ i++ ] );
+                       port            = (uint16_t) atoi( argv[ i++ ] );
                        text            = argv[ i ];
                        textSize        = strlen( text );
-                       if( ( domain[ 0 ] == '.' ) && ( domain[ 1 ] == '\0' ) )
+                       if( ( domain[ 0 ] == '\0' ) || ( ( domain[ 0 ] == '.' ) && ( domain[ 1 ] == '\0' ) ) )
                        {
                                domain = "local.";
                        }
@@ -450,7 +467,7 @@ static int ProcessArgs( int argc, char* argv[] )
                {
                        DNSHostRegistrationFlags                hostFlags;
                        
-                       // 'r'egister 'p'roxy 's'ervice <name> <type> <domain> <port> <txt>
+                       // 'r'egister 'p'roxy 's'ervice <host> <ip> <name> <type> <domain> <port> <txt>
                                                
                        require_action_string( argc > ( i + 7 ), exit, err = kDNSBadParamErr, "missing arguments" );
                        ++i;
@@ -459,7 +476,7 @@ static int ProcessArgs( int argc, char* argv[] )
                        name            = argv[ i++ ];
                        type            = argv[ i++ ];
                        domain          = argv[ i++ ];
-                       port            = atoi( argv[ i++ ] );
+                       port            = (uint16_t) atoi( argv[ i++ ] );
                        text            = argv[ i ];
                        textSize        = strlen( text );
                        if( ( domain[ 0 ] == '\0' ) || ( ( domain[ 0 ] == '.' ) && ( domain[ 1 ] == '\0' ) ) )
@@ -468,8 +485,11 @@ static int ProcessArgs( int argc, char* argv[] )
                        }
                        
                        sscanf( ip, "%u.%u.%u.%u", &b[ 0 ], &b[ 1 ], &b[ 2 ], &b[ 3 ] );
-                       addr.addressType                = kDNSNetworkAddressTypeIPv4;
-                       addr.u.ipv4.addr.v32    = (DNSUInt32)( ( b[ 0 ] << 24 ) | ( b[ 1 ] << 16 ) | ( b[ 2 ] <<  8 ) | ( b[ 3 ] <<  0 ) );
+                       addr.addressType                        = kDNSNetworkAddressTypeIPv4;
+                       addr.u.ipv4.addr.v8[ 0 ]        = (DNSUInt8) b[ 0 ];
+                       addr.u.ipv4.addr.v8[ 1 ]        = (DNSUInt8) b[ 1 ];
+                       addr.u.ipv4.addr.v8[ 2 ]        = (DNSUInt8) b[ 2 ];
+                       addr.u.ipv4.addr.v8[ 3 ]        = (DNSUInt8) b[ 3 ];
                        
                        fprintf( stdout, "registering proxy service \"%s.%s.%s\" port %d text \"%s\"\n", name, type, domain, port, text );
                        
@@ -570,16 +590,16 @@ static int ProcessArgs( int argc, char* argv[] )
                        name            = argv[ i++ ];
                        type            = argv[ i++ ];
                        domain          = argv[ i++ ];
-                       port            = atoi( argv[ i++ ] );
+                       port            = (uint16_t) atoi( argv[ i++ ] );
                        text            = argv[ i ];
                        textSize        = strlen( text );
-                       if( ( domain[ 0 ] == '.' ) && ( domain[ 1 ] == '\0' ) )
+                       if( ( domain[ 0 ] == '\0' ) || ( ( domain[ 0 ] == '.' ) && ( domain[ 1 ] == '\0' ) ) )
                        {
                                domain = "local.";
                        }
                        fprintf( stdout, "registering service \"%s.%s.%s\" port %d text \"%s\"\n", name, type, domain, port, text );
                        
-                       emulatedRef = DNSServiceRegistrationCreate( name, type, domain, (uint16_t) port, text, 
+                       emulatedRef = DNSServiceRegistrationCreate( name, type, domain, htons( port ), text, 
                                                                                                                EmulatedRegistrationCallBack, NULL );
                        require_action_string( emulatedRef, exit, err = kDNSUnknownErr, "create emulated registration failed" );
                }
@@ -758,10 +778,11 @@ static void BrowserCallBack( void *inContext, DNSBrowserRef inRef, DNSStatus inS
                        const uint8_t *         end;
                        int                                     i;
                        
-                       fprintf( stdout, "resolved       \"%s.%s%s\" to %s:%u on interface 0x%08X (%s)%s\n", 
+                       fprintf( stdout, "resolved       \"%s.%s%s\" to \"%s\" (%s:%u) on interface 0x%08X (%s)%s\n", 
                                         inEvent->data.resolved->name, 
                                         inEvent->data.resolved->type, 
                                         inEvent->data.resolved->domain, 
+                                        inEvent->data.resolved->hostName, 
                                         IPv4ToString( inEvent->data.resolved->address.u.ipv4.addr, ip ), 
                                         ( inEvent->data.resolved->address.u.ipv4.port.v8[ 0 ] << 8 ) | 
                                           inEvent->data.resolved->address.u.ipv4.port.v8[ 1 ], 
@@ -820,10 +841,11 @@ static void ResolverCallBack( void *inContext, DNSResolverRef inRef, DNSStatus i
                        const uint8_t *         end;
                        int                                     i;
                        
-                       fprintf( stdout, "resolved       \"%s.%s%s\" to %s:%u on interface 0x%08X (%s)%s\n", 
+                       fprintf( stdout, "resolved       \"%s.%s%s\" to \"%s\" (%s:%u) on interface 0x%08X (%s)%s\n", 
                                         inEvent->data.resolved.name, 
                                         inEvent->data.resolved.type, 
                                         inEvent->data.resolved.domain, 
+                                        inEvent->data.resolved.hostName, 
                                         IPv4ToString( inEvent->data.resolved.address.u.ipv4.addr, ip ), 
                                         ( inEvent->data.resolved.address.u.ipv4.port.v8[ 0 ] << 8 ) | 
                                           inEvent->data.resolved.address.u.ipv4.port.v8[ 1 ], 
index eaa6a70e675a9ac7bdf1f691da1e2780621fe864..901df49c739096fe3d022e94d7e9e18570c201a4 100644 (file)
@@ -1,8 +1,10 @@
 /*
- * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
@@ -23,6 +25,9 @@
     Change History (most recent first):
 
 $Log: ToolPrefixWindows.h,v $
+Revision 1.3  2004/01/30 03:04:32  bradley
+Updated for latest changes to mDNSWindows.
+
 Revision 1.2  2003/08/20 07:06:34  bradley
 Update to APSL 2.0. Updated change history to match other mDNSResponder files.
 
index 1f76fc225f4d84ab84adf32267013e46fda91931..5858503c5df1f7b5db196ec0fbd25796234010ae 100644 (file)
@@ -1,8 +1,10 @@
 /*
- * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
@@ -23,6 +25,9 @@
     Change History (most recent first):
     
 $Log: ToolPrefixWindowsDebug.h,v $
+Revision 1.3  2004/01/30 03:04:32  bradley
+Updated for latest changes to mDNSWindows.
+
 Revision 1.2  2003/08/20 07:06:34  bradley
 Update to APSL 2.0. Updated change history to match other mDNSResponder files.
 
index 064aba024384e04fd43cd810abd4688ce02028e7..21a4ed63564df5c789d5ab609f17095235e893fe 100644 (file)
Binary files a/mDNSWindows/Applications/DNSServiceTest/ToolWin32.mcp and b/mDNSWindows/Applications/DNSServiceTest/ToolWin32.mcp differ
index bc86b75d2b6403b9ec377cd2ee7c7bad2305c732..49300909e29f7f6582efe98268ea67ddd018117f 100644 (file)
@@ -3,15 +3,12 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Tool", "ToolWin32VS2002.vcp
 EndProject
 Global
        GlobalSection(SolutionConfiguration) = preSolution
-               ConfigName.0 = all
-               ConfigName.1 = Debug
-               ConfigName.2 = Release
+               ConfigName.0 = Debug
+               ConfigName.1 = Release
        EndGlobalSection
        GlobalSection(ProjectDependencies) = postSolution
        EndGlobalSection
        GlobalSection(ProjectConfiguration) = postSolution
-               {F66EFE7E-50A6-44D4-87C7-742B303BA852}.all.ActiveCfg = all|Win32
-               {F66EFE7E-50A6-44D4-87C7-742B303BA852}.all.Build.0 = all|Win32
                {F66EFE7E-50A6-44D4-87C7-742B303BA852}.Debug.ActiveCfg = Debug|Win32
                {F66EFE7E-50A6-44D4-87C7-742B303BA852}.Debug.Build.0 = Debug|Win32
                {F66EFE7E-50A6-44D4-87C7-742B303BA852}.Release.ActiveCfg = Release|Win32
index d5e1868c1957771a487bc692014b4168985751ff..cddc5a2779661d792c89da9aaa58fec3b5858c5c 100644 (file)
                        <Tool
                                Name="VCWebDeploymentTool"/>
                </Configuration>
-               <Configuration
-                       Name="all|Win32"
-                       OutputDirectory="all"
-                       IntermediateDirectory="all"
-                       ConfigurationType="1">
-                       <Tool
-                               Name="VCCLCompilerTool"/>
-                       <Tool
-                               Name="VCCustomBuildTool"/>
-                       <Tool
-                               Name="VCLinkerTool"/>
-                       <Tool
-                               Name="VCMIDLTool"/>
-                       <Tool
-                               Name="VCPostBuildEventTool"/>
-                       <Tool
-                               Name="VCPreBuildEventTool"/>
-                       <Tool
-                               Name="VCPreLinkEventTool"/>
-                       <Tool
-                               Name="VCResourceCompilerTool"/>
-                       <Tool
-                               Name="VCWebServiceProxyGeneratorTool"/>
-                       <Tool
-                               Name="VCWebDeploymentTool"/>
-               </Configuration>
        </Configurations>
        <Files>
                <Filter
                        Name="Rendezvous"
                        Filter="">
+                       <File
+                               RelativePath="..\..\..\mDNSCore\DNSCommon.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\..\mDNSCore\DNSCommon.h">
+                       </File>
+                       <File
+                               RelativePath="..\..\..\mDNSCore\DNSDigest.c">
+                       </File>
                        <File
                                RelativePath="..\..\DNSServices\DNSServiceDiscovery.c">
                        </File>
                        <File
                                RelativePath="..\..\..\mDNSCore\mDNSDebug.h">
                        </File>
-                       <File
-                               RelativePath="..\..\..\mDNSCore\mDNSPlatformFunctions.h">
-                       </File>
                        <File
                                RelativePath="..\..\mDNSWin32.c">
                        </File>
                        <File
                                RelativePath="..\..\mDNSWin32.h">
                        </File>
+                       <File
+                               RelativePath="..\..\..\mDNSCore\uDNS.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\..\mDNSCore\uDNS.h">
+                       </File>
                </Filter>
                <File
                        RelativePath="Tool.c">
index 53a2ba25c3514e897900dc404f7e91dbd982b4d1..e5e0122957f929e11f0594367828d4d2bfd4d3ca 100644 (file)
@@ -5,13 +5,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Tool", "ToolWin32VS2003.vcp
 EndProject
 Global
        GlobalSection(SolutionConfiguration) = preSolution
-               all = all
                Debug = Debug
                Release = Release
        EndGlobalSection
        GlobalSection(ProjectConfiguration) = postSolution
-               {F66EFE7E-50A6-44D4-87C7-742B303BA852}.all.ActiveCfg = all|Win32
-               {F66EFE7E-50A6-44D4-87C7-742B303BA852}.all.Build.0 = all|Win32
                {F66EFE7E-50A6-44D4-87C7-742B303BA852}.Debug.ActiveCfg = Debug|Win32
                {F66EFE7E-50A6-44D4-87C7-742B303BA852}.Debug.Build.0 = Debug|Win32
                {F66EFE7E-50A6-44D4-87C7-742B303BA852}.Release.ActiveCfg = Release|Win32
index 2349cb9069fe3ae4f2747e97db143279bc5353c2..c0ed0ee8c95df9bca13466ca7a7c0263aeec5fd1 100644 (file)
                        <Tool
                                Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
                </Configuration>
-               <Configuration
-                       Name="all|Win32"
-                       OutputDirectory="all"
-                       IntermediateDirectory="all"
-                       ConfigurationType="1">
-                       <Tool
-                               Name="VCCLCompilerTool"/>
-                       <Tool
-                               Name="VCCustomBuildTool"/>
-                       <Tool
-                               Name="VCLinkerTool"/>
-                       <Tool
-                               Name="VCMIDLTool"/>
-                       <Tool
-                               Name="VCPostBuildEventTool"/>
-                       <Tool
-                               Name="VCPreBuildEventTool"/>
-                       <Tool
-                               Name="VCPreLinkEventTool"/>
-                       <Tool
-                               Name="VCResourceCompilerTool"/>
-                       <Tool
-                               Name="VCWebServiceProxyGeneratorTool"/>
-                       <Tool
-                               Name="VCXMLDataGeneratorTool"/>
-                       <Tool
-                               Name="VCWebDeploymentTool"/>
-                       <Tool
-                               Name="VCManagedWrapperGeneratorTool"/>
-                       <Tool
-                               Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
-               </Configuration>
        </Configurations>
        <References>
        </References>
                <Filter
                        Name="Rendezvous"
                        Filter="">
+                       <File
+                               RelativePath="..\..\..\mDNSCore\DNSCommon.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\..\mDNSCore\DNSCommon.h">
+                       </File>
+                       <File
+                               RelativePath="..\..\..\mDNSCore\DNSDigest.c">
+                       </File>
                        <File
                                RelativePath="..\..\DNSServices\DNSServiceDiscovery.c">
                        </File>
                        <File
                                RelativePath="..\..\..\mDNSCore\mDNSDebug.h">
                        </File>
-                       <File
-                               RelativePath="..\..\..\mDNSCore\mDNSPlatformFunctions.h">
-                       </File>
                        <File
                                RelativePath="..\..\mDNSWin32.c">
                        </File>
                        <File
                                RelativePath="..\..\mDNSWin32.h">
                        </File>
+                       <File
+                               RelativePath="..\..\..\mDNSCore\uDNS.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\..\mDNSCore\uDNS.h">
+                       </File>
                </Filter>
                <File
                        RelativePath="Tool.c">
diff --git a/mDNSWindows/Applications/ExplorerPlugin/ClassFactory.cpp b/mDNSWindows/Applications/ExplorerPlugin/ClassFactory.cpp
new file mode 100644 (file)
index 0000000..44c9fb2
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+    
+$Log: ClassFactory.cpp,v $
+Revision 1.1  2004/01/30 03:01:56  bradley
+Explorer Plugin to browse for Rendezvous-enabled Web and FTP servers from within Internet Explorer.
+
+*/
+
+#include       "StdAfx.h"
+
+#include       "DebugServices.h"
+
+#include       "ExplorerBar.h"
+#include       "ExplorerPlugin.h"
+
+#include       "ClassFactory.h"
+
+// MFC Debugging
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+//===========================================================================================================================
+//     ClassFactory
+//===========================================================================================================================
+
+ClassFactory::ClassFactory( CLSID inCLSID )
+{
+       mCLSIDObject    = inCLSID;
+       mRefCount               = 1;
+       ++gDLLRefCount;
+}
+
+//===========================================================================================================================
+//     ~ClassFactory
+//===========================================================================================================================
+
+ClassFactory::~ClassFactory( void )
+{
+       check( gDLLRefCount > 0 );
+       
+       --gDLLRefCount;
+}
+
+#if 0
+#pragma mark -
+#pragma mark == IUnknown methods ==
+#endif
+
+//===========================================================================================================================
+//     QueryInterface
+//===========================================================================================================================
+
+STDMETHODIMP   ClassFactory::QueryInterface( REFIID inID, LPVOID *outResult )
+{
+       HRESULT         err;
+       
+       check( outResult );
+       
+       if( IsEqualIID( inID, IID_IUnknown ) )
+       {
+               *outResult = this;
+       }
+       else if( IsEqualIID( inID, IID_IClassFactory ) )
+       {
+               *outResult = (IClassFactory *) this;
+       }   
+       else
+       {
+               *outResult = NULL;
+               err = E_NOINTERFACE;
+               goto exit;
+       }
+       
+       ( *( (LPUNKNOWN *) outResult ) )->AddRef();
+       err = S_OK;
+       
+exit:
+       return( err );
+}                                             
+
+//===========================================================================================================================
+//     AddRef
+//===========================================================================================================================
+
+STDMETHODIMP_( DWORD ) ClassFactory::AddRef( void )
+{
+       return( ++mRefCount );
+}
+
+//===========================================================================================================================
+//     Release
+//===========================================================================================================================
+
+STDMETHODIMP_( DWORD ) ClassFactory::Release( void )
+{
+       DWORD           count;
+       
+       count = --mRefCount;
+       if( count == 0 )
+       {
+               delete this;
+       }
+       return( count );
+}
+
+#if 0
+#pragma mark -
+#pragma mark == IClassFactory methods ==
+#endif
+
+//===========================================================================================================================
+//     CreateInstance
+//===========================================================================================================================
+
+STDMETHODIMP   ClassFactory::CreateInstance( LPUNKNOWN inUnknown, REFIID inID, LPVOID *outObject )
+{
+       HRESULT         err;
+       LPVOID          obj;
+       
+       check( outObject );
+       
+       obj             = NULL;
+       *outObject      = NULL;
+       require_action( !inUnknown, exit, err = CLASS_E_NOAGGREGATION );
+       
+       // Create the object based on the CLSID.
+       
+       if( IsEqualCLSID( mCLSIDObject, CLSID_ExplorerBar ) )
+       {
+               try
+               {
+                       obj = new ExplorerBar();
+               }
+               catch( ... )
+               {
+                       // Don't let exception escape.
+               }
+               require_action( obj, exit, err = E_OUTOFMEMORY );
+       }
+       else
+       {
+               err = E_FAIL;
+               goto exit;
+       }
+       
+       // Query for the specified interface. Release the factory since QueryInterface retains it.
+               
+       err = ( (LPUNKNOWN ) obj )->QueryInterface( inID, outObject );
+       ( (LPUNKNOWN ) obj )->Release();
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     LockServer
+//===========================================================================================================================
+
+STDMETHODIMP   ClassFactory::LockServer( BOOL inLock )
+{
+       DEBUG_UNUSED( inLock );
+       
+       return( E_NOTIMPL );
+}
diff --git a/mDNSWindows/Applications/ExplorerPlugin/ClassFactory.h b/mDNSWindows/Applications/ExplorerPlugin/ClassFactory.h
new file mode 100644 (file)
index 0000000..2361129
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+    
+$Log: ClassFactory.h,v $
+Revision 1.1  2004/01/30 03:01:56  bradley
+Explorer Plugin to browse for Rendezvous-enabled Web and FTP servers from within Internet Explorer.
+
+*/
+
+#ifndef __CLASS_FACTORY__
+#define __CLASS_FACTORY__
+
+#include       "StdAfx.h"
+
+//===========================================================================================================================
+//     ClassFactory
+//===========================================================================================================================
+
+class  ClassFactory : public IClassFactory
+{
+       protected:
+       
+               DWORD           mRefCount;
+               CLSID           mCLSIDObject;
+       
+       public:
+       
+               ClassFactory( CLSID inCLSID );
+               ~ClassFactory( void );
+               
+               // IUnknown methods
+               
+               STDMETHODIMP                    QueryInterface( REFIID inID, LPVOID *outResult );
+               STDMETHODIMP_( DWORD )  AddRef( void );
+               STDMETHODIMP_( DWORD )  Release( void );
+
+               // IClassFactory methods
+               
+               STDMETHODIMP    CreateInstance( LPUNKNOWN inUnknown, REFIID inID, LPVOID *outObject );
+               STDMETHODIMP    LockServer( BOOL inLock );
+};
+
+#endif // __CLASS_FACTORY__
diff --git a/mDNSWindows/Applications/ExplorerPlugin/ExplorerBar.cpp b/mDNSWindows/Applications/ExplorerPlugin/ExplorerBar.cpp
new file mode 100644 (file)
index 0000000..4052d77
--- /dev/null
@@ -0,0 +1,582 @@
+/*
+ * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+    
+$Log: ExplorerBar.cpp,v $
+Revision 1.1  2004/01/30 03:01:56  bradley
+Explorer Plugin to browse for Rendezvous-enabled Web and FTP servers from within Internet Explorer.
+
+*/
+
+#include       "StdAfx.h"
+
+#include       "comutil.h"
+#include       "ShObjIdl.h"
+
+#include       "DebugServices.h"
+
+#include       "Resource.h"
+
+#include       "ExplorerBar.h"
+
+// MFC Debugging
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+//===========================================================================================================================
+//     Constants
+//===========================================================================================================================
+
+#define MIN_SIZE_X             10
+#define MIN_SIZE_Y             10
+
+//===========================================================================================================================
+//     ExplorerBar
+//===========================================================================================================================
+
+ExplorerBar::ExplorerBar( void )
+{
+       ++gDLLRefCount;
+       
+       mRefCount               = 1;
+       mSite                   = NULL;
+       mWebBrowser             = NULL;
+       mParentWindow   = NULL;
+       mFocus                  = FALSE;
+       mViewMode               = 0;
+       mBandID                 = 0;
+}
+
+//===========================================================================================================================
+//     ~ExplorerBar
+//===========================================================================================================================
+
+ExplorerBar::~ExplorerBar( void )
+{
+       if( mWebBrowser )
+       {
+               mWebBrowser->Release();
+               mWebBrowser = NULL;
+       }
+       if( mSite )
+       {
+               mSite->Release();
+               mSite = NULL;
+       }
+       
+       --gDLLRefCount;
+}
+
+#if 0
+#pragma mark -
+#pragma mark == IUnknown implementation ==
+#endif
+
+//===========================================================================================================================
+//     QueryInterface
+//===========================================================================================================================
+
+STDMETHODIMP   ExplorerBar::QueryInterface( REFIID inID, LPVOID *outResult )
+{
+       HRESULT         err;
+       
+       if( IsEqualIID( inID, IID_IUnknown ) )                          // IUnknown
+       {
+               *outResult = this;
+       }
+       else if( IsEqualIID( inID, IID_IOleWindow ) )           // IOleWindow
+       {
+               *outResult = (IOleWindow *) this;
+       }
+       else if( IsEqualIID( inID, IID_IDockingWindow ) )       // IDockingWindow
+       {
+               *outResult = (IDockingWindow *) this;
+       }
+       else if( IsEqualIID( inID, IID_IDeskBand ) )            // IDeskBand
+       {
+               *outResult = (IDeskBand *) this;
+       }
+       else if( IsEqualIID( inID, IID_IInputObject ) )         // IInputObject
+       {
+               *outResult = (IInputObject *) this;
+       }
+       else if( IsEqualIID( inID, IID_IObjectWithSite ) )      // IObjectWithSite
+       {
+               *outResult = (IObjectWithSite *) this;
+       }
+       else if( IsEqualIID( inID, IID_IPersistStream ) )       // IPersistStream
+       {
+               *outResult = (IPersistStream *) this;
+       }
+       else
+       {
+               *outResult = NULL;
+               err = E_NOINTERFACE;
+               goto exit;
+       }
+       
+       ( *( (LPUNKNOWN *) outResult ) )->AddRef();
+       err = S_OK;
+
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     AddRef
+//===========================================================================================================================
+
+STDMETHODIMP_( DWORD ) ExplorerBar::AddRef( void )
+{
+       return( ++mRefCount );
+}
+
+//===========================================================================================================================
+//     Release
+//===========================================================================================================================
+
+STDMETHODIMP_( DWORD ) ExplorerBar::Release( void )
+{
+       DWORD           count;
+
+       count = --mRefCount;
+       if( count == 0 )
+       {
+               delete this;
+       }
+       return( count );
+}
+
+#if 0
+#pragma mark -
+#pragma mark == IOleWindow implementation ==
+#endif
+
+//===========================================================================================================================
+//     GetWindow
+//===========================================================================================================================
+
+STDMETHODIMP   ExplorerBar::GetWindow( HWND *outWindow )
+{
+       *outWindow = mWindow.GetSafeHwnd();
+       return( S_OK );
+}
+
+//===========================================================================================================================
+//     ContextSensitiveHelp
+//===========================================================================================================================
+
+STDMETHODIMP   ExplorerBar::ContextSensitiveHelp( BOOL inEnterMode )
+{
+       DEBUG_UNUSED( inEnterMode );
+       
+       return( E_NOTIMPL );
+}
+
+#if 0
+#pragma mark -
+#pragma mark == IDockingWindow implementation ==
+#endif
+
+//===========================================================================================================================
+//     ShowDW
+//===========================================================================================================================
+
+STDMETHODIMP   ExplorerBar::ShowDW( BOOL inShow )
+{
+       if( mWindow.GetSafeHwnd() )
+       {
+               mWindow.ShowWindow( inShow ? SW_SHOW : SW_HIDE );
+       }
+       return( S_OK );
+}
+
+//===========================================================================================================================
+//     CloseDW
+//===========================================================================================================================
+
+STDMETHODIMP   ExplorerBar::CloseDW( DWORD inReserved )
+{
+       DEBUG_UNUSED( inReserved );
+
+       ShowDW( FALSE );
+       if( mWindow.GetSafeHwnd() )
+       {
+               mWindow.SendMessage( WM_CLOSE );
+       }
+       return( S_OK );
+}
+
+//===========================================================================================================================
+//     ResizeBorderDW
+//===========================================================================================================================
+
+STDMETHODIMP   ExplorerBar::ResizeBorderDW( LPCRECT inBorder, IUnknown *inPunkSite, BOOL inReserved )
+{
+       DEBUG_UNUSED( inBorder );
+       DEBUG_UNUSED( inPunkSite );
+       DEBUG_UNUSED( inReserved );
+       
+       return( E_NOTIMPL );
+}
+
+#if 0
+#pragma mark -
+#pragma mark == IDeskBand implementation ==
+#endif
+
+//===========================================================================================================================
+//     GetBandInfo
+//===========================================================================================================================
+
+STDMETHODIMP   ExplorerBar::GetBandInfo( DWORD inBandID, DWORD inViewMode, DESKBANDINFO *outInfo )
+{
+       HRESULT         err;
+       
+       require_action( outInfo, exit, err = E_INVALIDARG );
+       
+       mBandID   = inBandID;
+       mViewMode = inViewMode;
+       
+       if( outInfo->dwMask & DBIM_MINSIZE )
+       {
+               outInfo->ptMinSize.x = 100;
+               outInfo->ptMinSize.y = 100;
+       }
+       if( outInfo->dwMask & DBIM_MAXSIZE )
+       {
+               // Unlimited max size.
+               
+               outInfo->ptMaxSize.x = -1;
+               outInfo->ptMaxSize.y = -1;
+       }
+       if( outInfo->dwMask & DBIM_INTEGRAL )
+       {
+               outInfo->ptIntegral.x = 1;
+               outInfo->ptIntegral.y = 1;
+       }
+       if( outInfo->dwMask & DBIM_ACTUAL )
+       {
+               outInfo->ptActual.x = 0;
+               outInfo->ptActual.y = 0;
+       }
+       if( outInfo->dwMask & DBIM_TITLE )
+       {
+               CString         s;
+               BOOL            ok;
+               
+               ok = s.LoadString( IDS_NAME );
+               require_action( ok, exit, err = kNoResourcesErr );
+               
+               #ifdef UNICODE
+                       lstrcpyn( outInfo->wszTitle, s, sizeof_array( outInfo->wszTitle ) );
+               #else
+                       DWORD           nChars;
+                       
+                       nChars = MultiByteToWideChar( CP_ACP, 0, s, -1, outInfo->wszTitle, sizeof_array( outInfo->wszTitle ) );
+                       err = translate_errno( nChars > 0, (OSStatus) GetLastError(), kUnknownErr );
+                       require_noerr( err, exit );
+               #endif
+       }
+       if( outInfo->dwMask & DBIM_MODEFLAGS )
+       {
+               outInfo->dwModeFlags = DBIMF_NORMAL | DBIMF_VARIABLEHEIGHT;
+       }
+       
+       // Force the default background color.
+       
+       outInfo->dwMask &= ~DBIM_BKCOLOR;
+       err = S_OK;
+       
+exit:
+       return( err );
+}
+
+#if 0
+#pragma mark -
+#pragma mark == IInputObject implementation ==
+#endif
+
+//===========================================================================================================================
+//     UIActivateIO
+//===========================================================================================================================
+
+STDMETHODIMP   ExplorerBar::UIActivateIO( BOOL inActivate, LPMSG inMsg )
+{
+       DEBUG_UNUSED( inMsg );
+       
+       if( inActivate )
+       {
+               mWindow.SetFocus();
+       }
+       return( S_OK );
+}
+
+//===========================================================================================================================
+//     HasFocusIO
+//===========================================================================================================================
+
+STDMETHODIMP   ExplorerBar::HasFocusIO( void )
+{
+       if( mWindow.GetFocus()->GetSafeHwnd() == mWindow.GetSafeHwnd() )
+       {
+               return( S_OK );
+       }
+       return( S_FALSE );
+}
+
+//===========================================================================================================================
+//     TranslateAcceleratorIO
+//===========================================================================================================================
+
+STDMETHODIMP   ExplorerBar::TranslateAcceleratorIO( LPMSG inMsg )
+{
+       DEBUG_UNUSED( inMsg );
+               
+       return( S_FALSE );
+}
+
+#if 0
+#pragma mark -
+#pragma mark == IObjectWithSite implementation ==
+#endif
+
+//===========================================================================================================================
+//     SetSite
+//===========================================================================================================================
+
+STDMETHODIMP   ExplorerBar::SetSite( IUnknown *inPunkSite )
+{
+       AFX_MANAGE_STATE( AfxGetStaticModuleState() );
+       
+       HRESULT         err;
+       
+       // Release the old interfaces.
+       
+       if( mWebBrowser )
+       {
+               mWebBrowser->Release();
+               mWebBrowser = NULL;
+       }
+       if( mSite )
+       {
+               mSite->Release();
+               mSite = NULL;
+       }
+       
+       // A non-NULL site means we're setting the site. Otherwise, the site is being released (done above).
+       
+       if( !inPunkSite )
+       {
+               err = S_OK;
+               goto exit;
+       }
+       
+       // Get the parent window.
+       
+       IOleWindow *            oleWindow;
+               
+       mParentWindow = NULL;
+       err = inPunkSite->QueryInterface( IID_IOleWindow, (LPVOID *) &oleWindow );
+       require( SUCCEEDED( err ), exit );
+       
+       err = oleWindow->GetWindow( &mParentWindow );
+       oleWindow->Release();
+       require_noerr( err, exit );
+       require_action( mParentWindow, exit, err = E_FAIL );
+       
+       // Get the IInputObject interface.
+       
+       err = inPunkSite->QueryInterface( IID_IInputObjectSite, (LPVOID *) &mSite );
+       require( SUCCEEDED( err ), exit );
+       check( mSite );
+       
+       // Get the IWebBrowser2 interface.
+       
+       IOleCommandTarget *             oleCommandTarget;
+       
+       err = inPunkSite->QueryInterface( IID_IOleCommandTarget, (LPVOID *) &oleCommandTarget );
+       require( SUCCEEDED( err ), exit );
+       
+       IServiceProvider *              serviceProvider;
+       
+       err = oleCommandTarget->QueryInterface( IID_IServiceProvider, (LPVOID *) &serviceProvider );
+       oleCommandTarget->Release();
+       require( SUCCEEDED( err ), exit );
+       
+       err = serviceProvider->QueryService( SID_SWebBrowserApp, IID_IWebBrowser2, (LPVOID *) &mWebBrowser );
+       serviceProvider->Release();
+       require( SUCCEEDED( err ), exit );
+       
+       // Create the main window.
+       
+       err = SetupWindow();
+       require_noerr( err, exit );
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     GetSite
+//===========================================================================================================================
+
+STDMETHODIMP   ExplorerBar::GetSite( REFIID inID, LPVOID *outResult )
+{
+       HRESULT         err;
+       
+       *outResult = NULL;
+       require_action( mSite, exit, err = E_FAIL );
+       
+       err = mSite->QueryInterface( inID, outResult );
+       
+exit:
+       return( err );
+}
+
+#if 0
+#pragma mark -
+#pragma mark == IPersistStream implementation ==
+#endif
+
+//
+// IPersistStream implementation
+// 
+// This is only supported to allow the desk band to be dropped on the desktop and to prevent multiple instances of 
+// the desk band from showing up in the context menu. This desk band doesn't actually persist any data.
+//
+
+//===========================================================================================================================
+//     GetClassID
+//===========================================================================================================================
+
+STDMETHODIMP   ExplorerBar::GetClassID( LPCLSID outClassID )
+{
+       *outClassID = CLSID_ExplorerBar;
+       return( S_OK );
+}
+
+//===========================================================================================================================
+//     IsDirty
+//===========================================================================================================================
+
+STDMETHODIMP   ExplorerBar::IsDirty( void )
+{
+       return( S_FALSE );
+}
+
+//===========================================================================================================================
+//     Load
+//===========================================================================================================================
+
+STDMETHODIMP   ExplorerBar::Load( LPSTREAM inStream )
+{
+       DEBUG_UNUSED( inStream );
+       
+       return( S_OK );
+}
+
+//===========================================================================================================================
+//     Save
+//===========================================================================================================================
+
+STDMETHODIMP   ExplorerBar::Save( LPSTREAM inStream, BOOL inClearDirty )
+{
+       DEBUG_UNUSED( inStream );
+       DEBUG_UNUSED( inClearDirty );
+       
+       return( S_OK );
+}
+
+//===========================================================================================================================
+//     GetSizeMax
+//===========================================================================================================================
+
+STDMETHODIMP   ExplorerBar::GetSizeMax( ULARGE_INTEGER *outSizeMax )
+{
+       DEBUG_UNUSED( outSizeMax );
+       
+       return( E_NOTIMPL );
+}
+
+#if 0
+#pragma mark -
+#pragma mark == Other ==
+#endif
+
+//===========================================================================================================================
+//     SetupWindow
+//===========================================================================================================================
+
+OSStatus       ExplorerBar::SetupWindow( void )
+{
+       OSStatus                err;
+       CWnd *                  window;
+       CRect                   rect;
+       CString                 s;
+       BOOL                    ok;
+       
+       window = CWnd::FromHandle( mParentWindow );
+       check( window );
+       window->GetClientRect( rect );
+       
+       ok = s.LoadString( IDS_NAME );
+       require_action( ok, exit, err = kNoResourcesErr );
+       
+       ok = mWindow.Create( NULL, s, WS_CHILD | WS_VISIBLE, rect, window, 100 ) != 0;
+       require_action( ok, exit, err = kNoResourcesErr );
+       
+       mWindow.SetOwner( this );
+       err = kNoErr;
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     GoToURL
+//===========================================================================================================================
+
+OSStatus       ExplorerBar::GoToURL( const CString &inURL )
+{
+       OSStatus                err;
+       BSTR                    s;
+       VARIANT                 empty;
+       
+       s = inURL.AllocSysString();
+       require_action( s, exit, err = kNoMemoryErr );
+       
+       VariantInit( &empty );
+       err = mWebBrowser->Navigate( s, &empty, &empty, &empty, &empty );
+       SysFreeString( s );
+       require_noerr( err, exit );
+
+exit:
+       return( err );
+}
diff --git a/mDNSWindows/Applications/ExplorerPlugin/ExplorerBar.h b/mDNSWindows/Applications/ExplorerPlugin/ExplorerBar.h
new file mode 100644 (file)
index 0000000..1ab9df9
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+    
+$Log: ExplorerBar.h,v $
+Revision 1.1  2004/01/30 03:01:56  bradley
+Explorer Plugin to browse for Rendezvous-enabled Web and FTP servers from within Internet Explorer.
+
+*/
+
+#ifndef        __EXPLORER_BAR__
+#define        __EXPLORER_BAR__
+
+#include       "StdAfx.h"
+
+#include       "ExplorerBarWindow.h"
+#include       "ExplorerPlugin.h"
+
+//===========================================================================================================================
+//     ExplorerBar
+//===========================================================================================================================
+
+class  ExplorerBar : public IDeskBand, 
+                                         public IInputObject, 
+                                         public IObjectWithSite, 
+                                         public IPersistStream
+{
+       protected:
+
+               DWORD                                   mRefCount;
+               IInputObjectSite *              mSite;
+               IWebBrowser2 *                  mWebBrowser;
+               HWND                                    mParentWindow;
+               BOOL                                    mFocus;
+               DWORD                                   mViewMode;
+               DWORD                                   mBandID;
+               ExplorerBarWindow               mWindow;
+               
+       public:
+       
+               ExplorerBar( void );
+               ~ExplorerBar( void );
+               
+               // IUnknown methods
+               
+               STDMETHODIMP                    QueryInterface( REFIID inID, LPVOID *outResult );
+               STDMETHODIMP_( DWORD )  AddRef( void );
+               STDMETHODIMP_( DWORD )  Release( void );
+               
+               // IOleWindow methods
+               
+               STDMETHOD( GetWindow )( HWND *outWindow );
+               STDMETHOD( ContextSensitiveHelp )( BOOL inEnterMode );
+
+               // IDockingWindow methods
+               
+               STDMETHOD( ShowDW )( BOOL inShow );
+               STDMETHOD( CloseDW )( DWORD inReserved );
+               STDMETHOD( ResizeBorderDW )( LPCRECT inBorder, IUnknown *inPunkSite, BOOL inReserved );
+               
+               // IDeskBand methods
+               
+               STDMETHOD( GetBandInfo )( DWORD inBandID, DWORD inViewMode, DESKBANDINFO *outInfo );
+               
+               // IInputObject methods
+               
+               STDMETHOD( UIActivateIO )( BOOL inActivate, LPMSG inMsg );
+               STDMETHOD( HasFocusIO )( void );
+               STDMETHOD( TranslateAcceleratorIO )( LPMSG inMsg );
+               
+               // IObjectWithSite methods
+               
+               STDMETHOD( SetSite )( IUnknown *inPunkSite );
+               STDMETHOD( GetSite )( REFIID inID, LPVOID *outResult );
+               
+               // IPersistStream methods
+               
+               STDMETHOD( GetClassID )( LPCLSID outClassID );
+               STDMETHOD( IsDirty )( void );
+               STDMETHOD( Load )( LPSTREAM inStream );
+               STDMETHOD( Save )( LPSTREAM inStream, BOOL inClearDirty );
+               STDMETHOD( GetSizeMax )( ULARGE_INTEGER *outSizeMax );
+               
+               // Other
+               
+               OSStatus        SetupWindow( void );
+               OSStatus        GoToURL( const CString &inURL );
+};
+
+#endif // __EXPLORER_BAR__
diff --git a/mDNSWindows/Applications/ExplorerPlugin/ExplorerBarWindow.cpp b/mDNSWindows/Applications/ExplorerPlugin/ExplorerBarWindow.cpp
new file mode 100644 (file)
index 0000000..7ca9f2a
--- /dev/null
@@ -0,0 +1,751 @@
+/*
+ * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+    
+$Log: ExplorerBarWindow.cpp,v $
+Revision 1.5  2004/04/15 01:00:05  bradley
+Removed support for automatically querying for A/AAAA records when resolving names. Platforms
+without .local name resolving support will need to manually query for A/AAAA records as needed.
+
+Revision 1.4  2004/04/09 21:03:15  bradley
+Changed port numbers to use network byte order for consistency with other platforms.
+
+Revision 1.3  2004/04/08 09:43:43  bradley
+Changed callback calling conventions to __stdcall so they can be used with C# delegates.
+
+Revision 1.2  2004/02/21 04:36:19  bradley
+Enable dot local name lookups now that the NSP is being installed.
+
+Revision 1.1  2004/01/30 03:01:56  bradley
+Explorer Plugin to browse for Rendezvous-enabled Web and FTP servers from within Internet Explorer.
+
+*/
+
+#include       "StdAfx.h"
+
+#include       "CommonServices.h"
+#include       "DebugServices.h"
+#include       "DNSSD.h"
+
+#include       "ExplorerBar.h"
+#include       "LoginDialog.h"
+#include       "Resource.h"
+
+#include       "ExplorerBarWindow.h"
+
+// MFC Debugging
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+#if 0
+#pragma mark == Constants ==
+#endif
+
+//===========================================================================================================================
+//     Constants
+//===========================================================================================================================
+
+// Control IDs
+
+#define        IDC_EXPLORER_TREE                               1234
+
+// Private Messages
+
+#define        WM_PRIVATE_SERVICE_ADD                  ( WM_USER + 0x100 )
+#define        WM_PRIVATE_SERVICE_REMOVE               ( WM_USER + 0x101 )
+#define        WM_PRIVATE_RESOLVE                              ( WM_USER + 0x102 )
+
+// TXT records
+
+#define        kTXTRecordKeyPath                               "path="
+#define        kTXTRecordKeyPathSize                   sizeof_string( kTXTRecordKeyPath )
+
+#if 0
+#pragma mark == Prototypes ==
+#endif
+
+//===========================================================================================================================
+//     Prototypes
+//===========================================================================================================================
+
+DEBUG_LOCAL int                        FindServiceArrayIndex( const ServiceInfoArray &inArray, const ServiceInfo &inService, int &outIndex );
+DEBUG_LOCAL OSStatus   UTF8StringToStringObject( const char *inUTF8, CString &inObject );
+
+#if 0
+#pragma mark == Message Map ==
+#endif
+
+//===========================================================================================================================
+//     Message Map
+//===========================================================================================================================
+
+BEGIN_MESSAGE_MAP( ExplorerBarWindow, CWnd )
+       ON_WM_CREATE()
+       ON_WM_DESTROY()
+       ON_WM_SIZE()
+       ON_NOTIFY( NM_DBLCLK, IDC_EXPLORER_TREE, OnDoubleClick )
+       ON_MESSAGE( WM_PRIVATE_SERVICE_ADD, OnServiceAdd )
+       ON_MESSAGE( WM_PRIVATE_SERVICE_REMOVE, OnServiceRemove )
+       ON_MESSAGE( WM_PRIVATE_RESOLVE, OnResolve )
+END_MESSAGE_MAP()
+
+#if 0
+#pragma mark -
+#endif
+
+//===========================================================================================================================
+//     ExplorerBarWindow
+//===========================================================================================================================
+
+ExplorerBarWindow::ExplorerBarWindow( void )
+{
+       mOwner                          = NULL;
+       mResolveServiceRef      = NULL;
+}
+
+//===========================================================================================================================
+//     ~ExplorerBarWindow
+//===========================================================================================================================
+
+ExplorerBarWindow::~ExplorerBarWindow( void )
+{
+       //
+}
+
+#if 0
+#pragma mark -
+#endif
+
+//===========================================================================================================================
+//     OnCreate
+//===========================================================================================================================
+
+int    ExplorerBarWindow::OnCreate( LPCREATESTRUCT inCreateStruct )
+{
+       AFX_MANAGE_STATE( AfxGetStaticModuleState() );
+       
+       OSStatus                err;
+       CRect                   rect;
+       CString                 s;
+       
+       err = CWnd::OnCreate( inCreateStruct );
+       require_noerr( err, exit );
+       
+       GetClientRect( rect );
+       mTree.Create( WS_TABSTOP | WS_VISIBLE | WS_CHILD | TVS_HASBUTTONS | TVS_LINESATROOT | TVS_HASLINES, rect, this, 
+               IDC_EXPLORER_TREE );
+       
+       err = DNSServiceInitialize( kDNSServiceInitializeFlagsNone, 0 );
+       if( err != kNoErr )
+       {
+               // Cannot talk to the mDNSResponder service. Show the error message and exit (with kNoErr so they can see it).
+               
+               s.LoadString( IDS_RENDEZVOUS_NOT_AVAILABLE );
+               mTree.InsertItem( s, 0, 0, TVI_ROOT, TVI_LAST );
+               err = kNoErr;
+               goto exit;
+       }
+       
+       ServiceHandlerEntry *           e;
+       
+       // Web Site Handler
+       
+       e = new ServiceHandlerEntry;
+       check( e );
+       e->type                         = "_http._tcp";
+       e->urlScheme            = "http://";
+       e->ref                          = NULL;
+       e->treeItem                     = NULL;
+       e->treeFirst            = true;
+       e->obj                          = this;
+       e->needsLogin           = false;
+       mServiceHandlers.Add( e );
+       
+       s.LoadString( IDS_WEB_SITES );
+       e->treeItem = mTree.InsertItem( s, 0, 0 );
+       mTree.Expand( e->treeItem, TVE_EXPAND );
+       
+       err = DNSServiceBrowse( &e->ref, 0, 0, e->type, NULL, BrowseCallBack, e );
+       require_noerr( err, exit );
+
+       // FTP Site Handler
+       
+       e = new ServiceHandlerEntry;
+       check( e );
+       e->type                         = "_ftp._tcp";
+       e->urlScheme            = "ftp://";
+       e->ref                          = NULL;
+       e->treeItem                     = NULL;
+       e->treeFirst            = true;
+       e->obj                          = this;
+       e->needsLogin           = true;
+       mServiceHandlers.Add( e );
+       
+       s.LoadString( IDS_FTP_SITES );
+       e->treeItem = mTree.InsertItem( s, 0, 0 );
+       mTree.Expand( e->treeItem, TVE_EXPAND );
+       
+       err = DNSServiceBrowse( &e->ref, 0, 0, e->type, NULL, BrowseCallBack, e );
+       require_noerr( err, exit );
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     OnDestroy
+//===========================================================================================================================
+
+void   ExplorerBarWindow::OnDestroy( void ) 
+{
+       // Stop any resolves that may still be pending (shouldn't be any).
+       
+       StopResolve();
+       
+       // Clean up the service handlers.
+       
+       int             i;
+       int             n;
+       
+       n = (int) mServiceHandlers.GetSize();
+       for( i = 0; i < n; ++i )
+       {
+               delete mServiceHandlers[ i ];
+       }
+       
+       DNSServiceFinalize();
+       CWnd::OnDestroy();
+}
+
+//===========================================================================================================================
+//     OnSize
+//===========================================================================================================================
+
+void   ExplorerBarWindow::OnSize( UINT inType, int inX, int inY ) 
+{
+       CWnd::OnSize( inType, inX, inY );
+       mTree.MoveWindow( 0, 0, inX, inY );
+}
+
+//===========================================================================================================================
+//     OnDoubleClick
+//===========================================================================================================================
+
+void   ExplorerBarWindow::OnDoubleClick( NMHDR *inNMHDR, LRESULT *outResult )
+{
+       HTREEITEM                       item;
+       ServiceInfo *           service;
+       OSStatus                        err;
+       
+       DEBUG_UNUSED( inNMHDR );
+       
+       item = mTree.GetSelectedItem();
+       require( item, exit );
+       
+       service = reinterpret_cast < ServiceInfo * > ( mTree.GetItemData( item ) );
+       require_quiet( service, exit );
+       
+       err = StartResolve( service );
+       require_noerr( err, exit );
+
+exit:
+       *outResult = 0;
+}
+
+#if 0
+#pragma mark -
+#endif
+
+//===========================================================================================================================
+//     BrowseCallBack
+//===========================================================================================================================
+
+void CALLBACK_COMPAT
+       ExplorerBarWindow::BrowseCallBack(
+               DNSServiceRef                   inRef,
+               DNSServiceFlags                 inFlags,
+               uint32_t                                inInterfaceIndex,
+               DNSServiceErrorType     inErrorCode,
+               const char *                    inName, 
+               const char *                    inType, 
+               const char *                    inDomain,       
+               void *                                  inContext )
+{
+       ServiceHandlerEntry *           obj;
+       ServiceInfo *                           service;
+       OSStatus                                        err;
+       
+       DEBUG_UNUSED( inRef );
+       
+       service = NULL;
+       
+       require_noerr( inErrorCode, exit );
+       obj = reinterpret_cast < ServiceHandlerEntry * > ( inContext );
+       check( obj );
+       check( obj->obj );
+       
+       try
+       {
+               // Post a message to the main thread so it can handle it since MFC is not thread safe.
+               
+               service = new ServiceInfo;
+               require_action( service, exit, err = kNoMemoryErr );
+               
+               err = UTF8StringToStringObject( inName, service->displayName );
+               check_noerr( err );
+               
+               service->name = strdup( inName );
+               require_action( service->name, exit, err = kNoMemoryErr );
+               
+               service->type = strdup( inType );
+               require_action( service->type, exit, err = kNoMemoryErr );
+               
+               service->domain = strdup( inDomain );
+               require_action( service->domain, exit, err = kNoMemoryErr );
+               
+               service->ifi            = inInterfaceIndex;
+               service->handler        = obj;
+               
+               DWORD           message;
+               BOOL            ok;
+               
+               message = ( inFlags & kDNSServiceFlagsAdd ) ? WM_PRIVATE_SERVICE_ADD : WM_PRIVATE_SERVICE_REMOVE;
+               ok = ::PostMessage( obj->obj->GetSafeHwnd(), message, 0, (LPARAM) service );
+               check( ok );
+               if( ok )
+               {
+                       service = NULL;
+               }
+       }
+       catch( ... )
+       {
+               dlog( kDebugLevelError, "BrowseCallBack: exception thrown\n" );
+       }
+       
+exit:
+       if( service )
+       {
+               delete service;
+       }
+}
+
+//===========================================================================================================================
+//     OnServiceAdd
+//===========================================================================================================================
+
+LONG   ExplorerBarWindow::OnServiceAdd( WPARAM inWParam, LPARAM inLParam )
+{
+       ServiceInfo *                           service;
+       ServiceHandlerEntry *           handler;
+       int                                                     cmp;
+       int                                                     index;
+       
+       DEBUG_UNUSED( inWParam );
+       
+       service = reinterpret_cast < ServiceInfo * > ( inLParam );
+       check( service );
+       handler = service->handler; 
+       check( handler );
+       
+       cmp = FindServiceArrayIndex( handler->array, *service, index );
+       if( cmp == 0 )
+       {
+               // Found a match so update the item. The index is index + 1 so subtract 1.
+               
+               index -= 1;
+               check( index < handler->array.GetSize() );
+               
+               service->item = handler->array[ index ]->item;
+               delete handler->array[ index ];
+               handler->array[ index ] = service;
+               mTree.SetItemText( service->item, service->displayName );
+               mTree.SetItemData( service->item, (DWORD_PTR) service );
+       }
+       else
+       {
+               HTREEITEM               afterItem;
+               
+               // Insert the new item in sorted order.
+               
+               afterItem = ( index > 0 ) ? handler->array[ index - 1 ]->item : TVI_FIRST;
+               handler->array.InsertAt( index, service );
+               service->item = mTree.InsertItem( service->displayName, handler->treeItem, afterItem );
+               mTree.SetItemData( service->item, (DWORD_PTR) service );
+               
+               // Make sure the item is visible if this is the first time a service was added.
+       
+               if( handler->treeFirst )
+               {
+                       handler->treeFirst = false;
+                       mTree.EnsureVisible( service->item );
+               }
+       }
+       return( 0 );
+}
+
+//===========================================================================================================================
+//     OnServiceRemove
+//===========================================================================================================================
+
+LONG   ExplorerBarWindow::OnServiceRemove( WPARAM inWParam, LPARAM inLParam )
+{
+       ServiceInfo *                           service;
+       ServiceHandlerEntry *           handler;
+       int                                                     cmp;
+       int                                                     index;
+       
+       DEBUG_UNUSED( inWParam );
+       
+       service = reinterpret_cast < ServiceInfo * > ( inLParam );
+       check( service );
+       handler = service->handler; 
+       check( handler );
+       
+       // Search to see if we know about this service instance. If so, remove it from the list.
+       
+       cmp = FindServiceArrayIndex( handler->array, *service, index );
+       check( cmp == 0 );
+       if( cmp == 0 )
+       {
+               // Found a match remove the item. The index is index + 1 so subtract 1.
+               
+               index -= 1;
+               check( index < handler->array.GetSize() );
+               
+               mTree.DeleteItem( handler->array[ index ]->item );
+               delete handler->array[ index ];
+               handler->array.RemoveAt( index );
+       }
+       delete service;
+       return( 0 );
+}
+
+#if 0
+#pragma mark -
+#endif
+
+//===========================================================================================================================
+//     StartResolve
+//===========================================================================================================================
+
+OSStatus       ExplorerBarWindow::StartResolve( ServiceInfo *inService )
+{
+       OSStatus                err;
+       
+       check( inService );
+       
+       // Stop any current resolve that may be in progress.
+       
+       StopResolve();
+       
+       // Resolve the service.
+       
+       err = DNSServiceResolve( &mResolveServiceRef, kDNSServiceFlagsNone, inService->ifi, 
+               inService->name, inService->type, inService->domain, ResolveCallBack, inService->handler );
+       require_noerr( err, exit );
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     StopResolve
+//===========================================================================================================================
+
+void   ExplorerBarWindow::StopResolve( void )
+{
+       if( mResolveServiceRef )
+       {
+               DNSServiceRefDeallocate( mResolveServiceRef );
+               mResolveServiceRef = NULL;
+       }
+}
+
+//===========================================================================================================================
+//     ResolveCallBack
+//===========================================================================================================================
+
+void CALLBACK_COMPAT
+       ExplorerBarWindow::ResolveCallBack(
+               DNSServiceRef                   inRef,
+               DNSServiceFlags                 inFlags,
+               uint32_t                                inInterfaceIndex,
+               DNSServiceErrorType             inErrorCode,
+               const char *                    inFullName,     
+               const char *                    inHostName, 
+               uint16_t                                inPort,
+               uint16_t                                inTXTSize,
+               const char *                    inTXT,
+               void *                                  inContext )
+{
+       ExplorerBarWindow *                     obj;
+       ServiceHandlerEntry *           handler;
+       OSStatus                                        err;
+       
+       DEBUG_UNUSED( inRef );
+       DEBUG_UNUSED( inFlags );
+       DEBUG_UNUSED( inErrorCode );
+       DEBUG_UNUSED( inFullName );
+       
+       require_noerr( inErrorCode, exit );
+       handler = (ServiceHandlerEntry *) inContext;
+       check( handler );
+       obj = handler->obj;
+       check( obj );
+       
+       try
+       {
+               ResolveInfo *           resolve;
+               BOOL                            ok;
+               
+               dlog( kDebugLevelNotice, "resolved %s on ifi %d to %s\n", inFullName, inInterfaceIndex, inHostName );
+               
+               // Stop resolving after the first good result.
+               
+               obj->StopResolve();
+               
+               // Post a message to the main thread so it can handle it since MFC is not thread safe.
+               
+               resolve = new ResolveInfo;
+               require_action( resolve, exit, err = kNoMemoryErr );
+               
+               UTF8StringToStringObject( inHostName, resolve->host );
+               resolve->port           = ntohs( inPort );
+               resolve->ifi            = inInterfaceIndex;
+               resolve->handler        = handler;
+               
+               err = resolve->txt.SetData( inTXT, inTXTSize );
+               check_noerr( err );
+               
+               ok = ::PostMessage( obj->GetSafeHwnd(), WM_PRIVATE_RESOLVE, 0, (LPARAM) resolve );
+               check( ok );
+               if( !ok )
+               {
+                       delete resolve;
+               }
+       }
+       catch( ... )
+       {
+               dlog( kDebugLevelError, "ResolveCallBack: exception thrown\n" );
+       }
+
+exit:
+       return;
+}
+
+//===========================================================================================================================
+//     OnResolve
+//===========================================================================================================================
+
+LONG   ExplorerBarWindow::OnResolve( WPARAM inWParam, LPARAM inLParam )
+{
+       ResolveInfo *           resolve;
+       CString                         url;
+       uint8_t *                       path;
+       size_t                          pathSize;
+       char *                          pathPrefix;
+       CString                         username;
+       CString                         password;
+       
+       DEBUG_UNUSED( inWParam );
+       
+       resolve = reinterpret_cast < ResolveInfo * > ( inLParam );
+       check( resolve );
+               
+       // Get login info if needed.
+       
+       if( resolve->handler->needsLogin )
+       {
+               LoginDialog             dialog;
+               
+               if( !dialog.GetLogin( username, password ) )
+               {
+                       goto exit;
+               }
+       }
+       
+       // If the HTTP TXT record is a "path=" entry, use it as the resource path. Otherwise, use "/".
+       
+       pathPrefix = "";
+       if( strcmp( resolve->handler->type, "_http._tcp" ) == 0 )
+       {
+               resolve->txt.GetData( &path, &pathSize );
+               if( pathSize > 0 )
+               {
+                       pathSize = *path++;
+               }
+               if( ( pathSize > kTXTRecordKeyPathSize ) && ( memicmp( path, kTXTRecordKeyPath, kTXTRecordKeyPathSize ) == 0 )  )
+               {
+                       path            += kTXTRecordKeyPathSize;
+                       pathSize        -= kTXTRecordKeyPathSize;
+               }
+               else if( pathSize == 0 )
+               {
+                       path            = (uint8_t *) "/";
+                       pathSize        = 1;
+               }
+               if( *path != '/' )
+               {
+                       pathPrefix = "/";
+               }
+       }
+       else
+       {
+               path                    = (uint8_t *) "";
+               pathSize                = 1;
+       }
+
+       // Build the URL in the following format:
+       //
+       // <urlScheme>[<username>[:<password>]@]<name/ip>[<path>]
+
+       url.AppendFormat( TEXT( "%S" ), resolve->handler->urlScheme );                                  // URL Scheme
+       if( username.GetLength() > 0 )
+       {
+               url.AppendFormat( TEXT( "%s" ), username );                                                                     // Username
+               if( password.GetLength() > 0 )
+               {
+                       url.AppendFormat( TEXT( ":%s" ), password );                                                    // Password
+               }
+               url.AppendFormat( TEXT( "@" ) );
+       }
+       
+       url += resolve->host;                                                                                                                   // Host
+       url.AppendFormat( TEXT( ":%d" ), resolve->port );                                                               // :Port
+       url.AppendFormat( TEXT( "%S" ), pathPrefix );                                                                   // Path Prefix ("/" or empty).
+       url.AppendFormat( TEXT( "%.*S" ), (int) pathSize, (char *) path );                              // Path (possibly empty).
+       
+       // Tell Internet Explorer to go to the URL.
+       
+       check( mOwner );
+       mOwner->GoToURL( url );
+
+exit:
+       delete resolve;
+       return( 0 );
+}
+
+#if 0
+#pragma mark -
+#endif
+
+//===========================================================================================================================
+//     FindServiceArrayIndex
+//===========================================================================================================================
+
+DEBUG_LOCAL int        FindServiceArrayIndex( const ServiceInfoArray &inArray, const ServiceInfo &inService, int &outIndex )
+{
+       int             result;
+       int             lo;
+       int             hi;
+       int             mid;
+       
+       result  = -1;
+       mid             = 0;
+       lo              = 0;
+       hi              = (int)( inArray.GetSize() - 1 );
+       while( lo <= hi )
+       {
+               mid = ( lo + hi ) / 2;
+               result = inService.displayName.CompareNoCase( inArray[ mid ]->displayName );
+               if( result == 0 )
+               {
+                       result = ( (int) inService.ifi ) - ( (int) inArray[ mid ]->ifi );
+               }
+               if( result == 0 )
+               {
+                       break;
+               }
+               else if( result < 0 )
+               {
+                       hi = mid - 1;
+               }
+               else
+               {
+                       lo = mid + 1;
+               }
+       }
+       if( result == 0 )
+       {
+               mid += 1;       // Bump index so new item is inserted after matching item.
+       }
+       else if( result > 0 )
+       {
+               mid += 1;
+       }
+       outIndex = mid;
+       return( result );
+}
+
+//===========================================================================================================================
+//     UTF8StringToStringObject
+//===========================================================================================================================
+
+DEBUG_LOCAL 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 );
+}
diff --git a/mDNSWindows/Applications/ExplorerPlugin/ExplorerBarWindow.h b/mDNSWindows/Applications/ExplorerPlugin/ExplorerBarWindow.h
new file mode 100644 (file)
index 0000000..ac234f5
--- /dev/null
@@ -0,0 +1,281 @@
+/*
+ * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+    
+$Log: ExplorerBarWindow.h,v $
+Revision 1.3  2004/04/15 01:00:05  bradley
+Removed support for automatically querying for A/AAAA records when resolving names. Platforms
+without .local name resolving support will need to manually query for A/AAAA records as needed.
+
+Revision 1.2  2004/04/08 09:43:43  bradley
+Changed callback calling conventions to __stdcall so they can be used with C# delegates.
+
+Revision 1.1  2004/01/30 03:01:56  bradley
+Explorer Plugin to browse for Rendezvous-enabled Web and FTP servers from within Internet Explorer.
+
+*/
+
+#ifndef        __EXPLORER_BAR_WINDOW__
+#define        __EXPLORER_BAR_WINDOW__
+
+#pragma once
+
+#include       "afxtempl.h"
+
+#include       "DNSSD.h"
+
+//===========================================================================================================================
+//     Structures
+//===========================================================================================================================
+
+// Forward Declarations
+
+struct ServiceHandlerEntry;
+class  ExplorerBarWindow;
+
+// ServiceInfo
+
+struct ServiceInfo
+{
+       CString                                         displayName;
+       char *                                          name;
+       char *                                          type;
+       char *                                          domain;
+       uint32_t                                        ifi;
+       HTREEITEM                                       item;
+       ServiceHandlerEntry *           handler;
+       
+       ServiceInfo( void )
+       {
+               item    = NULL;
+               type    = NULL;
+               domain  = NULL;
+               handler = NULL;
+       }
+       
+       ~ServiceInfo( void )
+       {
+               if( name )
+               {
+                       free( name );
+               }
+               if( type )
+               {
+                       free( type );
+               }
+               if( domain )
+               {
+                       free( domain );
+               }
+       }
+};
+
+typedef CArray < ServiceInfo *, ServiceInfo * >                ServiceInfoArray;
+
+// TextRecord
+
+struct TextRecord
+{
+       uint8_t *               mData;
+       size_t                  mSize;
+       
+       TextRecord( void )
+       {
+               mData = NULL;
+               mSize = 0;
+       }
+       
+       ~TextRecord( void )
+       {
+               if( mData )
+               {
+                       free( mData );
+               }
+       }
+       
+       void    GetData( void *outData, size_t *outSize )
+       {
+               if( outData )
+               {
+                       *( (void **) outData ) = mData;
+               }
+               if( outSize )
+               {
+                       *outSize = mSize;
+               }
+       }
+       
+       OSStatus        SetData( const void *inData, size_t inSize )
+       {
+               OSStatus                err;
+               uint8_t *               newData;
+               
+               newData = (uint8_t *) malloc( inSize );
+               require_action( newData, exit, err = kNoMemoryErr );
+               memcpy( newData, inData, inSize );
+               
+               if( mData )
+               {
+                       free( mData );
+               }
+               mData = newData;
+               mSize = inSize;
+               err  = kNoErr;
+               
+       exit:
+               return( err );
+       }
+};
+
+// ResolveInfo
+
+struct ResolveInfo
+{
+       CString                                         host;
+       uint16_t                                        port;
+       uint32_t                                        ifi;
+       TextRecord                                      txt;
+       ServiceHandlerEntry *           handler;
+};
+
+// ServiceHandlerEntry
+
+struct ServiceHandlerEntry
+{
+       const char *                    type;
+       const char *                    urlScheme;
+       DNSServiceRef                   ref;
+       ServiceInfoArray                array;
+       HTREEITEM                               treeItem;
+       bool                                    treeFirst;
+       ExplorerBarWindow *             obj;
+       bool                                    needsLogin;
+       
+       ServiceHandlerEntry( void )
+       {
+               type            = NULL;
+               urlScheme       = NULL;
+               ref             = NULL;
+               treeItem        = NULL;
+               treeFirst       = true;
+               obj                     = NULL;
+               needsLogin      = false;
+       }
+       
+       ~ServiceHandlerEntry( void )
+       {
+               if( ref )
+               {
+                       DNSServiceRefDeallocate( ref );
+               }
+               
+               int             i;
+               int             n;
+               
+               n = (int) array.GetSize();
+               for( i = 0; i < n; ++i )
+               {
+                       delete array[ i ];
+               }
+       }
+};
+
+typedef CArray < ServiceHandlerEntry *, ServiceHandlerEntry * >                ServiceHandlerArray;
+
+//===========================================================================================================================
+//     ExplorerBarWindow
+//===========================================================================================================================
+
+class  ExplorerBar;    // Forward Declaration
+
+class  ExplorerBarWindow : public CWnd
+{
+       protected:
+
+               ExplorerBar *                   mOwner;
+               CTreeCtrl                               mTree;
+               
+               ServiceHandlerArray             mServiceHandlers;
+               DNSServiceRef                   mResolveServiceRef;
+               
+       public:
+               
+               ExplorerBarWindow( void );
+               virtual ~ExplorerBarWindow( void );
+
+       protected:
+               
+               // General
+               
+               afx_msg int             OnCreate( LPCREATESTRUCT inCreateStruct );
+               afx_msg void    OnDestroy( void );
+               afx_msg void    OnSize( UINT inType, int inX, int inY );
+               afx_msg void    OnDoubleClick( NMHDR *inNMHDR, LRESULT *outResult );
+               
+               // Browsing
+               
+               static void CALLBACK_COMPAT
+                       BrowseCallBack(
+                               DNSServiceRef                   inRef,
+                               DNSServiceFlags                 inFlags,
+                               uint32_t                                inInterfaceIndex,
+                               DNSServiceErrorType     inErrorCode,
+                               const char *                    inName, 
+                               const char *                    inType, 
+                               const char *                    inDomain,       
+                               void *                                  inContext );
+               afx_msg LONG OnServiceAdd( WPARAM inWParam, LPARAM inLParam );
+               afx_msg LONG OnServiceRemove( WPARAM inWParam, LPARAM inLParam );
+               
+               // Resolving
+               
+               OSStatus        StartResolve( ServiceInfo *inService );
+               void            StopResolve( void );
+
+               static void CALLBACK_COMPAT
+                       ResolveCallBack(
+                               DNSServiceRef                   inRef,
+                               DNSServiceFlags                 inFlags,
+                               uint32_t                                inInterfaceIndex,
+                               DNSServiceErrorType             inErrorCode,
+                               const char *                    inFullName,     
+                               const char *                    inHostName, 
+                               uint16_t                                inPort,
+                               uint16_t                                inTXTSize,
+                               const char *                    inTXT,
+                               void *                                  inContext );
+               afx_msg LONG OnResolve( WPARAM inWParam, LPARAM inLParam );             
+                               
+               // Accessors
+       
+       public:
+       
+               ExplorerBar *   GetOwner( void ) const                          { return( mOwner ); }
+               void                    SetOwner( ExplorerBar *inOwner )        { mOwner = inOwner; }
+               
+               DECLARE_MESSAGE_MAP()
+};
+
+#endif // __EXPLORER_BAR_WINDOW__
diff --git a/mDNSWindows/Applications/ExplorerPlugin/ExplorerPlugin.cpp b/mDNSWindows/Applications/ExplorerPlugin/ExplorerPlugin.cpp
new file mode 100644 (file)
index 0000000..9528577
--- /dev/null
@@ -0,0 +1,477 @@
+/*
+ * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+    
+$Log: ExplorerPlugin.cpp,v $
+Revision 1.1  2004/01/30 03:01:56  bradley
+Explorer Plugin to browse for Rendezvous-enabled Web and FTP servers from within Internet Explorer.
+
+*/
+
+#include       "StdAfx.h"
+
+// The following 2 includes have to be in this order and INITGUID must be defined here, before including the file
+// that specifies the GUID(s), and nowhere else. The reason for this is that initguid.h doesn't provide separate 
+// define and declare macros for GUIDs so you have to #define INITGUID in the single file where you want to define 
+// your GUID then in all the other files that just need the GUID declared, INITGUID must not be defined.
+
+#define        INITGUID
+#include       <initguid.h>
+#include       "ExplorerPlugin.h"
+
+#include       <comcat.h>
+#include       <Shlwapi.h>
+
+#include       "CommonServices.h"
+#include       "DebugServices.h"
+
+#include       "ClassFactory.h"
+#include       "Resource.h"
+
+// MFC Debugging
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+#if 0
+#pragma mark == Prototypes ==
+#endif
+
+//===========================================================================================================================
+//     Prototypes
+//===========================================================================================================================
+
+// DLL Exports
+
+extern "C" BOOL WINAPI DllMain( HINSTANCE inInstance, DWORD inReason, LPVOID inReserved );
+
+// MFC Support
+
+DEBUG_LOCAL OSStatus   MFCDLLProcessAttach( HINSTANCE inInstance );
+DEBUG_LOCAL void               MFCDLLProcessDetach( HINSTANCE inInstance );
+DEBUG_LOCAL void               MFCDLLThreadDetach( HINSTANCE inInstance );
+
+// Utilities
+
+DEBUG_LOCAL OSStatus   RegisterServer( HINSTANCE inInstance, CLSID inCLSID, LPCTSTR inName );
+DEBUG_LOCAL OSStatus   RegisterCOMCategory( CLSID inCLSID, CATID inCategoryID, BOOL inRegister );
+
+#if 0
+#pragma mark == Globals ==
+#endif
+
+//===========================================================================================================================
+//     Globals
+//===========================================================================================================================
+
+HINSTANCE              gInstance               = NULL;
+int                            gDLLRefCount    = 0;
+CWinApp                        gApp;
+
+#if 0
+#pragma mark -
+#pragma mark == DLL Exports ==
+#endif
+
+//===========================================================================================================================
+//     DllMain
+//===========================================================================================================================
+
+BOOL WINAPI    DllMain( HINSTANCE inInstance, DWORD inReason, LPVOID inReserved )
+{
+       BOOL                    ok;
+       OSStatus                err;
+       
+       DEBUG_UNUSED( inReserved );
+       
+       ok = TRUE;
+       switch( inReason )
+       {
+               case DLL_PROCESS_ATTACH:
+                       gInstance = inInstance;
+                       debug_initialize( kDebugOutputTypeWindowsEventLog, "RendezvousBar", inInstance );
+                       debug_set_property( kDebugPropertyTagPrintLevel, kDebugLevelTrace );
+                       dlog( kDebugLevelTrace, "\nDllMain: process attach\n" );
+                       
+                       err = MFCDLLProcessAttach( inInstance );
+                       ok = ( err == kNoErr );
+                       require_noerr( err, exit );
+                       break;
+               
+               case DLL_PROCESS_DETACH:
+                       dlog( kDebugLevelTrace, "DllMain: process detach\n" );
+                       MFCDLLProcessDetach( inInstance );
+                       break;
+               
+               case DLL_THREAD_ATTACH:
+                       dlog( kDebugLevelTrace, "DllMain: thread attach\n" );
+                       break;
+               
+               case DLL_THREAD_DETACH:
+                       dlog( kDebugLevelTrace, "DllMain: thread detach\n" );
+                       MFCDLLThreadDetach( inInstance );
+                       break;
+               
+               default:
+                       dlog( kDebugLevelTrace, "DllMain: unknown reason code (%d)\n",inReason );
+                       break;
+       }
+       
+exit:
+       return( ok );
+}
+
+//===========================================================================================================================
+//     DllCanUnloadNow
+//===========================================================================================================================
+
+STDAPI DllCanUnloadNow( void )
+{
+       dlog( kDebugLevelTrace, "DllCanUnloadNow (refCount=%d)\n", gDLLRefCount );
+       
+       return( gDLLRefCount == 0 );
+}
+
+//===========================================================================================================================
+//     DllGetClassObject
+//===========================================================================================================================
+
+STDAPI DllGetClassObject( REFCLSID inCLSID, REFIID inIID, LPVOID *outResult )
+{
+       HRESULT                         err;
+       BOOL                            ok;
+       ClassFactory *          factory;
+       
+       dlog( kDebugLevelTrace, "DllGetClassObject\n" );
+       
+       *outResult = NULL;
+       
+       // Check if the class ID is supported.
+       
+       ok = IsEqualCLSID( inCLSID, CLSID_ExplorerBar );
+       require_action_quiet( ok, exit, err = CLASS_E_CLASSNOTAVAILABLE );
+       
+       // Create the ClassFactory object.
+       
+       factory = NULL;
+       try
+       {
+               factory = new ClassFactory( inCLSID );
+       }
+       catch( ... )
+       {
+               // Do not let exception escape.
+       }
+       require_action( factory, exit, err = E_OUTOFMEMORY );
+       
+       // Query for the specified interface. Release the factory since QueryInterface retains it.
+       
+       err = factory->QueryInterface( inIID, outResult );
+       factory->Release();
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     DllRegisterServer
+//===========================================================================================================================
+
+STDAPI DllRegisterServer( void )
+{
+       HRESULT         err;
+       BOOL            ok;
+       CString         s;
+       
+       dlog( kDebugLevelTrace, "DllRegisterServer\n" );
+       
+       ok = s.LoadString( IDS_NAME );
+       require_action( ok, exit, err = E_UNEXPECTED );
+       
+       err = RegisterServer( gInstance, CLSID_ExplorerBar, s );
+       require_noerr( err, exit );
+       
+       err = RegisterCOMCategory( CLSID_ExplorerBar, CATID_InfoBand, TRUE );
+       require_noerr( err, exit );
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     DllUnregisterServer
+//===========================================================================================================================
+
+STDAPI DllUnregisterServer( void )
+{
+       HRESULT         err;
+       
+       dlog( kDebugLevelTrace, "DllUnregisterServer\n" );
+       
+       err = RegisterCOMCategory( CLSID_ExplorerBar, CATID_InfoBand, FALSE );
+       require_noerr( err, exit );
+       
+exit:
+       return( err );
+}
+
+#if 0
+#pragma mark -
+#pragma mark == MFC Support ==
+#endif
+
+//===========================================================================================================================
+//     MFCDLLProcessAttach
+//===========================================================================================================================
+
+DEBUG_LOCAL OSStatus   MFCDLLProcessAttach( HINSTANCE inInstance )
+{
+       OSStatus                                err;
+       _AFX_THREAD_STATE *             threadState;
+       AFX_MODULE_STATE *              previousModuleState;
+       BOOL                                    ok;
+       CWinApp *                               app;
+       
+       app = NULL;
+       
+       // Simulate what is done in dllmodul.cpp.
+       
+       threadState = AfxGetThreadState();
+       check( threadState );
+       previousModuleState = threadState->m_pPrevModuleState;
+       
+       ok = AfxWinInit( inInstance, NULL, TEXT( "" ), 0 );
+       require_action( ok, exit, err = kUnknownErr );
+       
+       app = AfxGetApp();
+       require_action( ok, exit, err = kNotInitializedErr );
+       
+       ok = app->InitInstance();
+       require_action( ok, exit, err = kUnknownErr );
+       
+       threadState->m_pPrevModuleState = previousModuleState;
+       threadState = NULL;
+       AfxInitLocalData( inInstance );
+       err = kNoErr;
+       
+exit:
+       if( err )
+       {
+               if( app )
+               {
+                       app->ExitInstance();
+               }
+               AfxWinTerm();
+       }
+       if( threadState )
+       {
+               threadState->m_pPrevModuleState = previousModuleState;
+       }
+       return( err );
+}
+
+//===========================================================================================================================
+//     MFCDLLProcessDetach
+//===========================================================================================================================
+
+DEBUG_LOCAL void       MFCDLLProcessDetach( HINSTANCE inInstance )
+{
+       CWinApp *               app;
+
+       // Simulate what is done in dllmodul.cpp.
+       
+       app = AfxGetApp();
+       if( app )
+       {
+               app->ExitInstance();
+       }
+
+#if( DEBUG )
+       if( AfxGetModuleThreadState()->m_nTempMapLock != 0 )
+       {
+               dlog( kDebugLevelWarning, "Warning: Temp map lock count non-zero (%ld).\n", AfxGetModuleThreadState()->m_nTempMapLock );
+       }
+#endif
+       
+       AfxLockTempMaps();
+       AfxUnlockTempMaps( -1 );
+
+       // Terminate the library before destructors are called.
+       
+       AfxWinTerm();
+       AfxTermLocalData( inInstance, TRUE );
+}
+
+//===========================================================================================================================
+//     MFCDLLFinalize
+//===========================================================================================================================
+
+DEBUG_LOCAL void       MFCDLLThreadDetach( HINSTANCE inInstance )
+{
+       // Simulate what is done in dllmodul.cpp.
+       
+#if( DEBUG )
+       if( AfxGetModuleThreadState()->m_nTempMapLock != 0 )
+       {
+               dlog( kDebugLevelWarning, "Warning: Temp map lock count non-zero (%ld).\n", AfxGetModuleThreadState()->m_nTempMapLock );
+       }
+#endif
+       
+       AfxLockTempMaps();
+       AfxUnlockTempMaps( -1 );
+       AfxTermThread( inInstance );
+}
+
+#if 0
+#pragma mark -
+#pragma mark == Utilities ==
+#endif
+
+//===========================================================================================================================
+//     RegisterServer
+//===========================================================================================================================
+
+DEBUG_LOCAL OSStatus   RegisterServer( HINSTANCE inInstance, CLSID inCLSID, LPCTSTR inName )
+{
+       typedef struct  RegistryBuilder         RegistryBuilder;
+       struct  RegistryBuilder
+       {
+               HKEY            rootKey;
+               LPCTSTR         subKey;
+               LPCTSTR         valueName;
+               LPCTSTR         data;
+       };
+       
+       OSStatus                        err;
+       LPWSTR                          clsidWideString;
+       TCHAR                           clsidString[ 64 ];
+       DWORD                           nChars;
+       size_t                          n;
+       size_t                          i;
+       HKEY                            key;
+       TCHAR                           keyName[ MAX_PATH ];
+       TCHAR                           moduleName[ MAX_PATH ] = TEXT( "" );
+       TCHAR                           data[ MAX_PATH ];
+       RegistryBuilder         entries[] = 
+       {
+               { HKEY_CLASSES_ROOT,    TEXT( "CLSID\\%s" ),                                    NULL,                                           inName },
+               { HKEY_CLASSES_ROOT,    TEXT( "CLSID\\%s\\InprocServer32" ),    NULL,                                           moduleName },
+               { HKEY_CLASSES_ROOT,    TEXT( "CLSID\\%s\\InprocServer32" ),    TEXT( "ThreadingModel" ),       TEXT( "Apartment" ) }
+       };
+       DWORD                           size;
+       OSVERSIONINFO           versionInfo;
+       
+       // Convert the CLSID to a string based on the encoding of this code (ANSI or Unicode).
+       
+       err = StringFromIID( inCLSID, &clsidWideString );
+       require_noerr( err, exit );
+       require_action( clsidWideString, exit, err = kNoMemoryErr );
+       
+       #ifdef UNICODE
+               lstrcpyn( clsidString, clsidWideString, sizeof_array( clsidString ) );
+               CoTaskMemFree( clsidWideString );
+       #else
+               nChars = WideCharToMultiByte( CP_ACP, 0, clsidWideString, -1, clsidString, sizeof_array( clsidString ), NULL, NULL );
+               err = translate_errno( nChars > 0, (OSStatus) GetLastError(), kUnknownErr );
+               CoTaskMemFree( clsidWideString );
+               require_noerr( err, exit );
+       #endif
+       
+       // Register the CLSID entries.
+       
+       nChars = GetModuleFileName( inInstance, moduleName, sizeof_array( moduleName ) );
+       err = translate_errno( nChars > 0, (OSStatus) GetLastError(), kUnknownErr );
+       require_noerr( err, exit );
+
+       n = sizeof_array( entries );
+       for( i = 0; i < n; ++i )
+       {
+               wsprintf( keyName, entries[ i ].subKey, clsidString );          
+               err = RegCreateKeyEx( entries[ i ].rootKey, keyName, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &key, NULL );
+               require_noerr( err, exit );
+               
+               size = (DWORD)( ( lstrlen( entries[ i ].data ) + 1 ) * sizeof( TCHAR ) );
+               err = RegSetValueEx( key, entries[ i ].valueName, 0, REG_SZ, (LPBYTE) entries[ i ].data, size );
+               RegCloseKey( key );
+               require_noerr( err, exit );
+       }
+       
+       // If running on NT, register the extension as approved.
+       
+       versionInfo.dwOSVersionInfoSize = sizeof( versionInfo );
+       GetVersionEx( &versionInfo );
+       if( versionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT )
+       {
+               lstrcpyn( keyName, TEXT( "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved" ), sizeof_array( keyName ) );
+               err = RegCreateKeyEx( HKEY_LOCAL_MACHINE, keyName, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &key, NULL );
+               require_noerr( err, exit );
+               
+               lstrcpyn( data, inName, sizeof_array( data ) );
+               size = (DWORD)( ( lstrlen( data ) + 1 ) * sizeof( TCHAR ) );
+               err = RegSetValueEx( key, clsidString, 0, REG_SZ, (LPBYTE) data, size );
+               RegCloseKey( key );
+       }
+       err = kNoErr;
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     RegisterCOMCategory
+//===========================================================================================================================
+
+DEBUG_LOCAL OSStatus   RegisterCOMCategory( CLSID inCLSID, CATID inCategoryID, BOOL inRegister )
+{
+       HRESULT                         err;
+       ICatRegister *          cat;
+
+       err = CoInitialize( NULL );
+       require( SUCCEEDED( err ), exit );
+       
+       err = CoCreateInstance( CLSID_StdComponentCategoriesMgr, NULL, CLSCTX_INPROC_SERVER, IID_ICatRegister, (LPVOID *) &cat );
+       check( SUCCEEDED( err ) );
+       if( SUCCEEDED( err ) )
+       {
+               if( inRegister )
+               {
+                       err = cat->RegisterClassImplCategories( inCLSID, 1, &inCategoryID );
+                       check_noerr( err );
+               }
+               else
+               {
+                       err = cat->UnRegisterClassImplCategories( inCLSID, 1, &inCategoryID );
+                       check_noerr( err );
+               }
+               cat->Release();
+       }
+       CoUninitialize();
+
+exit:
+       return( err );
+}
diff --git a/mDNSWindows/Applications/ExplorerPlugin/ExplorerPlugin.def b/mDNSWindows/Applications/ExplorerPlugin/ExplorerPlugin.def
new file mode 100644 (file)
index 0000000..028856c
--- /dev/null
@@ -0,0 +1,37 @@
+;
+; Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
+;
+; @APPLE_LICENSE_HEADER_START@
+; 
+; This file contains Original Code and/or Modifications of Original Code
+; as defined in and that are subject to the Apple Public Source License
+; Version 2.0 (the 'License'). You may not use this file except in
+; compliance with the License. Please obtain a copy of the License at
+; http://www.opensource.apple.com/apsl/ and read it before using this
+; file.
+; 
+; The Original Code and all software distributed under the License are
+; distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+; EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+; INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+; FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+; Please see the License for the specific language governing rights and
+; limitations under the License.
+; 
+; @APPLE_LICENSE_HEADER_END@
+;
+;      Change History (most recent first):
+;    
+; $Log: ExplorerPlugin.def,v $
+; Revision 1.1  2004/01/30 03:01:56  bradley
+; Explorer Plugin to browse for Rendezvous-enabled Web and FTP servers from within Internet Explorer.
+;
+;
+
+LIBRARY                ExplorerPlugin
+
+EXPORTS
+       DllCanUnloadNow         PRIVATE
+       DllGetClassObject       PRIVATE
+       DllRegisterServer       PRIVATE
+       DllUnregisterServer     PRIVATE
diff --git a/mDNSWindows/Applications/ExplorerPlugin/ExplorerPlugin.h b/mDNSWindows/Applications/ExplorerPlugin/ExplorerPlugin.h
new file mode 100644 (file)
index 0000000..e072af0
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+    
+$Log: ExplorerPlugin.h,v $
+Revision 1.1  2004/01/30 03:01:56  bradley
+Explorer Plugin to browse for Rendezvous-enabled Web and FTP servers from within Internet Explorer.
+
+*/
+
+//===========================================================================================================================
+//     Globals
+//===========================================================================================================================
+
+// {9999A076-A9E2-4c99-8A2B-632FC9429223}
+DEFINE_GUID(CLSID_ExplorerBar, 
+0x9999a076, 0xa9e2, 0x4c99, 0x8a, 0x2b, 0x63, 0x2f, 0xc9, 0x42, 0x92, 0x23);
+
+extern HINSTANCE               gInstance;
+extern int                             gDLLRefCount;
diff --git a/mDNSWindows/Applications/ExplorerPlugin/ExplorerPlugin.rc b/mDNSWindows/Applications/ExplorerPlugin/ExplorerPlugin.rc
new file mode 100644 (file)
index 0000000..f9e79ba
--- /dev/null
@@ -0,0 +1,173 @@
+// 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"
+    "LANGUAGE 9, 1\r\n"
+    "#pragma code_page(1252)\r\n"
+    "#include ""afxres.rc""     // Standard components\r\n"
+    "#endif\r\n"
+    "\0"
+END
+
+#endif    // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 1,0,0,1
+ PRODUCTVERSION 1,0,0,1
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+    BLOCK "StringFileInfo"
+    BEGIN
+        BLOCK "040904B0"
+        BEGIN
+            VALUE "CompanyName", "Apple Computer, Inc."
+            VALUE "FileDescription", "Rendezvous Bar"
+            VALUE "FileVersion", "1.0.0.1"
+            VALUE "InternalName", "ExplorerPlugin.dll"
+            VALUE "LegalCopyright", "Copyright (C) 2003-2004 Apple Computer, Inc."
+            VALUE "OriginalFilename", "ExplorerPlugin.dll"
+            VALUE "ProductName", "Rendezvous Bar"
+            VALUE "ProductVersion", "1.0.0.1"
+        END
+    END
+    BLOCK "VarFileInfo"
+    BEGIN
+        VALUE "Translation", 0x409, 1200
+    END
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_LOGIN DIALOGEX 0, 0, 180, 89
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | 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
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO 
+BEGIN
+    IDD_LOGIN, DIALOG
+    BEGIN
+        BOTTOMMARGIN, 62
+    END
+END
+#endif    // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// String Table
+//
+
+STRINGTABLE 
+BEGIN
+    IDS_NAME                "Rendezvous"
+    IDS_WEB_SITES           "Web Sites"
+    IDS_FTP_SITES           "FTP Sites"
+    IDS_PRINTERS            "Printers"
+    IDS_RENDEZVOUS_NOT_AVAILABLE "Rendezvous Not Available"
+END
+
+#endif    // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+#define _AFX_NO_SPLITTER_RESOURCES
+#define _AFX_NO_OLE_RESOURCES
+#define _AFX_NO_TRACKER_RESOURCES
+#define _AFX_NO_PROPERTY_RESOURCES
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+LANGUAGE 9, 1
+#pragma code_page(1252)
+#include "afxres.rc"     // Standard components
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+#endif    // not APSTUDIO_INVOKED
+
diff --git a/mDNSWindows/Applications/ExplorerPlugin/ExplorerPlugin.sln b/mDNSWindows/Applications/ExplorerPlugin/ExplorerPlugin.sln
new file mode 100644 (file)
index 0000000..24abed3
--- /dev/null
@@ -0,0 +1,21 @@
+Microsoft Visual Studio Solution File, Format Version 7.00
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ExplorerPlugin", "ExplorerPlugin.vcproj", "{BB8AC1B5-6587-4163-BDC6-788B157705CA}"
+EndProject
+Global
+       GlobalSection(SolutionConfiguration) = preSolution
+               ConfigName.0 = Debug
+               ConfigName.1 = Release
+       EndGlobalSection
+       GlobalSection(ProjectDependencies) = postSolution
+       EndGlobalSection
+       GlobalSection(ProjectConfiguration) = postSolution
+               {BB8AC1B5-6587-4163-BDC6-788B157705CA}.Debug.ActiveCfg = Debug|Win32
+               {BB8AC1B5-6587-4163-BDC6-788B157705CA}.Debug.Build.0 = Debug|Win32
+               {BB8AC1B5-6587-4163-BDC6-788B157705CA}.Release.ActiveCfg = Release|Win32
+               {BB8AC1B5-6587-4163-BDC6-788B157705CA}.Release.Build.0 = Release|Win32
+       EndGlobalSection
+       GlobalSection(ExtensibilityGlobals) = postSolution
+       EndGlobalSection
+       GlobalSection(ExtensibilityAddIns) = postSolution
+       EndGlobalSection
+EndGlobal
diff --git a/mDNSWindows/Applications/ExplorerPlugin/ExplorerPlugin.vcproj b/mDNSWindows/Applications/ExplorerPlugin/ExplorerPlugin.vcproj
new file mode 100644 (file)
index 0000000..ec8b589
--- /dev/null
@@ -0,0 +1,242 @@
+<?xml version="1.0" encoding = "Windows-1252"?>
+<VisualStudioProject
+       ProjectType="Visual C++"
+       Version="7.00"
+       Name="ExplorerPlugin"
+       ProjectGUID="{BB8AC1B5-6587-4163-BDC6-788B157705CA}"
+       SccProjectName=""
+       SccLocalPath="">
+       <Platforms>
+               <Platform
+                       Name="Win32"/>
+       </Platforms>
+       <Configurations>
+               <Configuration
+                       Name="Debug|Win32"
+                       OutputDirectory=".\Debug"
+                       IntermediateDirectory=".\Debug"
+                       ConfigurationType="2"
+                       UseOfMFC="1"
+                       ATLMinimizesCRunTimeLibraryUsage="FALSE"
+                       CharacterSet="1">
+                       <Tool
+                               Name="VCCLCompilerTool"
+                               Optimization="0"
+                               AdditionalIncludeDirectories="..\..\"
+                               PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;DEBUG=1;DNS_SD_DIRECT_ENABLED=0"
+                               StringPooling="TRUE"
+                               BasicRuntimeChecks="3"
+                               RuntimeLibrary="1"
+                               ForceConformanceInForLoopScope="TRUE"
+                               UsePrecompiledHeader="2"
+                               PrecompiledHeaderFile="$(OutDir)/$(ProjectName).pch"
+                               AssemblerListingLocation=".\Debug/"
+                               ObjectFile=".\Debug/"
+                               ProgramDataBaseFileName=".\Debug/"
+                               BrowseInformation="1"
+                               WarningLevel="4"
+                               WarnAsError="TRUE"
+                               SuppressStartupBanner="TRUE"
+                               Detect64BitPortabilityProblems="TRUE"
+                               DebugInformationFormat="3"
+                               CompileAs="0"/>
+                       <Tool
+                               Name="VCCustomBuildTool"
+                               Description="Registering"
+                               CommandLine="regsvr32.exe /s /c $(OutDir)/$(ProjectName).dll
+"
+                               Outputs="$(OUTDIR)\Register.out"/>
+                       <Tool
+                               Name="VCLinkerTool"
+                               AdditionalOptions="/MACHINE:I386 /IGNORE:4089 "
+                               AdditionalDependencies="uafxcwd.lib ws2_32.lib"
+                               LinkIncremental="1"
+                               SuppressStartupBanner="TRUE"
+                               IgnoreDefaultLibraryNames="uafxcwd.lib"
+                               ModuleDefinitionFile="./$(ProjectName).def"
+                               GenerateDebugInformation="TRUE"
+                               ProgramDatabaseFile="$(OutDir)/$(ProjectName).pdb"
+                               SubSystem="2"
+                               ImportLibrary="$(OutDir)/$(ProjectName).lib"/>
+                       <Tool
+                               Name="VCMIDLTool"
+                               PreprocessorDefinitions="_DEBUG"
+                               MkTypLibCompatible="TRUE"
+                               SuppressStartupBanner="TRUE"
+                               TargetEnvironment="1"
+                               TypeLibraryName="$(OutDir)/$(ProjectName).tlb"/>
+                       <Tool
+                               Name="VCPostBuildEventTool"/>
+                       <Tool
+                               Name="VCPreBuildEventTool"/>
+                       <Tool
+                               Name="VCPreLinkEventTool"/>
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                               PreprocessorDefinitions="_DEBUG"
+                               Culture="1033"/>
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"/>
+                       <Tool
+                               Name="VCWebDeploymentTool"/>
+               </Configuration>
+               <Configuration
+                       Name="Release|Win32"
+                       OutputDirectory=".\Release"
+                       IntermediateDirectory=".\Release"
+                       ConfigurationType="2"
+                       UseOfMFC="1"
+                       ATLMinimizesCRunTimeLibraryUsage="FALSE"
+                       CharacterSet="1">
+                       <Tool
+                               Name="VCCLCompilerTool"
+                               Optimization="2"
+                               GlobalOptimizations="TRUE"
+                               InlineFunctionExpansion="2"
+                               FavorSizeOrSpeed="2"
+                               OmitFramePointers="TRUE"
+                               AdditionalIncludeDirectories="..\..\"
+                               PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;DNS_SD_DIRECT_ENABLED=0"
+                               StringPooling="TRUE"
+                               RuntimeLibrary="0"
+                               BufferSecurityCheck="FALSE"
+                               EnableFunctionLevelLinking="FALSE"
+                               ForceConformanceInForLoopScope="TRUE"
+                               UsePrecompiledHeader="2"
+                               PrecompiledHeaderFile="$(OutDir)/$(ProjectName).pch"
+                               AssemblerListingLocation=".\Release/"
+                               ObjectFile=".\Release/"
+                               ProgramDataBaseFileName=".\Release/"
+                               BrowseInformation="1"
+                               WarningLevel="4"
+                               WarnAsError="TRUE"
+                               SuppressStartupBanner="TRUE"
+                               Detect64BitPortabilityProblems="TRUE"
+                               CompileAs="0"/>
+                       <Tool
+                               Name="VCCustomBuildTool"
+                               Description="Registering"
+                               CommandLine="regsvr32.exe /s /c $(OutDir)/$(ProjectName).dll
+"
+                               Outputs="$(OUTDIR)\Register.out"/>
+                       <Tool
+                               Name="VCLinkerTool"
+                               AdditionalOptions="/MACHINE:I386 /IGNORE:4089 "
+                               AdditionalDependencies="uafxcw.lib ws2_32.lib"
+                               OutputFile="$(OutDir)/$(ProjectName).dll"
+                               LinkIncremental="1"
+                               SuppressStartupBanner="TRUE"
+                               IgnoreDefaultLibraryNames="uafxcw.lib"
+                               ModuleDefinitionFile="./$(ProjectName).def"
+                               ProgramDatabaseFile="$(OutDir)/$(ProjectName).pdb"
+                               SubSystem="2"
+                               OptimizeReferences="2"
+                               EnableCOMDATFolding="2"
+                               ImportLibrary="$(OutDir)/$(ProjectName).lib"/>
+                       <Tool
+                               Name="VCMIDLTool"
+                               PreprocessorDefinitions="NDEBUG"
+                               MkTypLibCompatible="TRUE"
+                               SuppressStartupBanner="TRUE"
+                               TargetEnvironment="1"
+                               TypeLibraryName="$(OutDir)/$(ProjectName).tlb"/>
+                       <Tool
+                               Name="VCPostBuildEventTool"/>
+                       <Tool
+                               Name="VCPreBuildEventTool"/>
+                       <Tool
+                               Name="VCPreLinkEventTool"/>
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                               PreprocessorDefinitions="NDEBUG"
+                               Culture="1033"/>
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"/>
+                       <Tool
+                               Name="VCWebDeploymentTool"/>
+               </Configuration>
+       </Configurations>
+       <Files>
+               <Filter
+                       Name="Support"
+                       Filter="">
+                       <File
+                               RelativePath="..\..\CommonServices.h">
+                       </File>
+                       <File
+                               RelativePath="..\..\DNSSD.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\DNSSD.h">
+                       </File>
+                       <File
+                               RelativePath="..\..\DebugServices.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\DebugServices.h">
+                       </File>
+                       <File
+                               RelativePath="..\..\RMxClient.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\RMxClient.h">
+                       </File>
+                       <File
+                               RelativePath="..\..\RMxCommon.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\RMxCommon.h">
+                       </File>
+               </Filter>
+               <File
+                       RelativePath="ClassFactory.cpp">
+               </File>
+               <File
+                       RelativePath="ClassFactory.h">
+               </File>
+               <File
+                       RelativePath="ExplorerBar.cpp">
+               </File>
+               <File
+                       RelativePath="ExplorerBar.h">
+               </File>
+               <File
+                       RelativePath="ExplorerBarWindow.cpp">
+               </File>
+               <File
+                       RelativePath="ExplorerBarWindow.h">
+               </File>
+               <File
+                       RelativePath="ExplorerPlugin.cpp">
+               </File>
+               <File
+                       RelativePath="ExplorerPlugin.def">
+               </File>
+               <File
+                       RelativePath="ExplorerPlugin.h">
+               </File>
+               <File
+                       RelativePath="ExplorerPlugin.rc">
+               </File>
+               <File
+                       RelativePath="LoginDialog.cpp">
+               </File>
+               <File
+                       RelativePath="LoginDialog.h">
+               </File>
+               <File
+                       RelativePath="Resource.h">
+               </File>
+               <File
+                       RelativePath="StdAfx.cpp">
+               </File>
+               <File
+                       RelativePath="StdAfx.h">
+               </File>
+               <File
+                       RelativePath="Web.ico">
+               </File>
+       </Files>
+       <Globals>
+       </Globals>
+</VisualStudioProject>
diff --git a/mDNSWindows/Applications/ExplorerPlugin/LoginDialog.cpp b/mDNSWindows/Applications/ExplorerPlugin/LoginDialog.cpp
new file mode 100644 (file)
index 0000000..1947947
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+    
+$Log: LoginDialog.cpp,v $
+Revision 1.1  2004/01/30 03:01:56  bradley
+Explorer Plugin to browse for Rendezvous-enabled Web and FTP servers from within Internet Explorer.
+
+*/
+
+#include       <assert.h>
+#include       <stdlib.h>
+
+#include       "stdafx.h"
+
+#include       "LoginDialog.h"
+
+// MFC Debugging
+
+#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/Applications/ExplorerPlugin/LoginDialog.h b/mDNSWindows/Applications/ExplorerPlugin/LoginDialog.h
new file mode 100644 (file)
index 0000000..11d9d1c
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+    
+$Log: LoginDialog.h,v $
+Revision 1.1  2004/01/30 03:01:56  bradley
+Explorer Plugin to browse for Rendezvous-enabled Web and FTP servers from within Internet Explorer.
+
+*/
+
+#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/Applications/ExplorerPlugin/ReadMe.txt b/mDNSWindows/Applications/ExplorerPlugin/ReadMe.txt
new file mode 100644 (file)
index 0000000..ed73c22
--- /dev/null
@@ -0,0 +1,9 @@
+The Rendezvous Explorer Plugin is a vertical Explorer bar. It lets you browse for Rendezvous-enabled services directly within Internet Explorer. 
+
+This DLL needs to be registered to work. The Visual Studio project automatically registers the DLL after each successful build. If you need to manually register the DLL for some reason, you can execute the following line from the DOS command line prompt ("<path>" is the actual parent path of the DLL):
+
+regsvr32.exe /s /c <path>\ExplorerPlugin.dll
+
+For more information, see the Band Objects topic in the Microsoft Platform SDK documentation and check the following URL:
+
+<http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_adv/bands.asp>
diff --git a/mDNSWindows/Applications/ExplorerPlugin/Resource.h b/mDNSWindows/Applications/ExplorerPlugin/Resource.h
new file mode 100644 (file)
index 0000000..744ae44
--- /dev/null
@@ -0,0 +1,23 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by ExplorerPlugin.rc
+//
+#define IDS_NAME                        106
+#define IDS_WEB_SITES                   107
+#define IDS_FTP_SITES                   108
+#define IDS_PRINTERS                    109
+#define IDS_RENDEZVOUS_NOT_AVAILABLE    110
+#define IDD_LOGIN                       145
+#define IDC_LOGIN_USERNAME_TEXT         1182
+#define IDC_LOGIN_PASSWORD_TEXT         1183
+
+// Next default values for new objects
+// 
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE        115
+#define _APS_NEXT_COMMAND_VALUE         40001
+#define _APS_NEXT_CONTROL_VALUE         1001
+#define _APS_NEXT_SYMED_VALUE           101
+#endif
+#endif
diff --git a/mDNSWindows/Applications/ExplorerPlugin/StdAfx.cpp b/mDNSWindows/Applications/ExplorerPlugin/StdAfx.cpp
new file mode 100644 (file)
index 0000000..673073f
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+    
+$Log: StdAfx.cpp,v $
+Revision 1.1  2004/01/30 03:01:56  bradley
+Explorer Plugin to browse for Rendezvous-enabled Web and FTP servers from within Internet Explorer.
+
+*/
+
+#include       "StdAfx.h"
diff --git a/mDNSWindows/Applications/ExplorerPlugin/StdAfx.h b/mDNSWindows/Applications/ExplorerPlugin/StdAfx.h
new file mode 100644 (file)
index 0000000..45020c1
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+    
+$Log: StdAfx.h,v $
+Revision 1.1  2004/01/30 03:01:56  bradley
+Explorer Plugin to browse for Rendezvous-enabled Web and FTP servers from within Internet Explorer.
+
+*/
+
+#ifndef __STDAFX__
+#define __STDAFX__
+
+#pragma once
+
+#ifndef VC_EXTRALEAN
+#define VC_EXTRALEAN           // Exclude rarely-used stuff from Windows headers
+#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
+
+#include <winsock2.h>
+#include <afxsock.h>           // MFC socket extensions
+
+#endif // __STDAFX__
diff --git a/mDNSWindows/Applications/Java/makefile b/mDNSWindows/Applications/Java/makefile
new file mode 100755 (executable)
index 0000000..3ed3f9f
--- /dev/null
@@ -0,0 +1,134 @@
+# Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+#
+# $Log: makefile,v $
+# Revision 1.2  2004/05/01 00:31:41  rpantos
+# Change line endings for CVS.
+#
+# Revision 1.1  2004/04/30 16:32:34  rpantos
+# First checked in.
+#
+# This Makefile builds a .jar file and accompanying JNI support library
+# containing the DNSSD implementation for Java and support classes.
+#
+# 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 d:\javasdk. You can override this on the
+# command line (e.g. 'nmake JDK=\j2dk1.4.2_03').
+
+############################################################################
+
+COREDIR = ..\..\..\mDNSCore
+SHAREDDIR = ..\..\..\mDNSShared
+
+JDK = d:\javasdk
+
+CC = cl
+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=1 -DUSE_WIN_API=1 -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
+LIBDIR = ..\DLL\Debug
+!else
+CFLAGS_DEBUG = -Os -DMDNS_DEBUGMSGS=0 
+OBJDIR = objects\prod
+BUILDDIR = build\prod
+LIBDIR = ..\DLL\Release
+!endif
+
+CFLAGS = $(CFLAGS_COMMON) $(CFLAGS_DEBUG)
+JAVACFLAGS = $(CFLAGS) $(JAVACFLAGS_OS)
+
+#############################################################################
+
+all: setup Java
+
+# '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)
+
+# 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
+       @echo "Java wrappers done"
+
+JAVASRC        = $(SHAREDDIR)\Java
+JARCONTENTS =  $(OBJDIR)\com\apple\dnssd\DNSSDService.class \
+                               $(OBJDIR)\com\apple\dnssd\DNSRecord.class \
+                               $(OBJDIR)\com\apple\dnssd\DNSSDException.class \
+                               $(OBJDIR)\com\apple\dnssd\TXTRecord.class \
+                               $(OBJDIR)\com\apple\dnssd\DNSSDRegistration.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\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
+       $(CC) -Fe$@ $(JAVASRC)\JNISupport.c $(CFLAGS) -I$(OBJDIR) \
+       $(LIBDIR)\DNSSD.lib $(JDK)\lib\jvm.lib
+
+.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 
+
diff --git a/mDNSWindows/Applications/NSPTool/Prefix.h b/mDNSWindows/Applications/NSPTool/Prefix.h
new file mode 100644 (file)
index 0000000..c7f01c5
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+
+$Log: Prefix.h,v $
+Revision 1.1  2004/01/30 03:02:58  bradley
+NameSpace Provider Tool for installing, removing, list, etc. NameSpace Providers.
+                                       
+*/
+
+#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/Applications/NSPTool/Tool.c b/mDNSWindows/Applications/NSPTool/Tool.c
new file mode 100644 (file)
index 0000000..bee72f8
--- /dev/null
@@ -0,0 +1,580 @@
+/*
+ * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+       
+$Log: Tool.c,v $
+Revision 1.1  2004/01/30 03:02:58  bradley
+NameSpace Provider Tool for installing, removing, list, etc. NameSpace Providers.
+
+*/
+
+#include       <stdio.h>
+#include       <stdlib.h>
+
+#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, char *outString );
+DEBUG_LOCAL OSStatus   StringToGUID( const char *inCharString, GUID *outGUID );
+
+//===========================================================================================================================
+//     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, "  -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 ], "-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 );
+       
+       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 );
+       
+       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 );
+       
+       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, 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 = strlen( array[ i ].lpszIdentifier );
+       require_action( size < sizeof_array( name ), exit, err = kSizeErr );
+       CharToWCharString( array[ i ].lpszIdentifier, name );
+       
+       size = 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, char *outString )
+{
+       check( inGUID );
+       check( outString );
+       
+       sprintf( outString, "%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/Applications/NSPTool/Tool.mcp b/mDNSWindows/Applications/NSPTool/Tool.mcp
new file mode 100644 (file)
index 0000000..a6dcb6f
Binary files /dev/null and b/mDNSWindows/Applications/NSPTool/Tool.mcp differ
diff --git a/mDNSWindows/Applications/SystemService/EventLogMessages.bin b/mDNSWindows/Applications/SystemService/EventLogMessages.bin
new file mode 100644 (file)
index 0000000..e74c67e
Binary files /dev/null and b/mDNSWindows/Applications/SystemService/EventLogMessages.bin differ
diff --git a/mDNSWindows/Applications/SystemService/Prefix.h b/mDNSWindows/Applications/SystemService/Prefix.h
new file mode 100644 (file)
index 0000000..844b96e
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+    
+$Log: Prefix.h,v $
+Revision 1.2  2004/04/30 02:40:23  bradley
+Define DNS_SD_CLIENT_ENABLED=0 so DNSSD.c can be included without linking the client IPC code.
+
+Revision 1.1  2004/01/30 02:58:39  bradley
+mDNSResponder Windows Service. Provides global Rendezvous support with an IPC interface.
+
+*/
+
+#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/Applications/SystemService/Resource.h b/mDNSWindows/Applications/SystemService/Resource.h
new file mode 100644 (file)
index 0000000..50064bd
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+    
+$Log: Resource.h,v $
+Revision 1.1  2004/01/30 02:58:39  bradley
+mDNSResponder Windows Service. Provides global Rendezvous support with an IPC interface.
+
+*/
+
+#define IDS_SERVICE_DESCRIPTION                101
diff --git a/mDNSWindows/Applications/SystemService/Service.c b/mDNSWindows/Applications/SystemService/Service.c
new file mode 100644 (file)
index 0000000..d65fa58
--- /dev/null
@@ -0,0 +1,829 @@
+/*
+ * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+    
+$Log: Service.c,v $
+Revision 1.1  2004/01/30 02:58:39  bradley
+mDNSResponder Windows Service. Provides global Rendezvous support with an IPC interface.
+
+*/
+
+#include       <stdio.h>
+#include       <stdlib.h>
+
+#define        _WIN32_WINNT            0x0400
+
+#include       "CommonServices.h"
+#include       "DebugServices.h"
+
+#include       "DNSSDDirect.h"
+#include       "RMxServer.h"
+
+#include       "Resource.h"
+
+#include       "mDNSClientAPI.h"
+
+#if 0
+#pragma mark == Constants ==
+#endif
+
+//===========================================================================================================================
+//     Constants
+//===========================================================================================================================
+
+#define        DEBUG_NAME                                      "[Server] "
+#define        kServiceName                            "Rendezvous"
+#define        kServiceDependencies            "Tcpip\0winmgmt\0\0"
+
+#if 0
+#pragma mark == Prototypes ==
+#endif
+
+//===========================================================================================================================
+//     Prototypes
+//===========================================================================================================================
+
+int                            main( int argc, char *argv[] );
+static void                    Usage( void );
+static BOOL WINAPI     ConsoleControlHandler( DWORD inControlEvent );
+static OSStatus                InstallService( const char *inName, const char *inDisplayName, const char *inDescription, const char *inPath );
+static OSStatus                RemoveService( const char *inName );
+static OSStatus                SetServiceDescription( SC_HANDLE inSCM, const char *inServiceName, const char *inDescription );
+static void                    ReportStatus( int inType, const char *inFormat, ... );
+static OSStatus                RunDirect( int argc, char *argv[] );
+
+static void WINAPI     ServiceMain( DWORD argc, LPSTR argv[] );
+static OSStatus                ServiceSetupEventLogging( void );
+static void WINAPI     ServiceControlHandler( DWORD inControl );
+
+static OSStatus                ServiceRun( int argc, char *argv[] );
+static void                    ServiceStop( void );
+
+static OSStatus                ServiceSpecificInitialize( int argc, char *argv[] );
+static OSStatus                ServiceSpecificRun( int argc, char *argv[] );
+static OSStatus                ServiceSpecificStop( void );
+static void                    ServiceSpecificFinalize( int argc, char *argv[] );
+
+#include       "mDNSClientAPI.h"
+
+#if 0
+#pragma mark == Globals ==
+#endif
+
+//===========================================================================================================================
+//     Globals
+//===========================================================================================================================
+
+DEBUG_LOCAL BOOL                                               gServiceQuietMode               = FALSE;
+DEBUG_LOCAL SERVICE_TABLE_ENTRY                        gServiceDispatchTable[] = 
+{
+       { kServiceName, ServiceMain }, 
+       { NULL,                 NULL }
+};
+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.
+
+#if 0
+#pragma mark -
+#endif
+
+//===========================================================================================================================
+//     main
+//===========================================================================================================================
+
+int    main( int argc, char *argv[] )
+{
+       OSStatus                err;
+       BOOL                    ok;
+       BOOL                    start;
+       int                             i;
+       
+       debug_initialize( kDebugOutputTypeMetaConsole );
+       debug_set_property( kDebugPropertyTagPrintLevel, kDebugLevelVerbose );
+       
+       // 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 );
+       
+       // 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 ], "-install" ) == 0 )                      // Install
+               {
+                       char            desc[ 256 ];
+                       
+                       desc[ 0 ] = 0;
+                       LoadStringA( 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 ], "-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 ], "-start" ) == 0 )           // Start
+               {
+                       start = TRUE;
+               }
+               else if( strcmp( argv[ i ], "-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 ], "-q" ) == 0 )                       // Quiet Mode (toggle)
+               {
+                       gServiceQuietMode = !gServiceQuietMode;
+               }
+               else if( strcmp( argv[ i ], "-remote" ) == 0 )          // Allow Remote Connections
+               {
+                       gServiceAllowRemote = true;
+               }
+               else if( strcmp( argv[ i ], "-cache" ) == 0 )           // Number of mDNS cache entries
+               {
+                       if( i <= argc )
+                       {
+                               ReportStatus( EVENTLOG_ERROR_TYPE, "-cache used, but number of cache entries not specified\n" );
+                               err = kParamErr;
+                               goto exit;
+                       }
+                       gServiceCacheEntryCount = atoi( argv[ ++i ] );
+               }
+               else if( ( strcmp( argv[ i ], "-help" ) == 0 ) ||       // Help
+                                ( strcmp( argv[ i ], "-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 );
+       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( const char *inName, const char *inDisplayName, const char *inDescription, const char *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, sizeof( fullPath ), 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, inPath, NULL, NULL, kServiceDependencies, 
+                                                        NULL, NULL );
+       err = translate_errno( service, (OSStatus) GetLastError(), kDuplicateErr );
+       require_noerr( err, exit );
+       
+       if( inDescription )
+       {
+               err = SetServiceDescription( 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 \"%s\"/\"%s\" at \"%s\"\n", inName, inDisplayName, inPath );
+       err = kNoErr;
+       
+exit:
+       if( service )
+       {
+               CloseServiceHandle( service );
+       }
+       if( scm )
+       {
+               CloseServiceHandle( scm );
+       }
+       return( err );
+}
+
+//===========================================================================================================================
+//     RemoveService
+//===========================================================================================================================
+
+static OSStatus        RemoveService( const char *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 \"%s\"\n", inName );
+       err = ERROR_SUCCESS;
+       
+exit:
+       if( service )
+       {
+               CloseServiceHandle( service );
+       }
+       if( scm )
+       {
+               CloseServiceHandle( scm );
+       }
+       return( err );
+}
+
+//===========================================================================================================================
+//     SetServiceDescription
+//===========================================================================================================================
+
+static OSStatus        SetServiceDescription( SC_HANDLE inSCM, const char *inServiceName, const char *inDescription )
+{
+       OSStatus                                err;
+       SC_LOCK                                 lock;
+       SC_HANDLE                               service;
+       SERVICE_DESCRIPTION             description;
+       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 );
+       err = translate_errno( service, (OSStatus) GetLastError(), kNotFoundErr );
+       require_noerr( err, exit );
+       
+       // Change the description.
+       
+       description.lpDescription = (char *) inDescription;
+       ok = ChangeServiceConfig2( service, SERVICE_CONFIG_DESCRIPTION, &description );
+       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 ];
+                       
+                       vsprintf( s, inFormat, args );
+                       array[ 0 ] = s;
+                       ok = ReportEvent( gServiceEventSource, (WORD) inType, 0, 0x20000001L, 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
+//===========================================================================================================================
+
+static OSStatus        RunDirect( int argc, char *argv[] )
+{
+       OSStatus                err;
+       BOOL                    initialized;
+       
+       initialized = FALSE;
+       
+       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_SUCCESS, "Running \"%s\" service directly\n", kServiceName );
+       
+       err = ServiceSpecificRun( argc, argv );
+       require_noerr( err, exit );
+       
+       // Clean up.
+       
+exit:
+       if( initialized )
+       {
+               ServiceSpecificFinalize( argc, argv );
+       }
+       return( err );
+}
+
+#if 0
+#pragma mark -
+#endif
+
+//===========================================================================================================================
+//     ServiceMain
+//===========================================================================================================================
+
+static void WINAPI ServiceMain( DWORD argc, LPSTR argv[] )
+{
+       OSStatus                err;
+       BOOL                    ok;
+       char                    desc[ 256 ];
+       
+       err = ServiceSetupEventLogging();
+       require_noerr( err, exit );
+       
+       // 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;
+       gServiceStatus.dwWin32ExitCode                          = NO_ERROR;
+       gServiceStatus.dwServiceSpecificExitCode        = NO_ERROR;
+       gServiceStatus.dwCheckPoint                             = 0;
+       gServiceStatus.dwWaitHint                                       = 0;
+       
+       gServiceStatusHandle = RegisterServiceCtrlHandler( argv[ 0 ], ServiceControlHandler );
+       err = translate_errno( gServiceStatusHandle, (OSStatus) GetLastError(), kInUseErr );
+       require_noerr( err, exit );
+       
+       // Setup the description. This should be done by the installer, but it doesn't support that yet.
+                       
+       desc[ 0 ] = '\0';
+       LoadStringA( GetModuleHandle( NULL ), IDS_SERVICE_DESCRIPTION, desc, sizeof( desc ) );
+       err = SetServiceDescription( NULL, kServiceName, desc );
+       check_noerr( err );
+       
+       // 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;
+       }
+}
+
+//===========================================================================================================================
+//     ServiceSetupEventLogging
+//===========================================================================================================================
+
+static OSStatus        ServiceSetupEventLogging( void )
+{
+       OSStatus                        err;
+       HKEY                            key;
+       const char *            s;
+       DWORD                           typesSupported;
+       char                            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 = "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 );
+       err = RegSetValueEx( key, "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, "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 void WINAPI     ServiceControlHandler( DWORD inControl )
+{
+       BOOL            setStatus;
+       BOOL            ok;
+       
+       setStatus = TRUE;
+       switch( inControl )
+       {
+               case SERVICE_CONTROL_STOP:
+                       dlog( kDebugLevelNotice, DEBUG_NAME "ServiceControlHandler: SERVICE_CONTROL_STOP\n" );
+                       
+                       ServiceStop();
+                       setStatus = FALSE;
+                       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 );
+       }
+}
+
+//===========================================================================================================================
+//     ServiceRun
+//===========================================================================================================================
+
+static OSStatus        ServiceRun( int argc, char *argv[] )
+{
+       OSStatus                err;
+       BOOL                    initialized;
+       BOOL                    ok;
+       
+       DEBUG_UNUSED( argc );
+       DEBUG_UNUSED( argv );
+       
+       initialized = FALSE;
+       
+       // Initialize the service-specific stuff and mark the service as running.
+       
+       err = ServiceSpecificInitialize( argc, argv );
+       require_noerr( err, exit );
+       initialized = TRUE;
+       
+       gServiceStatus.dwCurrentState = SERVICE_RUNNING;
+       ok = SetServiceStatus( gServiceStatusHandle, &gServiceStatus );
+       check_translated_errno( ok, GetLastError(), kParamErr );
+       
+       // Run the service-specific stuff. This does not return until the service quits or is stopped.
+       
+       ReportStatus( EVENTLOG_INFORMATION_TYPE, "mDNSResponder started\n" );
+       err = ServiceSpecificRun( argc, argv );
+       ReportStatus( EVENTLOG_INFORMATION_TYPE, "mDNSResponder stopped (%d)\n", err );
+       require_noerr( err, exit );
+       
+       // Service stopped. Clean up and we're done.
+       
+exit:
+       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, char *argv[] )
+{
+       OSStatus                                                err;
+       DNSServiceInitializeFlags               initFlags;
+       RMxServerFlags                                  flags;
+       
+       DEBUG_UNUSED( argc );
+       DEBUG_UNUSED( argv );
+       
+       initFlags = kDNSServiceInitializeFlagsAdvertise | kDNSServiceInitializeFlagsNoServerCheck;
+       err = DNSServiceInitialize_direct( initFlags, gServiceCacheEntryCount );
+       require_noerr( err, exit );
+       
+       flags = 0;
+       if( gServiceAllowRemote )
+       {
+               flags |= kRMxServerFlagsAllowRemote;
+       }
+       err = RMxServerInitialize( flags );
+       require_noerr( err, exit );
+
+exit:
+       if( err != kNoErr )
+       {
+               ServiceSpecificFinalize( argc, argv );
+       }
+       return( err );
+}
+
+//===========================================================================================================================
+//     ServiceSpecificRun
+//===========================================================================================================================
+
+static OSStatus        ServiceSpecificRun( int argc, char *argv[] )
+{
+       OSStatus                err;
+       
+       DEBUG_UNUSED( argc );
+       DEBUG_UNUSED( argv );
+
+       err = RMxServerRun();
+       require_noerr( err, exit );
+
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     ServiceSpecificStop
+//===========================================================================================================================
+
+static OSStatus        ServiceSpecificStop( void )
+{
+       OSStatus                err;
+
+       err = RMxServerStop( kRMxServerStopFlagsNoWait );
+       require_noerr( err, exit );
+
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     ServiceSpecificFinalize
+//===========================================================================================================================
+
+static void    ServiceSpecificFinalize( int argc, char *argv[] )
+{
+       DEBUG_UNUSED( argc );
+       DEBUG_UNUSED( argv );
+       
+       RMxServerFinalize();
+       DNSServiceFinalize_direct();
+}
diff --git a/mDNSWindows/Applications/SystemService/Service.mcp b/mDNSWindows/Applications/SystemService/Service.mcp
new file mode 100644 (file)
index 0000000..0347957
Binary files /dev/null and b/mDNSWindows/Applications/SystemService/Service.mcp differ
diff --git a/mDNSWindows/Applications/SystemService/Service.rc b/mDNSWindows/Applications/SystemService/Service.rc
new file mode 100644 (file)
index 0000000..833a410
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+    
+$Log: Service.rc,v $
+Revision 1.1  2004/01/30 02:58:39  bradley
+mDNSResponder Windows Service. Provides global Rendezvous support with an IPC interface.
+
+*/
+
+#ifdef RC_INVOKED
+       #ifndef _INC_WINDOWS
+       #define _INC_WINDOWS
+               #include        "winres.h"
+       #endif
+#endif
+
+#include       "Resource.h"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Messages
+//
+
+LANGUAGE 0x9,0x1
+1 11 EventLogMessages.bin
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// 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", "mDNSResponder"
+            VALUE "FileVersion", "1, 0, 0, 1"
+            VALUE "InternalName", "mDNSResponder"
+            VALUE "LegalCopyright", "Copyright (C) 2003-2004 Apple Computer, Inc."
+            VALUE "OriginalFilename", "mDNSResponder.exe"
+            VALUE "ProductName", "mDNSResponder"
+            VALUE "ProductVersion", "1, 0, 0, 1"
+        END
+    END
+    BLOCK "VarFileInfo"
+    BEGIN
+        VALUE "Translation", 0x409, 1200
+    END
+END
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// String Table
+//
+
+STRINGTABLE 
+BEGIN
+    IDS_SERVICE_DESCRIPTION            "Rendezvous 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
diff --git a/mDNSWindows/Applications/SystemService/Service2002.sln b/mDNSWindows/Applications/SystemService/Service2002.sln
new file mode 100644 (file)
index 0000000..bbebcf4
--- /dev/null
@@ -0,0 +1,21 @@
+Microsoft Visual Studio Solution File, Format Version 7.00
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mDNSResponder", "Service2002.vcproj", "{F66EFE7E-50A6-44D4-87C7-742B303BA852}"
+EndProject
+Global
+       GlobalSection(SolutionConfiguration) = preSolution
+               ConfigName.0 = Debug
+               ConfigName.1 = Release
+       EndGlobalSection
+       GlobalSection(ProjectDependencies) = postSolution
+       EndGlobalSection
+       GlobalSection(ProjectConfiguration) = postSolution
+               {F66EFE7E-50A6-44D4-87C7-742B303BA852}.Debug.ActiveCfg = Debug|Win32
+               {F66EFE7E-50A6-44D4-87C7-742B303BA852}.Debug.Build.0 = Debug|Win32
+               {F66EFE7E-50A6-44D4-87C7-742B303BA852}.Release.ActiveCfg = Release|Win32
+               {F66EFE7E-50A6-44D4-87C7-742B303BA852}.Release.Build.0 = Release|Win32
+       EndGlobalSection
+       GlobalSection(ExtensibilityGlobals) = postSolution
+       EndGlobalSection
+       GlobalSection(ExtensibilityAddIns) = postSolution
+       EndGlobalSection
+EndGlobal
diff --git a/mDNSWindows/Applications/SystemService/Service2002.vcproj b/mDNSWindows/Applications/SystemService/Service2002.vcproj
new file mode 100644 (file)
index 0000000..d7e0bed
--- /dev/null
@@ -0,0 +1,196 @@
+<?xml version="1.0" encoding = "Windows-1252"?>
+<VisualStudioProject
+       ProjectType="Visual C++"
+       Version="7.00"
+       Name="mDNSResponder"
+       ProjectGUID="{F66EFE7E-50A6-44D4-87C7-742B303BA852}"
+       Keyword="Win32Proj">
+       <Platforms>
+               <Platform
+                       Name="Win32"/>
+       </Platforms>
+       <Configurations>
+               <Configuration
+                       Name="Debug|Win32"
+                       OutputDirectory="Debug"
+                       IntermediateDirectory="Debug"
+                       ConfigurationType="1"
+                       CharacterSet="2">
+                       <Tool
+                               Name="VCCLCompilerTool"
+                               Optimization="0"
+                               AdditionalIncludeDirectories="..\..\..\mDNSCore;..\..\..\mDNSWindows"
+                               PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;DEBUG=1;MDNS_DEBUGMSGS=0;DNS_SD_CLIENT_ENABLED=0"
+                               StringPooling="TRUE"
+                               MinimalRebuild="TRUE"
+                               ExceptionHandling="TRUE"
+                               BasicRuntimeChecks="3"
+                               SmallerTypeCheck="TRUE"
+                               RuntimeLibrary="1"
+                               BufferSecurityCheck="TRUE"
+                               ForceConformanceInForLoopScope="TRUE"
+                               UsePrecompiledHeader="2"
+                               BrowseInformation="1"
+                               WarningLevel="4"
+                               WarnAsError="TRUE"
+                               Detect64BitPortabilityProblems="TRUE"
+                               DebugInformationFormat="3"
+                               CompileAs="2"/>
+                       <Tool
+                               Name="VCCustomBuildTool"/>
+                       <Tool
+                               Name="VCLinkerTool"
+                               AdditionalDependencies="ws2_32.lib"
+                               OutputFile="$(ProjectName)Debug.exe"
+                               LinkIncremental="1"
+                               SuppressStartupBanner="TRUE"
+                               GenerateDebugInformation="TRUE"
+                               SubSystem="1"
+                               TargetMachine="1"/>
+                       <Tool
+                               Name="VCMIDLTool"/>
+                       <Tool
+                               Name="VCPostBuildEventTool"/>
+                       <Tool
+                               Name="VCPreBuildEventTool"/>
+                       <Tool
+                               Name="VCPreLinkEventTool"/>
+                       <Tool
+                               Name="VCResourceCompilerTool"/>
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"/>
+                       <Tool
+                               Name="VCWebDeploymentTool"/>
+               </Configuration>
+               <Configuration
+                       Name="Release|Win32"
+                       OutputDirectory="Release"
+                       IntermediateDirectory="Release"
+                       ConfigurationType="1"
+                       CharacterSet="2"
+                       WholeProgramOptimization="FALSE">
+                       <Tool
+                               Name="VCCLCompilerTool"
+                               Optimization="2"
+                               GlobalOptimizations="TRUE"
+                               InlineFunctionExpansion="2"
+                               FavorSizeOrSpeed="2"
+                               OmitFramePointers="TRUE"
+                               AdditionalIncludeDirectories="..\..\..\mDNSCore;..\..\..\mDNSWindows"
+                               PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;DNS_SD_CLIENT_ENABLED=0"
+                               StringPooling="TRUE"
+                               ExceptionHandling="FALSE"
+                               RuntimeLibrary="0"
+                               BufferSecurityCheck="FALSE"
+                               EnableFunctionLevelLinking="FALSE"
+                               DisableLanguageExtensions="FALSE"
+                               ForceConformanceInForLoopScope="TRUE"
+                               UsePrecompiledHeader="2"
+                               WarningLevel="4"
+                               WarnAsError="TRUE"
+                               Detect64BitPortabilityProblems="TRUE"
+                               DebugInformationFormat="3"
+                               CompileAs="0"/>
+                       <Tool
+                               Name="VCCustomBuildTool"/>
+                       <Tool
+                               Name="VCLinkerTool"
+                               AdditionalDependencies="ws2_32.lib"
+                               OutputFile="$(ProjectName).exe"
+                               LinkIncremental="1"
+                               SuppressStartupBanner="TRUE"
+                               GenerateDebugInformation="FALSE"
+                               SubSystem="1"
+                               OptimizeReferences="2"
+                               EnableCOMDATFolding="2"
+                               TargetMachine="1"/>
+                       <Tool
+                               Name="VCMIDLTool"/>
+                       <Tool
+                               Name="VCPostBuildEventTool"/>
+                       <Tool
+                               Name="VCPreBuildEventTool"/>
+                       <Tool
+                               Name="VCPreLinkEventTool"/>
+                       <Tool
+                               Name="VCResourceCompilerTool"/>
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"/>
+                       <Tool
+                               Name="VCWebDeploymentTool"/>
+               </Configuration>
+       </Configurations>
+       <Files>
+               <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="..\..\DNSSD.c">
+               </File>
+               <File
+                       RelativePath="..\..\DNSSD.h">
+               </File>
+               <File
+                       RelativePath="..\..\DNSSDDirect.c">
+               </File>
+               <File
+                       RelativePath="..\..\DNSSDDirect.h">
+               </File>
+               <File
+                       RelativePath="..\..\DebugServices.c">
+               </File>
+               <File
+                       RelativePath="..\..\DebugServices.h">
+               </File>
+               <File
+                       RelativePath="..\..\RMxCommon.c">
+               </File>
+               <File
+                       RelativePath="..\..\RMxCommon.h">
+               </File>
+               <File
+                       RelativePath="..\..\RMxServer.c">
+               </File>
+               <File
+                       RelativePath="..\..\RMxServer.h">
+               </File>
+               <File
+                       RelativePath="Service.c">
+               </File>
+               <File
+                       RelativePath="Service.rc">
+               </File>
+               <File
+                       RelativePath="..\..\..\mDNSCore\mDNS.c">
+               </File>
+               <File
+                       RelativePath="..\..\..\mDNSCore\mDNSClientAPI.h">
+               </File>
+               <File
+                       RelativePath="..\..\..\mDNSCore\mDNSDebug.h">
+               </File>
+               <File
+                       RelativePath="..\..\mDNSWin32.c">
+               </File>
+               <File
+                       RelativePath="..\..\mDNSWin32.h">
+               </File>
+               <File
+                       RelativePath="..\..\..\mDNSCore\uDNS.c">
+               </File>
+               <File
+                       RelativePath="..\..\..\mDNSCore\uDNS.h">
+               </File>
+       </Files>
+       <Globals>
+       </Globals>
+</VisualStudioProject>
diff --git a/mDNSWindows/Applications/SystemServiceTest/Prefix.h b/mDNSWindows/Applications/SystemServiceTest/Prefix.h
new file mode 100644 (file)
index 0000000..68e705b
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+
+$Log: Prefix.h,v $
+Revision 1.1  2004/01/30 02:58:57  bradley
+Test tool for the mDNSResponder Windows service.
+                                       
+*/
+
+#ifndef __PREFIX__
+#define __PREFIX__
+
+#if( defined( _DEBUG ) )
+       #define DEBUG                                   1
+       #define MDNS_DEBUGMSGS                  1
+#else
+       #define DEBUG                                   0
+#endif
+
+#define        DNS_SD_DIRECT_ENABLED           0
+#define        DNS_SD_CLIENT_ENABLED           1
+
+#endif // __PREFIX__
diff --git a/mDNSWindows/Applications/SystemServiceTest/Tool.c b/mDNSWindows/Applications/SystemServiceTest/Tool.c
new file mode 100644 (file)
index 0000000..5ab16d9
--- /dev/null
@@ -0,0 +1,847 @@
+/*
+ * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+       
+$Log: Tool.c,v $
+Revision 1.3  2004/04/09 21:03:15  bradley
+Changed port numbers to use network byte order for consistency with other platforms.
+
+Revision 1.2  2004/04/08 09:43:43  bradley
+Changed callback calling conventions to __stdcall so they can be used with C# delegates.
+
+Revision 1.1  2004/01/30 02:58:57  bradley
+Test tool for the mDNSResponder Windows service.
+
+*/
+
+#include       <stdio.h>
+#include       <stdlib.h>
+
+#include       "CommonServices.h"
+#include       "DebugServices.h"
+#include       "DNSSD.h"
+
+//===========================================================================================================================
+//     Structures
+//===========================================================================================================================
+
+#define MAX_DOMAIN_LABEL 63
+#define MAX_DOMAIN_NAME 255
+
+typedef union { unsigned char b[2]; unsigned short NotAnInteger; } Opaque16;
+
+typedef struct { u_char c[ 64]; } domainlabel;
+typedef struct { u_char c[256]; } domainname;
+
+typedef struct 
+    { 
+    uint16_t priority; 
+    uint16_t weight; 
+    uint16_t port; 
+    domainname target;
+    } srv_rdata;
+
+//===========================================================================================================================
+//     Prototypes
+//===========================================================================================================================
+
+int                            main( int argc, char* argv[] );
+static void                    Usage( void );
+static int                     ProcessArgs( int argc, char* argv[] );
+
+#if( defined( WINVER ) )
+       static BOOL WINAPI      ConsoleControlHandler( DWORD inControlEvent );
+#endif
+
+static void CALLBACK_COMPAT
+       EnumerateDomainsCallBack(
+               DNSServiceRef           inRef,
+               DNSServiceFlags         inFlags,
+               uint32_t                        inInterfaceIndex,
+               DNSServiceErrorType     inErrorCode,
+               const char *            inDomain,  
+               void *                          inContext );
+
+static void CALLBACK_COMPAT
+       BrowseCallBack(
+               DNSServiceRef           inRef,
+               DNSServiceFlags         inFlags,
+               uint32_t                        inInterfaceIndex,
+               DNSServiceErrorType     inErrorCode,
+               const char *            inName,  
+               const char *            inType,  
+               const char *            inDomain,  
+               void *                          inContext );
+
+static void CALLBACK_COMPAT
+       ResolveCallBack(
+               DNSServiceRef           inRef,
+               DNSServiceFlags         inFlags,
+               uint32_t                        inInterfaceIndex,
+               DNSServiceErrorType     inErrorCode,
+               const char *            inFullName,  
+               const char *            inHostName,  
+               uint16_t                        inPort, 
+               uint16_t                        inTXTSize, 
+               const char *            inTXT, 
+               void *                          inContext );
+
+static void CALLBACK_COMPAT
+       RegisterCallBack(
+               DNSServiceRef           inRef,
+               DNSServiceFlags         inFlags,
+               DNSServiceErrorType     inErrorCode,
+               const char *            inName,  
+               const char *            inType,  
+               const char *            inDomain,  
+               void *                          inContext );
+
+static void CALLBACK_COMPAT
+       RecordCallBack( 
+               DNSServiceRef                   inRef, 
+               DNSRecordRef                    inRecordRef, 
+               DNSServiceFlags                 inFlags, 
+               DNSServiceErrorType     inErrorCode, 
+               void *                                  inContext );
+
+static void CALLBACK_COMPAT
+       QueryCallBack( 
+               const DNSServiceRef             inRef, 
+               const DNSServiceFlags           inFlags, 
+               const uint32_t                          inInterfaceIndex, 
+               const DNSServiceErrorType       inErrorCode, 
+               const char *                            inName, 
+               const uint16_t                          inRRType, 
+               const uint16_t                          inRRClass, 
+               const uint16_t                          inRDataSize, 
+               const void *                            inRData, 
+               const uint32_t                          inTTL, 
+               void *                                          inContext );
+
+static void    PrintRData( uint16_t inRRType, size_t inRDataSize, const uint8_t *inRData );
+
+static char *ConvertDomainLabelToCString_withescape(const domainlabel *const label, char *ptr, char esc);
+static char *ConvertDomainNameToCString_withescape(const domainname *const name, char *ptr, char esc);
+
+//===========================================================================================================================
+//     Globals
+//===========================================================================================================================
+
+#if( defined( WINVER ) )
+       static volatile int             gQuit = 0;
+#endif
+
+//===========================================================================================================================
+//     main
+//===========================================================================================================================
+
+int main( int argc, char *argv[] )
+{
+       OSStatus                err;
+       
+       debug_initialize( kDebugOutputTypeMetaConsole );
+       debug_set_property( kDebugPropertyTagPrintLevel, kDebugLevelTrace );
+
+       SetConsoleCtrlHandler( ConsoleControlHandler, TRUE );
+       err = ProcessArgs( argc, argv );
+       return( (int) err );
+}
+
+//===========================================================================================================================
+//     Usage
+//===========================================================================================================================
+
+static void    Usage( void )
+{
+       fprintf( stderr, "\n" );
+       fprintf( stderr, "Rendezvous Service Test 1.0d1\n" );
+       fprintf( stderr, "\n" );
+       fprintf( stderr, "  -server <IP>                                      Set Remote Server\n" );
+       fprintf( stderr, "  -cv                                               Check Version\n" );
+       fprintf( stderr, "  -bd                                               Browse for Browse Domains\n" );
+       fprintf( stderr, "  -bs <type> <domain>                               Browse for Services\n" );
+       fprintf( stderr, "  -rsi <name> <type> <domain>                       Resolve Service Instance\n" );
+       fprintf( stderr, "  -rs <name> <type> <domain> <host> <port> <txt>    Register Service\n" );
+       fprintf( stderr, "  -rr                                               Register Records\n" );
+       fprintf( stderr, "  -qr <name> <type> <domain> <rrType>               Query Record\n" );
+       fprintf( stderr, "  -cr <name> <type> <domain> <rrType>               Reconfirm Record\n" );
+       fprintf( stderr, "  -cp <code>                                        Copy Property\n" );
+       fprintf( stderr, "  -h[elp]                                           Help\n" );
+       fprintf( stderr, "\n" );
+}
+
+DEBUG_LOCAL DNSServiceRef              gRef            = NULL;
+DEBUG_LOCAL DNSRecordRef               gRecordRef      = NULL;
+DEBUG_LOCAL const char *               gServer         = NULL;
+
+//===========================================================================================================================
+//     ProcessArgs
+//===========================================================================================================================
+
+static int ProcessArgs( int argc, char* argv[] )
+{      
+       OSStatus                        err;
+       int                                     i;
+       const char *            name;
+       const char *            type;
+       const char *            domain;
+       uint16_t                        port;
+       const char *            host;
+       const char *            txt;
+       uint16_t                        txtSize;
+       uint8_t                         txtStorage[ 256 ];
+       uint32_t                        ipv4;
+       char                            s[ 256 ];
+       DNSRecordRef            records[ 10 ];
+       char                            fullName[ kDNSServiceMaxDomainName ];
+       uint16_t                        rrType;
+       
+       err = DNSServiceInitialize( kDNSServiceInitializeFlagsNoServerCheck, 0 );
+       require_noerr( err, exit );
+       
+       // Parse the command line arguments (ignore first argument since it's just the program name).
+       
+       if( argc <= 1 )
+       {
+               Usage();
+               err = 0;
+               goto exit;
+       }
+       for( i = 1; i < argc; ++i )
+       {
+               if( strcmp( argv[ i ], "-server" ) == 0 )
+               {
+                       require_action( argc > ( i + 1 ), exit, err = kParamErr );
+                       gServer = argv[ ++i ];
+                       
+                       printf( "Server set to \"%s\"\n", gServer );
+               }
+               else if( strcmp( argv[ i ], "-cv" ) == 0 )
+               {
+                       // Check Version
+                                               
+                       err = DNSServiceCheckVersion();
+                       printf( "CheckVersion: %ld\n", err );
+                       err = kNoErr;
+                       goto exit;
+               }
+               else if( strcmp( argv[ i ], "-bd" ) == 0 )
+               {
+                       err = DNSServiceEnumerateDomains( &gRef, kDNSServiceFlagsBrowseDomains, 0, 
+                               EnumerateDomainsCallBack, NULL );
+                       require_noerr( err, exit );
+               }
+               else if( strcmp( argv[ i ], "-bs" ) == 0 )
+               {
+                       // Browse service <type> <domain>
+                                               
+                       if( argc > ( i + 2 ) )
+                       {
+                               type    = argv[ ++i ];
+                               domain  = argv[ ++i ];
+                       }
+                       else
+                       {
+                               type    = "_http._tcp";
+                               domain  = "";
+                       }
+                       if( ( domain[ 0 ] == '\0' ) || ( ( domain[ 0 ] == '.' ) && ( domain[ 1 ] == '\0' ) ) )
+                       {
+                               domain = "local.";
+                       }
+                       
+                       err = DNSServiceBrowse( &gRef, 0, 0, type, domain, BrowseCallBack, NULL );
+                       require_noerr( err, exit );
+               }
+               else if( strcmp( argv[ i ], "-rsi" ) == 0 )
+               {
+                       // Resolve Service Instance <name> <type> <domain>
+                                               
+                       if( argc > ( i + 3 ) )
+                       {
+                               name    = argv[ ++i ];
+                               type    = argv[ ++i ];
+                               domain  = argv[ ++i ];
+                       }
+                       else
+                       {
+                               name    = "test service";
+                               type    = "_http._tcp";
+                               domain  = "";
+                       }
+                       if( ( domain[ 0 ] == '\0' ) || ( ( domain[ 0 ] == '.' ) && ( domain[ 1 ] == '\0' ) ) )
+                       {
+                               domain = "local.";
+                       }
+                       
+                       err = DNSServiceResolve( &gRef, 0, 0, name, type, domain, ResolveCallBack, NULL );
+                       require_noerr( err, exit );
+               }
+               else if( strcmp( argv[ i ], "-rs" ) == 0 )
+               {
+                       // Register Service <name> <type> <domain> <host> <port> <txt>
+                       
+                       if( argc > ( i + 6 ) )
+                       {
+                               name    = argv[ ++i ];
+                               type    = argv[ ++i ];
+                               domain  = argv[ ++i ];
+                               host    = argv[ ++i ];
+                               port    = (uint16_t) atoi( argv[ ++i ] );
+                               txt     = argv[ ++i ];
+                       }
+                       else
+                       {
+                               name    = "test service";
+                               type    = "_http._tcp";
+                               domain  = "";
+                               host    = "";
+                               port    = 80;
+                               txt             = "My TXT Record";
+                       }
+                       if( *txt != '\0' )
+                       {
+                               txtStorage[ 0 ] = (uint8_t) strlen( txt );
+                               memcpy( &txtStorage[ 1 ], txt, txtStorage[ 0 ] );
+                               txtSize = (uint16_t)( 1 + txtStorage[ 0 ] );
+                               txt = (const char *) txtStorage;
+                       }
+                       else
+                       {
+                               txt = NULL;
+                               txtSize = 0;
+                       }
+                       if( ( domain[ 0 ] == '\0' ) || ( ( domain[ 0 ] == '.' ) && ( domain[ 1 ] == '\0' ) ) )
+                       {
+                               domain = "local.";
+                       }
+                       
+                       err = DNSServiceRegister( &gRef, 0, 0, name, type, domain, host, htons( port ), txtSize, txt, 
+                               RegisterCallBack, NULL );
+                       require_noerr( err, exit );
+                       
+                       #if( TEST_SERVICE_RECORDS )
+                               ipv4 = 0x11223344;
+                               err = DNSServiceAddRecord( gRef, &gRecordRef, 0, kDNSServiceDNSType_A, kDNSServiceDNSClass_IN, &ipv4, 60 );
+                               require_noerr( err, exit );
+                               
+                               Sleep( 10000 );
+                               
+                               ipv4 = 0x22334455;
+                               err = DNSServiceUpdateRecord( gRef, gRecordRef, 0, 4, &ipv4, 60 );
+                               require_noerr( err, exit );
+                               
+                               Sleep( 10000 );
+                               
+                               err = DNSServiceRemoveRecord( gRef, gRecordRef, 0 );
+                               require_noerr( err, exit );
+                               gRecordRef = NULL;
+                               
+                               Sleep( 10000 );
+                       #endif
+               }
+               else if( strcmp( argv[ i ], "-rr" ) == 0 )
+               {
+                       // Register Records
+                       
+                       err = DNSServiceCreateConnection( &gRef );
+                       require_noerr( err, exit );
+                                               
+                       printf( "registering 10 address records...\n" );
+                       ipv4 = 0x11223310;
+                       for( i = 0; i < 10; ++i )
+                       {
+                               sprintf( s, "testhost-%d.local.", i );
+                               ++ipv4;
+                               err = DNSServiceRegisterRecord( gRef, &records[ i ], kDNSServiceFlagsUnique, 0, s, 
+                                       kDNSServiceDNSType_A, kDNSServiceDNSClass_IN, 4, &ipv4, 60, RecordCallBack, NULL );
+                               check_noerr( err );
+                       }
+                       Sleep( 10000 );
+                       
+                       printf( "deregistering half of the records\n" );
+                       for( i = 0; i < 10; ++i )
+                       {
+                               if( i % 2 )
+                               {
+                                       err = DNSServiceRemoveRecord( gRef, records[ i ], 0 );
+                                       check_noerr( err );
+                                       records[ i ] = NULL;
+                               }
+                       }
+                       Sleep( 10000 );
+                       
+                       printf( "updating the remaining records\n" );
+                       for( i = 0; i < 10; ++i )
+                       {
+                               if( records[ i ] )
+                               {
+                                       ++ipv4;
+                                       err = DNSServiceUpdateRecord( gRef, records[ i ], 0, 4, &ipv4, 60 );
+                                       check_noerr( err );
+                               }
+                       }
+                       Sleep( 10000 );
+                       
+                       printf( "deregistering all remaining records\n" );
+               DNSServiceRefDeallocate( gRef );
+               
+               Sleep( 5000 );
+               }
+               else if( strcmp( argv[ i ], "-qr" ) == 0 )
+               {
+                       // Query Record <name> <type> <domain> <rrType>
+                                               
+                       if( argc > ( i + 4 ) )
+                       {
+                               name    = argv[ ++i ];
+                               type    = argv[ ++i ];
+                               domain  = argv[ ++i ];
+                               rrType  = (uint16_t) atoi( argv[ ++i ] );
+                       }
+                       else
+                       {
+                               name    = "test";
+                               type    = "";
+                               domain  = "";
+                               rrType  = 1;    // Address
+                       }
+                       if( ( domain[ 0 ] == '\0' ) || ( ( domain[ 0 ] == '.' ) && ( domain[ 1 ] == '\0' ) ) )
+                       {
+                               domain = "local.";
+                       }
+                       err = DNSServiceConstructFullName( fullName, name, type, domain );
+                       require_noerr( err, exit );
+                       
+                       printf( "resolving fullname %s type %d\n", fullName, rrType );
+                       err = DNSServiceQueryRecord( &gRef, 0, 0, fullName, rrType, kDNSServiceDNSClass_IN, QueryCallBack, NULL );
+                       require_noerr( err, exit );
+               }
+               else if( strcmp( argv[ i ], "-cr" ) == 0 )
+               {
+                       // Reconfirm Record <name> <type> <domain> <rrType>
+                       
+                       if( argc > ( i + 4 ) )
+                       {
+                               name    = argv[ ++i ];
+                               type    = argv[ ++i ];
+                               domain  = argv[ ++i ];
+                               rrType  = (uint16_t) atoi( argv[ ++i ] );
+                       }
+                       else
+                       {
+                               name    = "test";
+                               type    = "";
+                               domain  = "";
+                               rrType  = 1;    // Address
+                       }
+                       if( ( domain[ 0 ] == '\0' ) || ( ( domain[ 0 ] == '.' ) && ( domain[ 1 ] == '\0' ) ) )
+                       {
+                               domain = "local.";
+                       }
+                       err = DNSServiceConstructFullName( fullName, name, type, domain );
+                       require_noerr( err, exit );
+                       
+                       printf( "reconfirming record fullname %s type %d\n", fullName, rrType );
+                       ipv4 = 0x11223310;
+                       DNSServiceReconfirmRecord( 0, 0, fullName, rrType, kDNSServiceDNSClass_IN, 4, &ipv4 );
+               }
+               else if( strcmp( argv[ i ], "-cp" ) == 0 )
+               {
+                       DNSPropertyCode         code;
+                       DNSPropertyData         data;
+                       
+                       // Copy Property <code>
+                                               
+                       if( argc > ( i + 1 ) )
+                       {
+                               name = argv[ ++i ];
+                               require_action( strlen( name ) == 4, exit, err = kParamErr );
+                               
+                               code  = (DNSPropertyCode)( name[ 0 ] << 24 );
+                               code |= (DNSPropertyCode)( name[ 1 ] << 16 );
+                               code |= (DNSPropertyCode)( name[ 2 ] <<  8 );
+                               code |= (DNSPropertyCode)  name[ 3 ];
+                       }
+                       else
+                       {
+                               code = kDNSPropertyCodeVersion;
+                               name = "vers";
+                       }
+                       
+                       err = DNSServiceCopyProperty( code, &data );
+                       require_noerr( err, exit );
+                       
+                       printf( "'%s' property:\n", name );
+                       if( code == kDNSPropertyCodeVersion )
+                       {
+                               printf( "    clientCurrentVersion:      0x%08X\n", data.u.version.clientCurrentVersion );
+                               printf( "    clientOldestServerVersion: 0x%08X\n", data.u.version.clientOldestServerVersion );
+                               printf( "    serverCurrentVersion:      0x%08X\n", data.u.version.serverCurrentVersion );
+                               printf( "    serverOldestClientVersion: 0x%08X\n", data.u.version.serverOldestClientVersion );
+                       }
+               }
+               else if( ( strcmp( argv[ i ], "-help" ) == 0 ) || ( strcmp( argv[ i ], "-h" ) == 0 ) )
+               {
+                       // Help
+                       
+                       Usage();
+                       err = 0;
+                       goto exit;
+               }
+               else
+               {
+                       // Unknown parameter.
+                       
+                       dlog( kDebugLevelError, "unknown parameter (%s)\n", argv[ i ] );
+                       err = kParamErr;
+                       goto exit;
+               }
+       }
+       
+       // Run until control-C'd.
+       
+       while( !gQuit )
+       {
+               Sleep( 100 );
+       }
+       err = kNoErr;
+       
+exit:
+       DNSServiceFinalize();
+       if( err )
+       {
+               Usage();
+       }
+       return( err );
+}
+
+//===========================================================================================================================
+//     ConsoleControlHandler
+//===========================================================================================================================
+
+static BOOL WINAPI     ConsoleControlHandler( DWORD inControlEvent )
+{
+       BOOL            handled;
+       
+       handled = 0;
+       switch( inControlEvent )
+       {
+               case CTRL_C_EVENT:
+               case CTRL_BREAK_EVENT:
+               case CTRL_CLOSE_EVENT:
+               case CTRL_LOGOFF_EVENT:
+               case CTRL_SHUTDOWN_EVENT:
+                       gQuit = 1;
+                       handled = 1;
+                       break;
+               
+               default:
+                       break;
+       }
+       return( handled );
+}
+
+//===========================================================================================================================
+//     EnumerateDomainsCallBack
+//===========================================================================================================================
+
+static void CALLBACK_COMPAT
+       EnumerateDomainsCallBack(
+               DNSServiceRef           inRef,
+               DNSServiceFlags         inFlags,
+               uint32_t                        inInterfaceIndex,
+               DNSServiceErrorType     inErrorCode,
+               const char *            inDomain,  
+               void *                          inContext )
+{
+       printf( "inRef:            0x%08X\n", (uintptr_t) inRef );
+       printf( "inFlags:          0x%08X\n", (int) inFlags );
+       printf( "inInterfaceIndex: 0x%08X\n", (int) inInterfaceIndex );
+       printf( "inErrorCode:      %ld\n", inErrorCode );
+       printf( "inDomain:         \"%s\"\n", inDomain ? inDomain : "<null>" );
+       printf( "inContext:        0x%08X\n", (uintptr_t) inContext );
+       printf( "\n" );
+}
+
+//===========================================================================================================================
+//     BrowseCallBack
+//===========================================================================================================================
+
+static void CALLBACK_COMPAT
+       BrowseCallBack(
+               DNSServiceRef           inRef,
+               DNSServiceFlags         inFlags,
+               uint32_t                        inInterfaceIndex,
+               DNSServiceErrorType     inErrorCode,
+               const char *            inName,  
+               const char *            inType,  
+               const char *            inDomain,  
+               void *                          inContext )
+{
+       printf( "inRef:            0x%08X\n", (uintptr_t) inRef );
+       printf( "inFlags:          0x%08X\n", (int) inFlags );
+       printf( "inInterfaceIndex: 0x%08X\n", (int) inInterfaceIndex );
+       printf( "inErrorCode:      %ld\n", inErrorCode );
+       printf( "inName:           \"%s\"\n", inName ? inName : "<null>" );
+       printf( "inType:           \"%s\"\n", inType ? inType : "<null>" );
+       printf( "inDomain:         \"%s\"\n", inDomain ? inDomain : "<null>" );
+       printf( "inContext:        0x%08X\n", (uintptr_t) inContext );
+       printf( "\n" );
+}
+
+//===========================================================================================================================
+//     ResolveCallBack
+//===========================================================================================================================
+
+static void CALLBACK_COMPAT
+       ResolveCallBack(
+               DNSServiceRef           inRef,
+               DNSServiceFlags         inFlags,
+               uint32_t                        inInterfaceIndex,
+               DNSServiceErrorType     inErrorCode,
+               const char *            inFullName,  
+               const char *            inHostName,  
+               uint16_t                        inPort, 
+               uint16_t                        inTXTSize, 
+               const char *            inTXT, 
+               void *                          inContext )
+{
+       printf( "inRef:            0x%08X\n", (uintptr_t) inRef );
+       printf( "inFlags:          0x%08X\n", (int) inFlags );
+       printf( "inInterfaceIndex: 0x%08X\n", (int) inInterfaceIndex );
+       printf( "inErrorCode:      %ld\n", inErrorCode );
+       printf( "inFullName:       \"%s\"\n", inFullName ? inFullName : "<null>" );
+       printf( "inHostName:       \"%s\"\n", inHostName ? inHostName : "<null>" );
+       printf( "inPort:           %d\n", ntohs( inPort ) );
+       printf( "inTXTSize:        %ld\n", inTXTSize );
+       printf( "inTXT:            0x%08X\n", (uintptr_t) inTXT );
+       printf( "inContext:        0x%08X\n", (uintptr_t) inContext );
+       printf( "\n" );
+}
+
+//===========================================================================================================================
+//     RegisterCallBack
+//===========================================================================================================================
+
+static void CALLBACK_COMPAT
+       RegisterCallBack(
+               DNSServiceRef           inRef,
+               DNSServiceFlags         inFlags,
+               DNSServiceErrorType     inErrorCode,
+               const char *            inName,  
+               const char *            inType,  
+               const char *            inDomain,  
+               void *                          inContext )
+{
+       printf( "inRef:            0x%08X\n", (uintptr_t) inRef );
+       printf( "inFlags:          0x%08X\n", (int) inFlags );
+       printf( "inErrorCode:      %ld\n", inErrorCode );
+       printf( "inName:           \"%s\"\n", inName ? inName : "<null>" );
+       printf( "inType:           \"%s\"\n", inType ? inType : "<null>" );
+       printf( "inDomain:         \"%s\"\n", inDomain ? inDomain : "<null>" );
+       printf( "inContext:        0x%08X\n", (uintptr_t) inContext );
+       printf( "\n" );
+}
+
+//===========================================================================================================================
+//     RecordCallBack
+//===========================================================================================================================
+
+static void CALLBACK_COMPAT
+       RecordCallBack( 
+               DNSServiceRef                   inRef, 
+               DNSRecordRef                    inRecordRef, 
+               DNSServiceFlags                 inFlags, 
+               DNSServiceErrorType     inErrorCode, 
+               void *                                  inContext )
+{
+       DEBUG_UNUSED( inRef );
+       DEBUG_UNUSED( inRecordRef );
+       DEBUG_UNUSED( inFlags );
+       DEBUG_UNUSED( inContext );
+       
+       if( inErrorCode == kDNSServiceErr_NoError )
+       {
+               printf( "RecordCallBack: no errors\n" );
+       }
+       else
+       {
+               printf( "RecordCallBack: %ld error\n", inErrorCode );
+       }
+}
+
+//===========================================================================================================================
+//     QueryCallBack
+//===========================================================================================================================
+
+static void CALLBACK_COMPAT
+       QueryCallBack( 
+               const DNSServiceRef             inRef, 
+               const DNSServiceFlags           inFlags, 
+               const uint32_t                          inInterfaceIndex, 
+               const DNSServiceErrorType       inErrorCode, 
+               const char *                            inName, 
+               const uint16_t                          inRRType, 
+               const uint16_t                          inRRClass, 
+               const uint16_t                          inRDataSize, 
+               const void *                            inRData, 
+               const uint32_t                          inTTL, 
+               void *                                          inContext )
+{
+       DEBUG_UNUSED( inRef );
+       DEBUG_UNUSED( inRRClass );
+       DEBUG_UNUSED( inTTL );
+       DEBUG_UNUSED( inContext );
+       
+       if( inErrorCode == kDNSServiceErr_NoError )
+       {
+               if( inFlags & kDNSServiceFlagsAdd )
+               {
+                       printf( "Add" );
+               }
+               else
+               {
+                       printf( "Rmv" );
+               }
+               if( inFlags & kDNSServiceFlagsMoreComing )
+               {
+                       printf( "+" );
+               }
+               else
+               {
+                       printf( " " );
+               }
+               printf(" 0x%04X %d %s rdata ", inFlags, inInterfaceIndex, inName );
+               PrintRData( inRRType, (size_t) inRDataSize, (const uint8_t *) inRData );
+       }
+       else
+       {
+               printf( "QueryCallback: %ld error\n", inErrorCode );
+       }
+}
+
+//===========================================================================================================================
+//     PrintRData
+//===========================================================================================================================
+
+static void    PrintRData( uint16_t inRRType, size_t inRDataSize, const uint8_t *inRData )
+{
+       size_t                          i;
+       srv_rdata *                     srv;
+       char                            s[ 1005 ];
+       struct in_addr          in;
+       
+       switch( inRRType )
+       {
+               case kDNSServiceDNSType_TXT:
+                       
+                       // Print all the alphanumeric and punctuation characters
+                       
+                       for( i = 0; i < inRDataSize; ++i )
+                       {
+                               if( ( inRData[ i ] >= 32 ) && ( inRData[ i ] <= 127 ) )
+                               {
+                                       printf( "%c", inRData[ i ] );
+                               }
+                       }
+                       printf( "\n" );
+                       break;
+                       
+               case kDNSServiceDNSType_SRV:
+                       srv = (srv_rdata *)inRData;
+                       ConvertDomainNameToCString_withescape(&srv->target, s, 0);
+                       printf("pri=%d, w=%d, port=%d, target=%s\n", srv->priority, srv->weight, srv->port, s);
+                       break;
+                       
+               case kDNSServiceDNSType_A:
+                       check( inRDataSize == 4 );
+                       memcpy( &in, inRData, sizeof( in ) );
+                       printf( "%s\n", inet_ntoa( in ) );
+                       break;
+                       
+               case kDNSServiceDNSType_PTR:
+                       ConvertDomainNameToCString_withescape( (domainname *) inRData, s, 0 );
+                       break;
+               
+               case kDNSServiceDNSType_AAAA:
+                       check( inRDataSize == 16 );
+                       printf( "%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X\n",
+                                       inRData[0], inRData[1], inRData[2], inRData[3], inRData[4], inRData[5], inRData[6], inRData[7], inRData[8], 
+                                       inRData[9], inRData[10], inRData[11], inRData[12], inRData[13], inRData[14], inRData[15] );
+                       break;
+               
+               default:
+                       printf( "ERROR: I dont know how to print inRData of type %d\n", inRRType );
+                       return;
+       }
+}
+
+static char *ConvertDomainLabelToCString_withescape(const domainlabel *const label, char *ptr, char esc)
+    {
+    const unsigned char *      src = label->c;                         // Domain label we're reading
+    const unsigned char        len = *src++;                           // Read length of this (non-null) label
+    const unsigned char *const end = src + len;                        // Work out where the label ends
+    if (len > 63) return(NULL);           // If illegal label, abort
+    while (src < end)                                           // While we have characters in the label
+        {
+        unsigned char c = *src++;
+        if (esc)
+            {
+            if (c == '.')                                       // If character is a dot,
+                *ptr++ = esc;                                   // Output escape character
+            else if (c <= ' ')                                  // If non-printing ascii,
+                {                                                   // Output decimal escape sequence
+                *ptr++ = esc;
+                *ptr++ = (char)  ('0' + (c / 100)     );
+                *ptr++ = (char)  ('0' + (c /  10) % 10);
+                c      = (unsigned char)('0' + (c      ) % 10);
+                }
+            }
+        *ptr++ = (char)c;                                       // Copy the character
+        }
+    *ptr = 0;                                                   // Null-terminate the string
+    return(ptr);                                                // and return
+    }
+
+static char *ConvertDomainNameToCString_withescape(const domainname *const name, char *ptr, char esc)
+    {
+    const unsigned char *src         = name->c;                        // Domain name we're reading
+    const unsigned char *const max   = name->c + MAX_DOMAIN_NAME;      // Maximum that's valid
+
+    if (*src == 0) *ptr++ = '.';                                // Special case: For root, just write a dot
+
+    while (*src)                                                                                                        // While more characters in the domain name
+        {
+        if (src + 1 + *src >= max) return(NULL);
+        ptr = ConvertDomainLabelToCString_withescape((const domainlabel *)src, ptr, esc);
+        if (!ptr) return(NULL);
+        src += 1 + *src;
+        *ptr++ = '.';                                           // Write the dot after the label
+        }
+
+    *ptr++ = 0;                                                 // Null-terminate the string
+    return(ptr);                                                // and return
+    }
diff --git a/mDNSWindows/Applications/SystemServiceTest/Tool.mcp b/mDNSWindows/Applications/SystemServiceTest/Tool.mcp
new file mode 100644 (file)
index 0000000..5920013
Binary files /dev/null and b/mDNSWindows/Applications/SystemServiceTest/Tool.mcp differ
diff --git a/mDNSWindows/Applications/SystemServiceTest/Tool2002.sln b/mDNSWindows/Applications/SystemServiceTest/Tool2002.sln
new file mode 100644 (file)
index 0000000..1659ac6
--- /dev/null
@@ -0,0 +1,21 @@
+Microsoft Visual Studio Solution File, Format Version 7.00
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Tool", "Tool2002.vcproj", "{F66EFE7E-50A6-44D4-87C7-742B303BA852}"
+EndProject
+Global
+       GlobalSection(SolutionConfiguration) = preSolution
+               ConfigName.0 = Debug
+               ConfigName.1 = Release
+       EndGlobalSection
+       GlobalSection(ProjectDependencies) = postSolution
+       EndGlobalSection
+       GlobalSection(ProjectConfiguration) = postSolution
+               {F66EFE7E-50A6-44D4-87C7-742B303BA852}.Debug.ActiveCfg = Debug|Win32
+               {F66EFE7E-50A6-44D4-87C7-742B303BA852}.Debug.Build.0 = Debug|Win32
+               {F66EFE7E-50A6-44D4-87C7-742B303BA852}.Release.ActiveCfg = Release|Win32
+               {F66EFE7E-50A6-44D4-87C7-742B303BA852}.Release.Build.0 = Release|Win32
+       EndGlobalSection
+       GlobalSection(ExtensibilityGlobals) = postSolution
+       EndGlobalSection
+       GlobalSection(ExtensibilityAddIns) = postSolution
+       EndGlobalSection
+EndGlobal
diff --git a/mDNSWindows/Applications/SystemServiceTest/Tool2002.vcproj b/mDNSWindows/Applications/SystemServiceTest/Tool2002.vcproj
new file mode 100644 (file)
index 0000000..0afc4b3
--- /dev/null
@@ -0,0 +1,191 @@
+<?xml version="1.0" encoding = "Windows-1252"?>
+<VisualStudioProject
+       ProjectType="Visual C++"
+       Version="7.00"
+       Name="mDNSResponderTest"
+       ProjectGUID="{F66EFE7E-50A6-44D4-87C7-742B303BA852}"
+       Keyword="Win32Proj">
+       <Platforms>
+               <Platform
+                       Name="Win32"/>
+       </Platforms>
+       <Configurations>
+               <Configuration
+                       Name="Debug|Win32"
+                       OutputDirectory="Debug"
+                       IntermediateDirectory="Debug"
+                       ConfigurationType="1"
+                       CharacterSet="2">
+                       <Tool
+                               Name="VCCLCompilerTool"
+                               Optimization="0"
+                               AdditionalIncludeDirectories="..\..\..\mDNSCore;..\..\..\mDNSWindows"
+                               PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;DEBUG=1"
+                               StringPooling="TRUE"
+                               MinimalRebuild="TRUE"
+                               ExceptionHandling="FALSE"
+                               BasicRuntimeChecks="3"
+                               SmallerTypeCheck="FALSE"
+                               RuntimeLibrary="1"
+                               BufferSecurityCheck="TRUE"
+                               ForceConformanceInForLoopScope="TRUE"
+                               UsePrecompiledHeader="2"
+                               BrowseInformation="1"
+                               WarningLevel="4"
+                               WarnAsError="TRUE"
+                               Detect64BitPortabilityProblems="TRUE"
+                               DebugInformationFormat="3"/>
+                       <Tool
+                               Name="VCCustomBuildTool"/>
+                       <Tool
+                               Name="VCLinkerTool"
+                               AdditionalDependencies="ws2_32.lib"
+                               OutputFile="$(ProjectName)Debug.exe"
+                               LinkIncremental="1"
+                               SuppressStartupBanner="TRUE"
+                               GenerateDebugInformation="TRUE"
+                               SubSystem="1"
+                               TargetMachine="1"/>
+                       <Tool
+                               Name="VCMIDLTool"/>
+                       <Tool
+                               Name="VCPostBuildEventTool"/>
+                       <Tool
+                               Name="VCPreBuildEventTool"/>
+                       <Tool
+                               Name="VCPreLinkEventTool"/>
+                       <Tool
+                               Name="VCResourceCompilerTool"/>
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"/>
+                       <Tool
+                               Name="VCWebDeploymentTool"/>
+               </Configuration>
+               <Configuration
+                       Name="Release|Win32"
+                       OutputDirectory="Release"
+                       IntermediateDirectory="Release"
+                       ConfigurationType="1"
+                       CharacterSet="2"
+                       WholeProgramOptimization="FALSE">
+                       <Tool
+                               Name="VCCLCompilerTool"
+                               Optimization="2"
+                               InlineFunctionExpansion="2"
+                               FavorSizeOrSpeed="2"
+                               OmitFramePointers="TRUE"
+                               AdditionalIncludeDirectories="..\..\..\mDNSCore;..\..\..\mDNSWindows"
+                               PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+                               StringPooling="TRUE"
+                               ExceptionHandling="FALSE"
+                               RuntimeLibrary="0"
+                               BufferSecurityCheck="FALSE"
+                               EnableFunctionLevelLinking="FALSE"
+                               DisableLanguageExtensions="FALSE"
+                               ForceConformanceInForLoopScope="TRUE"
+                               UsePrecompiledHeader="2"
+                               WarningLevel="4"
+                               WarnAsError="TRUE"
+                               Detect64BitPortabilityProblems="TRUE"
+                               DebugInformationFormat="3"
+                               CompileAs="1"/>
+                       <Tool
+                               Name="VCCustomBuildTool"/>
+                       <Tool
+                               Name="VCLinkerTool"
+                               AdditionalDependencies="ws2_32.lib"
+                               OutputFile="$(ProjectName).exe"
+                               LinkIncremental="1"
+                               SuppressStartupBanner="TRUE"
+                               GenerateDebugInformation="TRUE"
+                               SubSystem="1"
+                               OptimizeReferences="2"
+                               EnableCOMDATFolding="2"
+                               TargetMachine="1"/>
+                       <Tool
+                               Name="VCMIDLTool"/>
+                       <Tool
+                               Name="VCPostBuildEventTool"/>
+                       <Tool
+                               Name="VCPreBuildEventTool"/>
+                       <Tool
+                               Name="VCPreLinkEventTool"/>
+                       <Tool
+                               Name="VCResourceCompilerTool"/>
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"/>
+                       <Tool
+                               Name="VCWebDeploymentTool"/>
+               </Configuration>
+       </Configurations>
+       <Files>
+               <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="..\..\DNSSD.c">
+               </File>
+               <File
+                       RelativePath="..\..\DNSSD.h">
+               </File>
+               <File
+                       RelativePath="..\..\DNSSDDirect.c">
+               </File>
+               <File
+                       RelativePath="..\..\DNSSDDirect.h">
+               </File>
+               <File
+                       RelativePath="..\..\DebugServices.c">
+               </File>
+               <File
+                       RelativePath="..\..\DebugServices.h">
+               </File>
+               <File
+                       RelativePath="..\..\RMxClient.c">
+               </File>
+               <File
+                       RelativePath="..\..\RMxClient.h">
+               </File>
+               <File
+                       RelativePath="..\..\RMxCommon.c">
+               </File>
+               <File
+                       RelativePath="..\..\RMxCommon.h">
+               </File>
+               <File
+                       RelativePath="Tool.c">
+               </File>
+               <File
+                       RelativePath="..\..\..\mDNSCore\mDNS.c">
+               </File>
+               <File
+                       RelativePath="..\..\..\mDNSCore\mDNSClientAPI.h">
+               </File>
+               <File
+                       RelativePath="..\..\..\mDNSCore\mDNSDebug.h">
+               </File>
+               <File
+                       RelativePath="..\..\mDNSWin32.c">
+               </File>
+               <File
+                       RelativePath="..\..\mDNSWin32.h">
+               </File>
+               <File
+                       RelativePath="..\..\..\mDNSCore\uDNS.c">
+               </File>
+               <File
+                       RelativePath="..\..\..\mDNSCore\uDNS.h">
+               </File>
+       </Files>
+       <Globals>
+       </Globals>
+</VisualStudioProject>
diff --git a/mDNSWindows/Applications/mdnsNSP/NSP.c b/mDNSWindows/Applications/mdnsNSP/NSP.c
new file mode 100644 (file)
index 0000000..faf459d
--- /dev/null
@@ -0,0 +1,1367 @@
+/*
+ * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+    
+$Log: NSP.c,v $
+Revision 1.2  2004/04/08 09:43:43  bradley
+Changed callback calling conventions to __stdcall so they can be used with C# delegates.
+
+Revision 1.1  2004/01/30 03:00:33  bradley
+Rendezvous NameSpace Provider (NSP). Hooks into the Windows name resolution system to resolve
+Rendezvous name lookups using Multicast DNS so .local names work in all Windows apps.
+
+*/
+
+#include       <stdio.h>
+#include       <stdlib.h>
+#include       <string.h>
+
+#include       "CommonServices.h"
+#include       "DebugServices.h"
+
+#include       <guiddef.h>
+#include       <ws2spi.h>
+
+#include       "DNSSD.h"
+
+#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                          dataEvent;
+       HANDLE                          cancelEvent;
+       HANDLE                          waitHandles[ 2 ];
+       DWORD                           waitCount;
+       DNSServiceRef           resolver;
+       char                            name[ kDNSServiceMaxDomainName ];
+       size_t                          nameSize;
+       uint32_t                        addr;
+       bool                            addrValid;
+};
+
+#if 0
+#pragma mark == Prototypes ==
+#endif
+
+//===========================================================================================================================
+//     Prototypes
+//===========================================================================================================================
+
+// DLL Exports
+
+BOOL WINAPI            DllMain( HINSTANCE inInstance, DWORD inReason, LPVOID inReserved );
+
+// 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
+       QueryRecordCallback(
+               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
+
+#if 0
+#pragma mark == Globals ==
+#endif
+
+//===========================================================================================================================
+//     Globals
+//===========================================================================================================================
+
+// {B600E6E9-553B-4a19-8696-335E5C896153}
+// GUID                kRendezvousNSPGUID = { 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 bool                                       gDNSSDInitialized       = false;
+DEBUG_LOCAL QueryRef                           gQueryList                      = 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:                        
+                       debug_initialize( kDebugOutputTypeWindowsEventLog, "Rendezvous NSP", inInstance );
+                       debug_set_property( kDebugPropertyTagPrintLevel, kDebugLevelInfo );
+                       dlog( kDebugLevelTrace, "\n" );
+                       dlog( kDebugLevelVerbose, "%s: process attach\n", __ROUTINE__ );
+                       break;
+               
+               case DLL_PROCESS_DETACH:
+                       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 );
+}
+
+//===========================================================================================================================
+//     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;
+       
+       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();
+       }
+       
+       // Shut down DNS-SD and release our resources.
+       
+       if( gDNSSDInitialized )
+       {
+               gDNSSDInitialized = false;
+               DNSServiceFinalize();
+       }
+       if( gLockInitialized )
+       {
+               gLockInitialized = false;
+               DeleteCriticalSection( &gLock );
+       }
+       
+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_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 );
+       require_action_quiet( ( ( 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' ) ) ), 
+                                                 exit, err = WSASERVICE_NOT_FOUND );
+       
+       // The name ends in .local so start the resolve operation. Lazy initialize DNS-SD if needed.
+               
+       NSPLock();
+       if( !gDNSSDInitialized )
+       {
+               err = DNSServiceInitialize( kDNSServiceInitializeFlagsNoServerCheck, 0 );
+               require_noerr( err, exit );
+               gDNSSDInitialized = true;
+       }
+       
+       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 )
+{
+       OSStatus                err;
+       QueryRef                obj;
+       DWORD                   waitResult;
+       size_t                  size;
+       
+       DEBUG_USE_ONLY( inFlags );
+       
+       dlog( kDebugLevelTrace, "%s begin (ticks=%d)\n", __ROUTINE__, GetTickCount() );
+       
+       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, 5 * 1000 );
+       NSPLock();
+       require_action_quiet( waitResult != ( WAIT_OBJECT_0 + 1 ), exit, err = WSA_E_CANCELLED );
+       err = translate_errno( waitResult == WAIT_OBJECT_0, (OSStatus) GetLastError(), WSASERVICE_NOT_FOUND );
+       require_noerr_quiet( err, exit );
+       require_action_quiet( obj->addrValid, 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->addrValid = 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;
+       
+       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 events to signal when data is ready and when cancelling.
+       
+       obj->dataEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
+       require_action( obj->dataEvent, exit, err = WSA_NOT_ENOUGH_MEMORY );
+       
+       obj->cancelEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
+       require_action( obj->cancelEvent, exit, err = WSA_NOT_ENOUGH_MEMORY );
+       
+       obj->waitCount = 0;
+       obj->waitHandles[ obj->waitCount++ ] = obj->dataEvent;
+       obj->waitHandles[ obj->waitCount++ ] = obj->cancelEvent;
+       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 );
+       
+       // Start the query.
+       
+       err = DNSServiceQueryRecord( &obj->resolver, 0, 0, name, kDNSServiceDNSType_A, kDNSServiceDNSClass_IN, 
+               QueryRecordCallback, obj );
+       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->resolver )
+       {
+               DNSServiceRefDeallocate( inRef->resolver );
+               inRef->resolver = 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->dataEvent )
+       {
+               ok = CloseHandle( inRef->dataEvent );
+               check_translated_errno( ok, GetLastError(), WSAEINVAL );
+       }
+       if( inRef->querySet )
+       {
+               free( inRef->querySet );
+       }
+       free( inRef );
+       err = NO_ERROR;
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     QueryRecordCallback
+//===========================================================================================================================
+
+DEBUG_LOCAL void CALLBACK_COMPAT
+       QueryRecordCallback(
+               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   == kDNSServiceDNSClass_IN, exit );
+       require( inRRType    == kDNSServiceDNSType_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->addr, inRData, inRDataSize );
+       obj->addrValid = true;
+       
+       // Signal that a result is ready.
+       
+       check( obj->dataEvent );
+       ok = SetEvent( obj->dataEvent );
+       check_translated_errno( ok, GetLastError(), WSAEINVAL );
+       
+       // Stop the resolver after the first response.
+       
+       DNSServiceRefDeallocate( inRef );
+       obj->resolver = NULL;
+
+exit:
+       NSPUnlock();
+}
+
+#if 0
+#pragma mark -
+#endif
+
+//===========================================================================================================================
+//     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->addrValid )
+       {
+               struct sockaddr_in *            addr;
+               
+               outQuerySet->dwNumberOfCsAddrs                                                          = 1;
+               outQuerySet->lpcsaBuffer                                                                        = (LPCSADDR_INFO) dst;
+               dst                                                                                                        += sizeof( *outQuerySet->lpcsaBuffer );
+               
+               outQuerySet->lpcsaBuffer[ 0 ].LocalAddr.lpSockaddr                      = NULL;
+               outQuerySet->lpcsaBuffer[ 0 ].LocalAddr.iSockaddrLength         = 0;
+               
+               outQuerySet->lpcsaBuffer[ 0 ].RemoteAddr.lpSockaddr             = (LPSOCKADDR) dst;
+               outQuerySet->lpcsaBuffer[ 0 ].RemoteAddr.iSockaddrLength        = sizeof( struct sockaddr_in );
+               
+               addr                                                                                                            = (struct sockaddr_in *) dst;
+               memset( addr, 0, sizeof( *addr ) );
+               addr->sin_family                                                                                        = AF_INET;
+               memcpy( &addr->sin_addr, &inRef->addr, 4 );
+               dst                                                                                                        += sizeof( *addr );
+               
+               outQuerySet->lpcsaBuffer[ 0 ].iSocketType                                       = AF_INET;              // Emulate Tcpip NSP
+               outQuerySet->lpcsaBuffer[ 0 ].iProtocol                                         = IPPROTO_UDP;  // Emulate Tcpip NSP
+       }
+       else
+       {
+               outQuerySet->dwNumberOfCsAddrs  = 0;
+               outQuerySet->lpcsaBuffer                = NULL;
+       }
+       
+       // Copy the hostent blob.
+       
+       if( ( inQuerySetFlags & LUP_RETURN_BLOB ) && inRef->addrValid )
+       {
+               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->addr;
+               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->addrValid )
+       {
+               size += sizeof( *inQuerySet->lpcsaBuffer );
+               size += sizeof( struct sockaddr_in );
+       }
+       
+       // Calculate the size of the hostent blob.
+       
+       if( ( inQuerySetFlags & LUP_RETURN_BLOB ) && inRef->addrValid )
+       {
+               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
diff --git a/mDNSWindows/Applications/mdnsNSP/NSP.def b/mDNSWindows/Applications/mdnsNSP/NSP.def
new file mode 100644 (file)
index 0000000..3428a50
--- /dev/null
@@ -0,0 +1,36 @@
+;
+; Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
+;
+; @APPLE_LICENSE_HEADER_START@
+; 
+; This file contains Original Code and/or Modifications of Original Code
+; as defined in and that are subject to the Apple Public Source License
+; Version 2.0 (the 'License'). You may not use this file except in
+; compliance with the License. Please obtain a copy of the License at
+; http://www.opensource.apple.com/apsl/ and read it before using this
+; file.
+; 
+; The Original Code and all software distributed under the License are
+; distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+; EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+; INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+; FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+; Please see the License for the specific language governing rights and
+; limitations under the License.
+; 
+; @APPLE_LICENSE_HEADER_END@
+;
+;      Change History (most recent first):
+;    
+; $Log: NSP.def,v $
+; Revision 1.1  2004/01/30 03:00:33  bradley
+; Rendezvous NameSpace Provider (NSP). Hooks into the Windows name resolution system to resolve
+; Rendezvous name lookups using Multicast DNS so .local names work in all Windows apps.
+;
+;
+
+LIBRARY                RendezvousNSP
+
+EXPORTS
+       NSPStartup
+       NSPCleanup
diff --git a/mDNSWindows/Applications/mdnsNSP/NSP.mcp b/mDNSWindows/Applications/mdnsNSP/NSP.mcp
new file mode 100644 (file)
index 0000000..96007ec
Binary files /dev/null and b/mDNSWindows/Applications/mdnsNSP/NSP.mcp differ
diff --git a/mDNSWindows/Applications/mdnsNSP/Prefix.h b/mDNSWindows/Applications/mdnsNSP/Prefix.h
new file mode 100644 (file)
index 0000000..b1b7369
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+    
+$Log: Prefix.h,v $
+Revision 1.1  2004/01/30 03:00:33  bradley
+Rendezvous NameSpace Provider (NSP). Hooks into the Windows name resolution system to resolve
+Rendezvous name lookups using Multicast DNS so .local names work in all Windows apps.
+
+*/
+
+#ifndef __PREFIX__
+#define __PREFIX__
+
+#if( defined( _DEBUG ) )
+       #define DEBUG                                           1
+       #define DNS_SD_DIRECT_ENABLED           0
+#else
+       #define DEBUG                                           0
+       #define DNS_SD_DIRECT_ENABLED           0
+#endif
+
+#endif // __PREFIX__
diff --git a/mDNSWindows/Applications/mdnsNSP/ReadMe.txt b/mDNSWindows/Applications/mdnsNSP/ReadMe.txt
new file mode 100644 (file)
index 0000000..86de247
--- /dev/null
@@ -0,0 +1,15 @@
+The Rendezvous NSP 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 Rendezvous. For example, when the Rendezvous NSP is installed, you can type "http://computer.local./" in Internet Explorer and it will resolve "computer.local." using Rendezvous and go to the web site (assuming you have a computer named "computer" on the local network and advertised via Rendezvous).
+
+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 Rendezvous NSP, you can use the NSPTool (sources for it are provided along with the Rendezvous NSP) with the following line from the DOS command line prompt ("<path>" is the actual parent path of the DLL):
+
+NSPTool -install "RendezvousNSP" "B600E6E9-553B-4a19-8696-335E5C896153" "<path>"
+
+You can remove remove the Rendezvous NSP 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/Applications/mdnsNSP/mdnsNSP.c b/mDNSWindows/Applications/mdnsNSP/mdnsNSP.c
new file mode 100644 (file)
index 0000000..71fa70e
--- /dev/null
@@ -0,0 +1,1367 @@
+/*
+ * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+    
+$Log: mdnsNSP.c,v $
+Revision 1.2  2004/04/08 09:43:43  bradley
+Changed callback calling conventions to __stdcall so they can be used with C# delegates.
+
+Revision 1.1  2004/01/30 03:00:33  bradley
+Rendezvous NameSpace Provider (NSP). Hooks into the Windows name resolution system to resolve
+Rendezvous name lookups using Multicast DNS so .local names work in all Windows apps.
+
+*/
+
+#include       <stdio.h>
+#include       <stdlib.h>
+#include       <string.h>
+
+#include       "CommonServices.h"
+#include       "DebugServices.h"
+
+#include       <guiddef.h>
+#include       <ws2spi.h>
+
+#include       "DNSSD.h"
+
+#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                          dataEvent;
+       HANDLE                          cancelEvent;
+       HANDLE                          waitHandles[ 2 ];
+       DWORD                           waitCount;
+       DNSServiceRef           resolver;
+       char                            name[ kDNSServiceMaxDomainName ];
+       size_t                          nameSize;
+       uint32_t                        addr;
+       bool                            addrValid;
+};
+
+#if 0
+#pragma mark == Prototypes ==
+#endif
+
+//===========================================================================================================================
+//     Prototypes
+//===========================================================================================================================
+
+// DLL Exports
+
+BOOL WINAPI            DllMain( HINSTANCE inInstance, DWORD inReason, LPVOID inReserved );
+
+// 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
+       QueryRecordCallback(
+               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
+
+#if 0
+#pragma mark == Globals ==
+#endif
+
+//===========================================================================================================================
+//     Globals
+//===========================================================================================================================
+
+// {B600E6E9-553B-4a19-8696-335E5C896153}
+// GUID                kRendezvousNSPGUID = { 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 bool                                       gDNSSDInitialized       = false;
+DEBUG_LOCAL QueryRef                           gQueryList                      = 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:                        
+                       debug_initialize( kDebugOutputTypeWindowsEventLog, "Rendezvous NSP", inInstance );
+                       debug_set_property( kDebugPropertyTagPrintLevel, kDebugLevelInfo );
+                       dlog( kDebugLevelTrace, "\n" );
+                       dlog( kDebugLevelVerbose, "%s: process attach\n", __ROUTINE__ );
+                       break;
+               
+               case DLL_PROCESS_DETACH:
+                       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 );
+}
+
+//===========================================================================================================================
+//     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;
+       
+       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();
+       }
+       
+       // Shut down DNS-SD and release our resources.
+       
+       if( gDNSSDInitialized )
+       {
+               gDNSSDInitialized = false;
+               DNSServiceFinalize();
+       }
+       if( gLockInitialized )
+       {
+               gLockInitialized = false;
+               DeleteCriticalSection( &gLock );
+       }
+       
+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_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 );
+       require_action_quiet( ( ( 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' ) ) ), 
+                                                 exit, err = WSASERVICE_NOT_FOUND );
+       
+       // The name ends in .local so start the resolve operation. Lazy initialize DNS-SD if needed.
+               
+       NSPLock();
+       if( !gDNSSDInitialized )
+       {
+               err = DNSServiceInitialize( kDNSServiceInitializeFlagsNoServerCheck, 0 );
+               require_noerr( err, exit );
+               gDNSSDInitialized = true;
+       }
+       
+       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 )
+{
+       OSStatus                err;
+       QueryRef                obj;
+       DWORD                   waitResult;
+       size_t                  size;
+       
+       DEBUG_USE_ONLY( inFlags );
+       
+       dlog( kDebugLevelTrace, "%s begin (ticks=%d)\n", __ROUTINE__, GetTickCount() );
+       
+       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, 5 * 1000 );
+       NSPLock();
+       require_action_quiet( waitResult != ( WAIT_OBJECT_0 + 1 ), exit, err = WSA_E_CANCELLED );
+       err = translate_errno( waitResult == WAIT_OBJECT_0, (OSStatus) GetLastError(), WSASERVICE_NOT_FOUND );
+       require_noerr_quiet( err, exit );
+       require_action_quiet( obj->addrValid, 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->addrValid = 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;
+       
+       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 events to signal when data is ready and when cancelling.
+       
+       obj->dataEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
+       require_action( obj->dataEvent, exit, err = WSA_NOT_ENOUGH_MEMORY );
+       
+       obj->cancelEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
+       require_action( obj->cancelEvent, exit, err = WSA_NOT_ENOUGH_MEMORY );
+       
+       obj->waitCount = 0;
+       obj->waitHandles[ obj->waitCount++ ] = obj->dataEvent;
+       obj->waitHandles[ obj->waitCount++ ] = obj->cancelEvent;
+       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 );
+       
+       // Start the query.
+       
+       err = DNSServiceQueryRecord( &obj->resolver, 0, 0, name, kDNSServiceDNSType_A, kDNSServiceDNSClass_IN, 
+               QueryRecordCallback, obj );
+       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->resolver )
+       {
+               DNSServiceRefDeallocate( inRef->resolver );
+               inRef->resolver = 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->dataEvent )
+       {
+               ok = CloseHandle( inRef->dataEvent );
+               check_translated_errno( ok, GetLastError(), WSAEINVAL );
+       }
+       if( inRef->querySet )
+       {
+               free( inRef->querySet );
+       }
+       free( inRef );
+       err = NO_ERROR;
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     QueryRecordCallback
+//===========================================================================================================================
+
+DEBUG_LOCAL void CALLBACK_COMPAT
+       QueryRecordCallback(
+               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   == kDNSServiceDNSClass_IN, exit );
+       require( inRRType    == kDNSServiceDNSType_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->addr, inRData, inRDataSize );
+       obj->addrValid = true;
+       
+       // Signal that a result is ready.
+       
+       check( obj->dataEvent );
+       ok = SetEvent( obj->dataEvent );
+       check_translated_errno( ok, GetLastError(), WSAEINVAL );
+       
+       // Stop the resolver after the first response.
+       
+       DNSServiceRefDeallocate( inRef );
+       obj->resolver = NULL;
+
+exit:
+       NSPUnlock();
+}
+
+#if 0
+#pragma mark -
+#endif
+
+//===========================================================================================================================
+//     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->addrValid )
+       {
+               struct sockaddr_in *            addr;
+               
+               outQuerySet->dwNumberOfCsAddrs                                                          = 1;
+               outQuerySet->lpcsaBuffer                                                                        = (LPCSADDR_INFO) dst;
+               dst                                                                                                        += sizeof( *outQuerySet->lpcsaBuffer );
+               
+               outQuerySet->lpcsaBuffer[ 0 ].LocalAddr.lpSockaddr                      = NULL;
+               outQuerySet->lpcsaBuffer[ 0 ].LocalAddr.iSockaddrLength         = 0;
+               
+               outQuerySet->lpcsaBuffer[ 0 ].RemoteAddr.lpSockaddr             = (LPSOCKADDR) dst;
+               outQuerySet->lpcsaBuffer[ 0 ].RemoteAddr.iSockaddrLength        = sizeof( struct sockaddr_in );
+               
+               addr                                                                                                            = (struct sockaddr_in *) dst;
+               memset( addr, 0, sizeof( *addr ) );
+               addr->sin_family                                                                                        = AF_INET;
+               memcpy( &addr->sin_addr, &inRef->addr, 4 );
+               dst                                                                                                        += sizeof( *addr );
+               
+               outQuerySet->lpcsaBuffer[ 0 ].iSocketType                                       = AF_INET;              // Emulate Tcpip NSP
+               outQuerySet->lpcsaBuffer[ 0 ].iProtocol                                         = IPPROTO_UDP;  // Emulate Tcpip NSP
+       }
+       else
+       {
+               outQuerySet->dwNumberOfCsAddrs  = 0;
+               outQuerySet->lpcsaBuffer                = NULL;
+       }
+       
+       // Copy the hostent blob.
+       
+       if( ( inQuerySetFlags & LUP_RETURN_BLOB ) && inRef->addrValid )
+       {
+               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->addr;
+               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->addrValid )
+       {
+               size += sizeof( *inQuerySet->lpcsaBuffer );
+               size += sizeof( struct sockaddr_in );
+       }
+       
+       // Calculate the size of the hostent blob.
+       
+       if( ( inQuerySetFlags & LUP_RETURN_BLOB ) && inRef->addrValid )
+       {
+               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
diff --git a/mDNSWindows/Applications/mdnsNSP/mdnsNSP.def b/mDNSWindows/Applications/mdnsNSP/mdnsNSP.def
new file mode 100644 (file)
index 0000000..948f863
--- /dev/null
@@ -0,0 +1,36 @@
+;
+; Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
+;
+; @APPLE_LICENSE_HEADER_START@
+; 
+; This file contains Original Code and/or Modifications of Original Code
+; as defined in and that are subject to the Apple Public Source License
+; Version 2.0 (the 'License'). You may not use this file except in
+; compliance with the License. Please obtain a copy of the License at
+; http://www.opensource.apple.com/apsl/ and read it before using this
+; file.
+; 
+; The Original Code and all software distributed under the License are
+; distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+; EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+; INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+; FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+; Please see the License for the specific language governing rights and
+; limitations under the License.
+; 
+; @APPLE_LICENSE_HEADER_END@
+;
+;      Change History (most recent first):
+;    
+; $Log: mdnsNSP.def,v $
+; Revision 1.1  2004/01/30 03:00:33  bradley
+; Rendezvous NameSpace Provider (NSP). Hooks into the Windows name resolution system to resolve
+; Rendezvous name lookups using Multicast DNS so .local names work in all Windows apps.
+;
+;
+
+LIBRARY                RendezvousNSP
+
+EXPORTS
+       NSPStartup
+       NSPCleanup
diff --git a/mDNSWindows/Applications/mdnsNSP/mdnsNSP.mcp b/mDNSWindows/Applications/mdnsNSP/mdnsNSP.mcp
new file mode 100644 (file)
index 0000000..96007ec
Binary files /dev/null and b/mDNSWindows/Applications/mdnsNSP/mdnsNSP.mcp differ
diff --git a/mDNSWindows/CommonServices.h b/mDNSWindows/CommonServices.h
new file mode 100644 (file)
index 0000000..2c00724
--- /dev/null
@@ -0,0 +1,1509 @@
+/*
+ * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+    
+$Log: CommonServices.h,v $
+Revision 1.3  2004/04/08 09:27:12  bradley
+Added macro for portable specification of callback calling conventions.
+
+Revision 1.2  2004/03/07 05:53:39  bradley
+Fixed NumVersion extraction macros. Updated error code mappings to match latest internal version.
+
+Revision 1.1  2004/01/30 02:25:59  bradley
+Common Services and portability support for various platforms.
+
+*/
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @header         CommonServices
+       
+       Common Services for Mac OS X, Linux, Palm, VxWorks, Windows, and Windows CE.
+*/
+
+#ifndef        __COMMON_SERVICES__
+#define        __COMMON_SERVICES__
+
+#ifdef __cplusplus
+       extern "C" {
+#endif
+
+#if 0
+#pragma mark == Target ==
+#endif
+
+//===========================================================================================================================
+//      Target
+//===========================================================================================================================
+
+// Macintosh
+
+#if( !defined( TARGET_OS_MAC ) )
+       #if( ( macintosh || __MACH__ ) && !KERNEL )
+               // ConditionalMacros.h in CoreServices will define this TARGET_* flag.
+       #else
+               #define TARGET_OS_MAC                   0
+       #endif
+#endif
+
+#if( !defined( TARGET_API_MAC_OSX_KERNEL ) )
+       #if( __MACH__ && KERNEL )
+               #define TARGET_API_MAC_OSX_KERNEL               1
+       #else
+               #define TARGET_API_MAC_OSX_KERNEL               0
+       #endif
+#endif
+
+// Linux
+
+#if( !defined( TARGET_OS_LINUX ) )
+       #if( defined( __linux__ ) )
+               #define TARGET_OS_LINUX                 1
+       #else
+               #define TARGET_OS_LINUX                 0
+       #endif
+#endif
+
+// Palm
+
+#if( !defined( TARGET_OS_PALM ) )
+       #if( defined( __PALMOS_TRAPS__ ) || defined( __PALMOS_ARMLET__ ) )
+               #define TARGET_OS_PALM                  1
+       #else
+               #define TARGET_OS_PALM                  0
+       #endif
+#endif
+
+// VxWorks
+
+#if( !defined( TARGET_OS_VXWORKS ) )
+       
+       // No predefined macro for VxWorks so just assume VxWorks if nothing else is set.
+       
+       #if( !macintosh && !__MACH__  && !defined( __linux__ ) && !defined( __PALMOS_TRAPS__ ) && !defined( __PALMOS_ARMLET__ ) && !defined( _WIN32 ) )
+               #define TARGET_OS_VXWORKS               1
+       #else
+               #define TARGET_OS_VXWORKS               0
+       #endif
+#endif
+
+// Windows
+
+#if( !defined( TARGET_OS_WIN32 ) )
+       #if( macintosh || __MACH__ )
+               // ConditionalMacros.h in CoreServices will define this TARGET_* flag.
+       #else                   
+               #if( defined( _WIN32 ) )
+                       #define TARGET_OS_WIN32         1
+               #else
+                       #define TARGET_OS_WIN32         0
+               #endif
+       #endif
+#endif
+
+// Windows CE
+
+#if( !defined( TARGET_OS_WINDOWS_CE ) )
+       #if( defined( _WIN32_WCE ) )
+               #define TARGET_OS_WINDOWS_CE    1
+       #else
+               #define TARGET_OS_WINDOWS_CE    0
+       #endif
+#endif
+
+#if 0
+#pragma mark == Includes ==
+#endif
+
+//===========================================================================================================================
+//      Includes
+//===========================================================================================================================
+
+#if( !KERNEL )
+       #include        <stddef.h>
+#endif
+       
+#if( ( macintosh || __MACH__ ) && !KERNEL )
+               
+       #if( defined( __MWERKS__ ) )
+               #if( __option( c9x ) )
+                       #include        <stdbool.h>
+               #endif
+       #else
+               #include        <stdbool.h>
+       #endif
+       
+       #include        <stdint.h>
+       
+       #if( __MACH__ )
+               
+               // Mac OS X
+               
+               #include        <sys/types.h>
+               #include        <netinet/in.h>
+               #include        <arpa/inet.h>
+               #include        <fcntl.h>
+               #include        <pthread.h>
+               #include        <sys/ioctl.h>
+               #include        <sys/socket.h>
+               #include        <unistd.h>
+               
+               #include        <CoreServices/CoreServices.h>
+       
+       #else
+               
+               // Classic Mac OS
+               
+               #include        <ConditionalMacros.h>
+               #include        <MacTypes.h>
+       
+       #endif
+       
+#elif( KERNEL )
+       
+       // Mac OS X Kernel
+       
+       #include        <stdint.h>
+       
+       #include        <libkern/OSTypes.h>
+       #include        <sys/types.h>
+       
+#elif( TARGET_OS_LINUX )
+       
+       // Linux (no special includes yet).
+
+#elif( TARGET_OS_PALM )
+       
+       // Palm (no special includes yet).
+
+#elif( TARGET_OS_VXWORKS )
+       
+       // VxWorks
+       
+       #include        "vxWorks.h"
+       
+#elif( TARGET_OS_WIN32 )
+       
+       // Windows
+       
+       #if( !defined( WIN32_WINDOWS ) )
+               #define WIN32_WINDOWS           0x0401
+       #endif
+       
+       #if( !defined( _WIN32_WINDOWS ) )
+               #define _WIN32_WINDOWS          0x0401
+       #endif
+       
+       #if( !defined( WIN32_LEAN_AND_MEAN ) )
+               #define WIN32_LEAN_AND_MEAN                     // Needed to avoid redefinitions by Windows interfaces.
+       #endif
+       
+       #if( defined( __MWERKS__ ) )
+       
+               #if( __option( c9x ) )
+                       #include        <stdbool.h>
+               #endif
+               
+               #include        <stdint.h>
+               
+       #elif( defined( _MSC_VER ) )
+       
+               #pragma warning( disable:4127 )         // Disable "conditional expression is constant" warning for debug macros.
+               #pragma warning( disable:4706 )         // Disable "assignment within conditional expression" for Microsoft headers.
+               
+       #endif
+
+       #include        <windows.h>
+       #include        <winsock2.h>
+       #include        <Ws2tcpip.h>
+       
+       #if( defined( _MSC_VER ) )
+               #pragma warning( default:4706 )
+       #endif
+       
+#else
+       #error unknown OS - update this file to support your OS
+#endif
+
+#if( !defined( TARGET_BUILD_MAIN ) )
+       #if( !TARGET_OS_VXWORKS )
+               #define TARGET_BUILD_MAIN               1
+       #endif
+#endif
+
+#if( __GNUC__ || !TARGET_OS_VXWORKS )
+       #define TARGET_LANGUAGE_C_LIKE          1
+#else
+       #define TARGET_LANGUAGE_C_LIKE          0
+#endif
+
+#if 0
+#pragma mark == CPU ==
+#endif
+
+//===========================================================================================================================
+//     CPU
+//===========================================================================================================================
+
+// PowerPC
+
+#if( !defined( TARGET_CPU_PPC ) )
+       #if( defined( __ppc__ ) || defined( __PPC__ ) || defined( powerpc ) || defined( ppc ) || defined( _M_MPPC ) )
+               #define TARGET_CPU_PPC                          1
+       #else
+               #define TARGET_CPU_PPC                          0
+       #endif
+#endif
+
+// x86
+
+#if( !defined( TARGET_CPU_X86 ) )
+       #if( __INTEL__ || defined( __i386__ ) || defined( i386 ) || defined( intel ) || defined( _M_IX86 ) )
+               #define TARGET_CPU_X86                          1
+       #else
+               #define TARGET_CPU_X86                          0
+       #endif
+#endif
+
+// MIPS
+
+#if( !defined( TARGET_CPU_MIPS ) )
+       #if( __MIPS__ || defined( MIPS32 ) || defined( R3000 ) || defined( R4000 ) || defined( R4650 ) || defined( _M_MRX000 ) )
+               #define TARGET_CPU_MIPS                         1
+       #else
+               #define TARGET_CPU_MIPS                         0
+       #endif
+#endif
+
+#if( !defined( TARGET_CPU_PPC ) && !defined( TARGET_CPU_X86 ) && !defined( TARGET_CPU_MIPS ) )
+       #error unknown CPU - update this file to support your CPU
+#endif
+
+#if 0
+#pragma mark == Byte Order ==
+#endif
+
+//===========================================================================================================================
+//     Byte Order
+//===========================================================================================================================
+
+// TARGET_RT_LITTLE_ENDIAN
+
+#if( !defined( TARGET_RT_LITTLE_ENDIAN ) )
+       #if( MIPSEL || IL_LITTLE_ENDIAN || defined( __LITTLE_ENDIAN__ )                                                                                 || \
+                ( defined(   BYTE_ORDER ) && defined(   LITTLE_ENDIAN ) && (   BYTE_ORDER ==   LITTLE_ENDIAN ) )       || \
+                ( defined(  _BYTE_ORDER ) && defined(  _LITTLE_ENDIAN ) && (  _BYTE_ORDER ==  _LITTLE_ENDIAN ) )       || \
+                ( defined( __BYTE_ORDER ) && defined( __LITTLE_ENDIAN ) && ( __BYTE_ORDER == __LITTLE_ENDIAN ) )       || \
+                TARGET_CPU_X86 || ( defined( TARGET_RT_BIG_ENDIAN ) && !TARGET_RT_BIG_ENDIAN ) )
+               #define TARGET_RT_LITTLE_ENDIAN         1
+       #else
+               #define TARGET_RT_LITTLE_ENDIAN         0
+       #endif
+#endif
+
+// TARGET_RT_BIG_ENDIAN
+
+#if( !defined( TARGET_RT_BIG_ENDIAN ) )
+       #if( MIPSEB || IL_BIG_ENDIAN || defined( __BIG_ENDIAN__ )                                                                               || \
+                ( defined(   BYTE_ORDER ) && defined(   BIG_ENDIAN ) && (   BYTE_ORDER ==   BIG_ENDIAN ) )     || \
+                ( defined(  _BYTE_ORDER ) && defined(  _BIG_ENDIAN ) && (  _BYTE_ORDER ==  _BIG_ENDIAN ) )     || \
+                ( defined( __BYTE_ORDER ) && defined( __BIG_ENDIAN ) && ( __BYTE_ORDER == __BIG_ENDIAN ) )     || \
+               ( defined( TARGET_RT_LITTLE_ENDIAN ) && !TARGET_RT_LITTLE_ENDIAN ) )
+               #define TARGET_RT_BIG_ENDIAN            1
+       #else
+               #define TARGET_RT_BIG_ENDIAN            0
+       #endif
+#endif
+
+#if( defined( TARGET_RT_LITTLE_ENDIAN ) && !defined( TARGET_RT_BIG_ENDIAN ) )
+       #if( TARGET_RT_LITTLE_ENDIAN )
+               #define TARGET_RT_BIG_ENDIAN            0
+       #else
+               #define TARGET_RT_BIG_ENDIAN            1
+       #endif
+#endif
+
+#if( defined( TARGET_RT_BIG_ENDIAN ) && !defined( TARGET_RT_LITTLE_ENDIAN ) )
+       #if( TARGET_RT_BIG_ENDIAN )
+               #define TARGET_RT_LITTLE_ENDIAN         0
+       #else
+               #define TARGET_RT_LITTLE_ENDIAN         1
+       #endif
+#endif
+
+#if( !defined( TARGET_RT_LITTLE_ENDIAN ) || !defined( TARGET_RT_BIG_ENDIAN ) )
+       #error unknown byte order - update this file to support your byte order
+#endif
+
+// TARGET_RT_BYTE_ORDER
+
+#if( !defined( TARGET_RT_BYTE_ORDER_BIG_ENDIAN ) )
+       #define TARGET_RT_BYTE_ORDER_BIG_ENDIAN                 1234
+#endif
+
+#if( !defined( TARGET_RT_BYTE_ORDER_LITTLE_ENDIAN ) )
+       #define TARGET_RT_BYTE_ORDER_LITTLE_ENDIAN              4321
+#endif
+
+#if( !defined( TARGET_RT_BYTE_ORDER ) )
+       #if( TARGET_RT_LITTLE_ENDIAN )
+               #define TARGET_RT_BYTE_ORDER                            TARGET_RT_BYTE_ORDER_LITTLE_ENDIAN
+       #else
+               #define TARGET_RT_BYTE_ORDER                            TARGET_RT_BYTE_ORDER_BIG_ENDIAN
+       #endif
+#endif
+
+#if 0
+#pragma mark == Constants ==
+#endif
+
+//===========================================================================================================================
+//     Constants
+//===========================================================================================================================
+
+#if( !TARGET_OS_MAC )
+       #define CR              '\r'
+#endif
+
+#define LF                     '\n'
+#define        CRSTR           "\r"
+#define        LFSTR           "\n"
+#define CRLF           "\r\n"
+#define CRCR           "\r\r"
+
+#if 0
+#pragma mark == Compatibility ==
+#endif
+
+//===========================================================================================================================
+//     Compatibility
+//===========================================================================================================================
+
+// Macros to allow the same code to work on Windows and other sockets API-compatible platforms.
+
+#if( TARGET_OS_WIN32 )
+       #define close_compat( X )               closesocket( X )
+       #define errno_compat()                  (int) GetLastError()
+       #define set_errno_compat( X )   SetLastError( X )
+       #define EWOULDBLOCK_compat              WSAEWOULDBLOCK
+       #define ETIMEDOUT_compat                WSAETIMEDOUT
+       #define ENOTCONN_compat                 WSAENOTCONN
+       #define IsValidSocket( X )              ( ( X ) != INVALID_SOCKET )
+       #define kInvalidSocketRef               INVALID_SOCKET
+       #if( TARGET_LANGUAGE_C_LIKE )
+               typedef SOCKET                          SocketRef;
+       #endif
+#else
+       #define close_compat( X )               close( X )
+       #define errno_compat()                  errno
+       #define set_errno_compat( X )   do { errno = ( X ); } while( 0 )
+       #define EWOULDBLOCK_compat              EWOULDBLOCK
+       #define ETIMEDOUT_compat                ETIMEDOUT
+       #define ENOTCONN_compat                 ENOTCONN
+       #define IsValidSocket( X )              ( ( X ) >= 0 )
+       #define kInvalidSocketRef               -1
+       #if( TARGET_LANGUAGE_C_LIKE )
+               typedef int                                     SocketRef;
+       #endif
+#endif
+
+// socklen_t is not defined on the following platforms so emulate it if not defined:
+// 
+// - Pre-Panther Mac OS X. Panther defines SO_NOADDRERR so trigger off that.
+// - Windows SDK prior to 2003. 2003+ SDK's define EAI_AGAIN so trigger off that.
+// - VxWorks
+
+#if( TARGET_LANGUAGE_C_LIKE )
+       #if( ( TARGET_OS_MAC && !defined( SO_NOADDRERR ) ) || ( TARGET_OS_WIN32 && !defined( EAI_AGAIN ) ) || TARGET_OS_VXWORKS )
+               typedef int                                             socklen_t;
+       #endif
+#endif
+
+// ssize_t is not defined on the following platforms so emulate it if not defined:
+// 
+// - Mac OS X when not building with BSD headers
+// - Windows
+
+#if( TARGET_LANGUAGE_C_LIKE )
+       #if( ( TARGET_OS_WIN32 || !defined( _BSD_SSIZE_T_DEFINED_ ) ) && !TARGET_OS_VXWORKS )
+               typedef int                                             ssize_t;
+       #endif
+#endif
+
+// sockaddr_storage is not supported on non-IPv6 machines so alias it to an IPv4-compatible structure.
+
+#if( TARGET_LANGUAGE_C_LIKE )
+       #if( !defined( AF_INET6 ) )
+               #define sockaddr_storage                sockaddr_in
+               #define ss_family                               sin_family
+       #endif
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        SOCKADDR_IS_IP_LOOPBACK
+       
+       @abstract       Determines if a sockaddr is an IPv4 or IPv6 loopback address (if IPv6 is supported).
+*/
+
+#if( defined( AF_INET6 ) )
+       #define SOCKADDR_IS_IP_LOOPBACK( SA )                                                                                                                   \
+               ( ( (const struct sockaddr *)( SA ) )->sa_family == AF_INET )                                                           \
+               ? ( ( (const struct sockaddr_in *)( SA ) )->sin_addr.s_addr == htonl( INADDR_LOOPBACK ) )       \
+               : ( ( (const struct sockaddr *)( SA ) )->sa_family == AF_INET6 )                                                        \
+                       ? IN6_IS_ADDR_LOOPBACK( &( (const struct sockaddr_in6 *)( SA ) )->sin6_addr )                   \
+                       : 0
+#else
+       #define SOCKADDR_IS_IP_LOOPBACK( SA )                                                                                                                   \
+               ( ( (const struct sockaddr *)( SA ) )->sa_family == AF_INET )                                                           \
+               ? ( ( (const struct sockaddr_in *)( SA ) )->sin_addr.s_addr == htonl( INADDR_LOOPBACK ) )       \
+               : 0
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        SOCKADDR_IS_IP_LINK_LOCAL
+       
+       @abstract       Determines if a sockaddr is an IPv4 or IPv6 link-local address (if IPv6 is supported).
+*/
+
+#if( defined( AF_INET6 ) )
+       #define SOCKADDR_IS_IP_LINK_LOCAL( SA )                                                                                                                         \
+               ( ( ( (const struct sockaddr *)( SA ) )->sa_family == AF_INET )                                                                 \
+                 ? ( ( ( (uint8_t *)( &( (const struct sockaddr_in *)( SA ) )->sin_addr ) )[ 0 ] == 169 ) &&   \
+                         ( ( (uint8_t *)( &( (const struct sockaddr_in *)( SA ) )->sin_addr ) )[ 1 ] == 254 ) )        \
+                 : IN6_IS_ADDR_LOOPBACK( &( (const struct sockaddr_in6 *)( SA ) )->sin6_addr ) )
+#else
+       #define SOCKADDR_IS_IP_LINK_LOCAL( SA )                                                                                                                         \
+               ( ( ( (const struct sockaddr *)( SA ) )->sa_family == AF_INET )                                                                 \
+                 ? ( ( ( (uint8_t *)( &( (const struct sockaddr_in *)( SA ) )->sin_addr ) )[ 0 ] == 169 ) &&   \
+                         ( ( (uint8_t *)( &( (const struct sockaddr_in *)( SA ) )->sin_addr ) )[ 1 ] == 254 ) )        \
+                 : 0 )
+#endif
+
+// _beginthreadex and _endthreadex are not supported on Windows CE 2.1 or later (the C runtime issues with leaking 
+// resources have apparently been resolved and they seem to have just ripped out support for the API) so map it to 
+// CreateThread on Windows CE.
+
+#if( TARGET_OS_WINDOWS_CE )
+       #define _beginthreadex_compat( SECURITY_PTR, STACK_SIZE, START_ADDRESS, ARG_LIST, FLAGS, THREAD_ID_PTR )                        \
+               (uintptr_t) CreateThread( SECURITY_PTR, STACK_SIZE, (LPTHREAD_START_ROUTINE) START_ADDRESS, ARG_LIST, FLAGS,    \
+                                         (LPDWORD) THREAD_ID_PTR )
+       
+       #define _endthreadex_compat( RESULT )           ExitThread( (DWORD) RESULT )
+#elif( TARGET_OS_WIN32 )
+       #define _beginthreadex_compat                           _beginthreadex
+       #define _endthreadex_compat                                     _endthreadex
+#endif
+
+// The C99 "inline" keyword is not supported by Microsoft compilers, but they do support __inline so map it when needed.
+
+#if( defined( _MSC_VER ) )
+       #define inline_compat           __inline
+#else
+       #define inline_compat           inline
+#endif
+
+// Calling conventions 
+
+#if( !defined( CALLBACK_COMPAT ) )
+       #if( TARGET_OS_WIN32 || TARGET_OS_WINDOWS_CE )
+               #define CALLBACK_COMPAT         CALLBACK
+       #else
+               #define CALLBACK_COMPAT
+       #endif
+#endif
+
+#if 0
+#pragma mark == Macros ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        kSizeCString
+
+       @abstract       A meta-value to pass to supported routines to indicate the size should be calculated with strlen.
+*/
+
+#define        kSizeCString            ( (size_t) -1 )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        sizeof_array
+       
+       @abstract       Determines the number of elements in an array.
+*/
+
+#define        sizeof_array( X )               ( sizeof( X ) / sizeof( X[ 0 ] ) )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        sizeof_element
+       
+       @abstract       Determines the size of an array element.
+*/
+
+#define        sizeof_element( X )             sizeof( X[ 0 ] )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        sizeof_string
+       
+       @abstract       Determines the size of a constant C string, excluding the null terminator.
+*/
+
+#define        sizeof_string( X )              ( sizeof( ( X ) ) - 1 )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        sizeof_field
+       
+       @abstract       Determines the size of a field of a type.
+*/
+
+#define        sizeof_field( TYPE, FIELD )             sizeof( ( ( (TYPE *) 0 )->FIELD ) )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       RoundUp
+
+       @abstract       Rounds X up to a multiple of Y.
+*/
+
+#define        RoundUp( X, Y )         ( ( X ) + ( ( Y ) - ( ( X ) % ( Y ) ) ) )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       IsAligned
+
+       @abstract       Returns non-zero if X is aligned to a Y byte boundary and 0 if not. Y must be a power of 2.
+*/
+
+#define        IsAligned( X, Y )               ( ( ( X ) & ( ( Y ) - 1 ) ) == 0 )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       IsFieldAligned
+
+       @abstract       Returns non-zero if FIELD of type TYPE is aligned to a Y byte boundary and 0 if not. Y must be a power of 2.
+*/
+
+#define        IsFieldAligned( X, TYPE, FIELD, Y )             IsAligned( ( (uintptr_t)( X ) ) + offsetof( TYPE, FIELD ), ( Y ) )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       AlignDown
+
+       @abstract       Aligns X down to a Y byte boundary. Y must be a power of 2.
+*/
+
+#define        AlignDown( X, Y )               ( ( X ) & ~( ( Y ) - 1 ) )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       AlignUp
+
+       @abstract       Aligns X up to a Y byte boundary. Y must be a power of 2.
+*/
+
+#define        AlignUp( X, Y )         ( ( ( X ) + ( ( Y ) - 1 ) ) & ~( ( Y ) - 1 ) )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       Min
+
+       @abstract       Returns the lesser of X and Y.
+*/
+
+#if( !defined( Min ) )
+       #define Min( X, Y )             ( ( ( X ) < ( Y ) ) ? ( X ) : ( Y ) )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       Max
+
+       @abstract       Returns the greater of X and Y.
+*/
+
+#if( !defined( Max ) )
+       #define Max( X, Y )             ( ( ( X ) > ( Y ) ) ? ( X ) : ( Y ) )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       InsertBits
+
+       @abstract       Inserts BITS (both 0 and 1 bits) into X, controlled by MASK and SHIFT, and returns the result.
+       
+       @discussion
+       
+       MASK is the bitmask of the bits in the final position.
+       SHIFT is the number of bits to shift left for 1 to reach the first bit position of MASK.
+       
+       For example, if you wanted to insert 0x3 into the leftmost 4 bits of a 32-bit value:
+       
+       InsertBits( 0, 0x3, 0xF0000000U, 28 ) == 0x30000000
+*/
+
+#define        InsertBits( X, BITS, MASK, SHIFT )              ( ( ( X ) & ~( MASK ) ) | ( ( ( BITS ) << ( SHIFT ) ) & ( MASK ) ) )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       ExtractBits
+
+       @abstract       Extracts bits from X, controlled by MASK and SHIFT, and returns the result.
+       
+       @discussion
+       
+       MASK is the bitmask of the bits in the final position.
+       SHIFT is the number of bits to shift right to right justify MASK.
+       
+       For example, if you had a 32-bit value (e.g. 0x30000000) wanted the left-most 4 bits (e.g. 3 in this example):
+       
+       ExtractBits( 0x30000000U, 0xF0000000U, 28 ) == 0x3
+*/
+
+#define        ExtractBits( X, MASK, SHIFT )                   ( ( ( X ) >> ( SHIFT ) ) & ( ( MASK ) >> ( SHIFT ) ) )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       Stringify
+
+       @abstract       Stringify's an expression.
+       
+       @discussion
+       
+       Stringify macros to process raw text passed via -D options to C string constants. The double-wrapping is necessary 
+       because the C preprocessor doesn't perform its normal argument expansion pre-scan with stringified macros so the 
+       -D macro needs to be expanded once via the wrapper macro then stringified so the raw text is stringified. Otherwise, 
+       the replacement value would be used instead of the symbolic name (only for preprocessor symbols like #defines).
+       
+       For example:
+       
+               #define kMyConstant             1
+               
+               printf( "%s", Stringify( kMyConstant ) );                       // Prints "kMyConstant"
+               printf( "%s", StringifyExpansion( kMyConstant ) );      // Prints "1"
+               
+       Non-preprocessor symbols do not have this issue. For example:
+       
+               enum
+               {
+                       kMyConstant = 1
+               };
+               
+               printf( "%s", Stringify( kMyConstant ) );                       // Prints "kMyConstant"
+               printf( "%s", StringifyExpansion( kMyConstant ) );      // Prints "kMyConstant"
+       
+       See <http://gcc.gnu.org/onlinedocs/cpp/Argument-Prescan.html> for more info on C preprocessor pre-scanning.
+*/
+
+#define        Stringify( X )                          # X
+#define        StringifyExpansion( X )         Stringify( X )
+
+#if 0
+#pragma mark == Types ==
+#endif
+
+#if( TARGET_LANGUAGE_C_LIKE )
+//===========================================================================================================================
+//      Standard Types
+//===========================================================================================================================
+
+#if( !defined( INT8_MIN ) )
+       
+       #define INT8_MIN                                        SCHAR_MIN
+       
+       #if( defined( _MSC_VER ) )
+
+               // C99 stdint.h not supported in VC++/VS.NET yet.
+
+               typedef INT8                                    int8_t;
+               typedef UINT8                                   uint8_t;
+               typedef INT16                                   int16_t;
+               typedef UINT16                                  uint16_t;
+               typedef INT32                                   int32_t;
+               typedef UINT32                                  uint32_t;
+               typedef __int64                                 int64_t;
+               typedef unsigned __int64                uint64_t;
+               
+       #elif( TARGET_OS_VXWORKS && ( TORNADO_VERSION < 220 ) )
+               typedef long long                               int64_t;
+               typedef unsigned long long              uint64_t;
+       #endif
+       
+       typedef int8_t                                          int_least8_t;
+       typedef int16_t                                         int_least16_t;
+       typedef int32_t                                         int_least32_t;
+       typedef int64_t                                         int_least64_t;
+
+       typedef uint8_t                                         uint_least8_t;
+       typedef uint16_t                                        uint_least16_t;
+       typedef uint32_t                                        uint_least32_t;
+       typedef uint64_t                                        uint_least64_t;
+       
+       typedef int8_t                                          int_fast8_t;
+       typedef int16_t                                         int_fast16_t;
+       typedef int32_t                                         int_fast32_t;
+       typedef int64_t                                         int_fast64_t;
+       
+       typedef uint8_t                                         uint_fast8_t;
+       typedef uint16_t                                        uint_fast16_t;
+       typedef uint32_t                                        uint_fast32_t;
+       typedef uint64_t                                        uint_fast64_t;
+
+       #if( !defined( _MSC_VER ) || TARGET_OS_WINDOWS_CE )
+               typedef long int                                intptr_t;
+               typedef unsigned long int               uintptr_t;
+       #endif
+
+#endif
+
+// Macros for minimum-width integer constants
+
+#if( !defined( INT8_C ) )
+       #define INT8_C( value )                 value
+#endif
+
+#if( !defined( INT16_C ) )
+       #define INT16_C( value )                value
+#endif
+
+#if( !defined( INT32_C ) )
+       #define INT32_C( value )                value ## L
+#endif
+
+#if( !defined( INT64_C ) )
+       #if( defined( _MSC_VER ) )
+               #define INT64_C( value )        value ## i64
+       #else
+               #define INT64_C( value )        value ## LL
+       #endif
+#endif
+
+#if( !defined( UINT8_C ) )
+       #define UINT8_C( value )                value ## U
+#endif
+
+#if( !defined( UINT16_C ) )
+       #define UINT16_C( value )               value ## U
+#endif
+
+#if( !defined( UINT32_C ) )
+       #define UINT32_C( value )               value ## UL
+#endif
+
+#if( !defined( UINT64_C ) )
+       #if( defined( _MSC_VER ) )
+               #define UINT64_C( value )       value ## UI64
+       #else
+               #define UINT64_C( value )       value ## ULL
+       #endif
+#endif
+
+#if 0
+#pragma mark == bool ==
+#endif
+
+//===========================================================================================================================
+//      Boolean Constants and Types
+//===========================================================================================================================
+
+// C++ defines bool, true, and false. Metrowerks allows this to be controlled by the "bool" option though.
+// C99 defines __bool_true_false_are_defined when bool, true, and false are defined.
+// MacTypes.h defines true and false (Mac builds only).
+// 
+// Note: The Metrowerks has to be in its own block because Microsoft Visual Studio .NET does not completely 
+// short-circuit and gets confused by the option( bool ) portion of the conditional.
+
+#if( defined( __MWERKS__ ) )
+       
+       // Note: The following test is done on separate lines because CodeWarrior doesn't like it all on one line.
+       
+       #if( !__bool_true_false_are_defined && ( !defined( __cplusplus ) || !__option( bool ) ) )
+               #define COMMON_SERVICES_NEEDS_BOOL              1
+       #else
+               #define COMMON_SERVICES_NEEDS_BOOL              0
+       #endif
+       
+       // Workaround when building with CodeWarrior, but using the Apple stdbool.h header, which uses _Bool.
+       
+       #if( __bool_true_false_are_defined && !defined( __cplusplus ) && !__option( c9x ) )
+               #define _Bool   int
+       #endif
+       
+       // Workaround when building with CodeWarrior for C++ with bool disabled and using the Apple stdbool.h header, 
+       // which defines true and false to map to C++ true and false (which are not enabled). Serenity Now!
+       
+       #if( __bool_true_false_are_defined && defined( __cplusplus ) && !__option( bool ) )
+               #define true    1
+               #define false   0
+       #endif
+#else
+       #define COMMON_SERVICES_NEEDS_BOOL                      ( !defined( __cplusplus ) && !__bool_true_false_are_defined )
+#endif
+
+#if( COMMON_SERVICES_NEEDS_BOOL )
+       
+       typedef int             bool;
+       
+       #define bool    bool
+       
+       #if( !defined( __MACTYPES__ ) && !defined( true ) && !defined( false ) )
+               #define true    1
+               #define false   0
+       #endif
+       
+       #define __bool_true_false_are_defined           1
+#endif
+
+// IOKit IOTypes.h typedef's bool if TYPE_BOOL is not defined so define it here to prevent redefinition by IOTypes.h.
+
+#if( TARGET_API_MAC_OSX_KERNEL )
+       #define TYPE_BOOL               1
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @typedef        CStr255
+       
+       @abstract       255 character null-terminated (C-style) string.
+*/
+
+#if( TARGET_LANGUAGE_C_LIKE )
+       typedef char    CStr255[ 256 ];
+#endif
+
+#endif // TARGET_LANGUAGE_C_LIKE
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        TYPE_LONGLONG_NATIVE
+
+       @abstract       Defines whether long long (or its equivalent) is natively supported or requires special libraries.
+*/
+
+#if( !defined( TYPE_LONGLONG_NATIVE ) )
+       #if( !TARGET_OS_VXWORKS )
+               #define TYPE_LONGLONG_NATIVE                    1
+       #else
+               #define TYPE_LONGLONG_NATIVE                    0
+       #endif
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        long_long_compat
+
+       @abstract       Compatibility type to map to the closest thing to long long and unsigned long long.
+       
+       @discussion
+       
+       Neither long long nor unsigned long long are supported by Microsoft compilers, but they do support proprietary
+       "__int64" and "unsigned __int64" equivalents so map to those types if the real long long is not supported.
+*/
+
+#if( TARGET_LANGUAGE_C_LIKE )
+       #if( TARGET_OS_WIN32 )
+               typedef __int64                                 long_long_compat;
+               typedef unsigned __int64                unsigned_long_long_compat;
+       #else
+               typedef signed long long                long_long_compat;
+               typedef unsigned long long              unsigned_long_long_compat;
+       #endif
+#endif
+
+#if 0
+#pragma mark == Errors ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @enum           OSStatus
+
+       @abstract       Status Code
+       
+       @constant       kNoErr                                              0 No error occurred.
+       @constant       kInProgressErr                              1 Operation in progress.
+       @constant       kUnknownErr                                     -6700 Unknown error occurred.
+       @constant       kOptionErr                                      -6701 Option was not acceptable.
+       @constant       kSelectorErr                            -6702 Selector passed in is invalid or unknown.
+       @constant       kExecutionStateErr                      -6703 Call made in the wrong execution state (e.g. called at interrupt time).
+       @constant       kPathErr                                        -6704 Path is invalid, too long, or otherwise not usable.
+       @constant       kParamErr                                       -6705 Parameter is incorrect, missing, or not appropriate.
+       @constant       kParamCountErr                          -6706 Incorrect or unsupported number of parameters.
+       @constant       kCommandErr                                     -6707 Command invalid or not supported.
+       @constant       kIDErr                                          -6708 Unknown, invalid, or inappropriate identifier.
+       @constant       kStateErr                                       -6709 Not in appropriate state to perform operation.
+       @constant       kRangeErr                                       -6710 Index is out of range or not valid.
+       @constant       kRequestErr                                     -6711 Request was improperly formed or not appropriate.
+       @constant       kResponseErr                            -6712 Response was incorrect or out of sequence.
+       @constant       kChecksumErr                            -6713 Checksum does not match the actual data.
+       @constant       kNotHandledErr                          -6714 Operation was not handled (or not handled completely).
+       @constant       kVersionErr                                     -6715 Version is not incorrect or not compatibile.
+       @constant       kSignatureErr                           -6716 Signature did not match what was expected.
+       @constant       kFormatErr                                      -6717 Unknown, invalid, or inappropriate file/data format.
+       @constant       kNotInitializedErr                      -6718 Action request before needed services were initialized.
+       @constant       kAlreadyInitializedErr          -6719 Attempt made to initialize when already initialized.
+       @constant       kNotInUseErr                            -6720 Object not in use (e.g. cannot abort if not already in use).
+       @constant       kInUseErr                                       -6721 Object is in use (e.g. cannot reuse active param blocks).
+       @constant       kTimeoutErr                                     -6722 Timeout occurred.
+       @constant       kCanceledErr                            -6723 Operation canceled (successful cancel).
+       @constant       kAlreadyCanceledErr                     -6724 Operation has already been canceled.
+       @constant       kCannotCancelErr                        -6725 Operation could not be canceled (maybe already done or invalid).
+       @constant       kDeletedErr                                     -6726 Object has already been deleted.
+       @constant       kNotFoundErr                            -6727 Something was not found.
+       @constant       kNoMemoryErr                            -6728 Not enough memory was available to perform the operation.
+       @constant       kNoResourcesErr                         -6729 Resources unavailable to perform the operation.
+       @constant       kDuplicateErr                           -6730 Duplicate found or something is a duplicate.
+       @constant       kImmutableErr                           -6731 Entity is not changeable.
+       @constant       kUnsupportedDataErr                     -6732 Data is unknown or not supported.
+       @constant       kIntegrityErr                           -6733 Data is corrupt.
+       @constant       kIncompatibleErr                        -6734 Data is not compatible or it is in an incompatible format.
+       @constant       kUnsupportedErr                         -6735 Feature or option is not supported.
+       @constant       kUnexpectedErr                          -6736 Error occurred that was not expected.
+       @constant       kValueErr                                       -6737 Value is not appropriate.
+       @constant       kNotReadableErr                         -6738 Could not read or reading is not allowed.
+       @constant       kNotWritableErr                         -6739 Could not write or writing is not allowed.
+       @constant       kBadReferenceErr                        -6740 An invalid or inappropriate reference was specified.
+       @constant       kFlagErr                                        -6741 An invalid, inappropriate, or unsupported flag was specified.
+       @constant       kMalformedErr                           -6742 Something was not formed correctly.
+       @constant       kSizeErr                                        -6743 Size was too big, too small, or not appropriate.
+       @constant       kNameErr                                        -6744 Name was not correct, allowed, or appropriate.
+       @constant       kNotReadyErr                            -6745 Device or service is not ready.
+       @constant       kReadErr                                        -6746 Could not read.
+       @constant       kWriteErr                                       -6747 Could not write.
+       @constant       kMismatchErr                            -6748 Something does not match.
+       @constant       kDateErr                                        -6749 Date is invalid or out-of-range.
+       @constant       kUnderrunErr                            -6750 Less data than expected.
+       @constant       kOverrunErr                                     -6751 More data than expected.
+       @constant       kEndingErr                                      -6752 Connection, session, or something is ending.
+       @constant       kConnectionErr                          -6753 Connection failed or could not be established.
+       @constant       kAuthenticationErr                      -6754 Authentication failed or is not supported.
+       @constant       kOpenErr                                        -6755 Could not open file, pipe, device, etc.
+       @constant       kTypeErr                                        -6756 Incorrect or incompatible type (e.g. file, data, etc.).
+       @constant       kSkipErr                                        -6757 Items should be or was skipped.
+       @constant       kNoAckErr                                       -6758 No acknowledge.
+       @constant       kCollisionErr                           -6759 Collision occurred (e.g. two on bus at same time).
+       @constant       kBackoffErr                                     -6760 Backoff in progress and operation intentionally failed.
+       @constant       kNoAddressAckErr                        -6761 No acknowledge of address.
+       @constant       kBusyErr                                        -6762 Cannot perform because something is busy.
+       @constant       kNoSpaceErr                                     -6763 Not enough space to perform operation.
+*/
+
+#if( TARGET_LANGUAGE_C_LIKE )
+       #if( !TARGET_OS_MAC && !TARGET_API_MAC_OSX_KERNEL )
+               typedef int32_t         OSStatus;
+       #endif
+#endif
+
+#define kNoErr                                         0
+#define kInProgressErr                         1
+
+// Generic error codes are in the range -6700 to -6779.
+
+#define kGenericErrorBase                      -6700   // Starting error code for all generic errors.
+       
+#define kUnknownErr                                    -6700
+#define kOptionErr                                     -6701
+#define kSelectorErr                           -6702
+#define kExecutionStateErr                     -6703
+#define kPathErr                                       -6704
+#define kParamErr                                      -6705
+#define kParamCountErr                         -6706
+#define kCommandErr                                    -6707
+#define kIDErr                                         -6708
+#define kStateErr                                      -6709
+#define kRangeErr                                      -6710
+#define kRequestErr                                    -6711
+#define kResponseErr                           -6712
+#define kChecksumErr                           -6713
+#define kNotHandledErr                         -6714
+#define kVersionErr                                    -6715
+#define kSignatureErr                          -6716
+#define kFormatErr                                     -6717
+#define kNotInitializedErr                     -6718
+#define kAlreadyInitializedErr         -6719
+#define kNotInUseErr                           -6720
+#define kInUseErr                                      -6721
+#define kTimeoutErr                                    -6722
+#define kCanceledErr                           -6723
+#define kAlreadyCanceledErr                    -6724
+#define kCannotCancelErr                       -6725
+#define kDeletedErr                                    -6726
+#define kNotFoundErr                           -6727
+#define kNoMemoryErr                           -6728
+#define kNoResourcesErr                                -6729
+#define kDuplicateErr                          -6730
+#define kImmutableErr                          -6731
+#define kUnsupportedDataErr                    -6732
+#define kIntegrityErr                          -6733
+#define kIncompatibleErr                       -6734
+#define kUnsupportedErr                                -6735
+#define kUnexpectedErr                         -6736
+#define kValueErr                                      -6737
+#define kNotReadableErr                                -6738
+#define kNotWritableErr                                -6739
+#define        kBadReferenceErr                        -6740
+#define        kFlagErr                                        -6741
+#define        kMalformedErr                           -6742
+#define        kSizeErr                                        -6743
+#define        kNameErr                                        -6744
+#define        kNotReadyErr                            -6745
+#define        kReadErr                                        -6746
+#define        kWriteErr                                       -6747
+#define        kMismatchErr                            -6748
+#define        kDateErr                                        -6749
+#define        kUnderrunErr                            -6750
+#define        kOverrunErr                                     -6751
+#define        kEndingErr                                      -6752
+#define        kConnectionErr                          -6753
+#define        kAuthenticationErr                      -6754
+#define        kOpenErr                                        -6755
+#define        kTypeErr                                        -6756
+#define        kSkipErr                                        -6757
+#define        kNoAckErr                                       -6758
+#define        kCollisionErr                           -6759
+#define        kBackoffErr                                     -6760
+#define        kNoAddressAckErr                        -6761
+#define        kBusyErr                                        -6762
+#define        kNoSpaceErr                                     -6763
+
+#define kGenericErrorEnd                       -6779   // Last generic error code (inclusive)
+
+#if 0
+#pragma mark == Mac Compatibility ==
+#endif
+
+//===========================================================================================================================
+//     Mac Compatibility
+//===========================================================================================================================
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @enum           Duration
+       
+       @abstract       Type used to specify a duration of time.
+       
+       @constant       kDurationImmediate                      Indicates no delay/wait time.
+       @constant       kDurationMicrosecond            Microsecond units.
+       @constant       kDurationMillisecond            Millisecond units.
+       @constant       kDurationSecond                         Second units.
+       @constant       kDurationMinute                         Minute units.
+       @constant       kDurationHour                           Hour units.
+       @constant       kDurationDay                            Day units.
+       @constant       kDurationForever                        Infinite period of time (no timeout).
+
+       @discussion 
+       
+       Duration values are intended to be multiplied by the specific interval to achieve an actual duration. For example, 
+       to wait for 5 seconds you would use "5 * kDurationSecond".
+*/
+
+#if( TARGET_LANGUAGE_C_LIKE )
+       #if( !TARGET_OS_MAC )
+               typedef int32_t         Duration;
+       #endif
+#endif
+
+#define        kDurationImmediate                              0L
+#define        kDurationMicrosecond                    -1L
+#define        kDurationMillisecond                    1L
+#define        kDurationSecond                                 ( 1000L * kDurationMillisecond )
+#define        kDurationMinute                                 ( 60L * kDurationSecond )
+#define        kDurationHour                                   ( 60L * kDurationMinute )
+#define        kDurationDay                                    ( 24L * kDurationHour )
+#define        kDurationForever                                0x7FFFFFFFL
+
+// Seconds <-> Minutes <-> Hours <-> Days <-> Weeks <-> Months <-> Years conversions
+
+#define kNanosecondsPerMicrosecond             1000
+#define kNanosecondsPerMillisecond             1000000
+#define kNanosecondsPerSecond                  1000000000
+#define kMicrosecondsPerSecond                 1000000
+#define kMicrosecondsPerMillisecond            1000
+#define kMillisecondsPerSecond                 1000
+#define kSecondsPerMinute                              60
+#define kSecondsPerHour                                        ( 60 * 60 )                             // 3600
+#define kSecondsPerDay                                 ( 60 * 60 * 24 )                // 86400
+#define kSecondsPerWeek                                        ( 60 * 60 * 24 * 7 )    // 604800
+#define kMinutesPerHour                                        60
+#define kMinutesPerDay                                 ( 60 * 24 )                             // 1440
+#define kHoursPerDay                                   24
+#define kDaysPerWeek                                   7
+#define kWeeksPerYear                                  52
+#define kMonthsPerYear                                 12
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        VersionStages
+
+       @abstract       NumVersion-style version stages.
+*/
+
+#define        kVersionStageDevelopment                0x20
+#define        kVersionStageAlpha                              0x40
+#define        kVersionStageBeta                               0x60
+#define        kVersionStageFinal                              0x80
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       NumVersionBuild
+
+       @abstract       Builds a 32-bit Mac-style NumVersion value (e.g. NumVersionBuild( 1, 2, 3, kVersionStageBeta, 4 ) -> 1.2.3b4).
+*/
+
+#define        NumVersionBuild( MAJOR, MINOR, BUGFIX, STAGE, REV )     \
+       ( ( ( ( MAJOR )  & 0xFF ) << 24 ) |                                             \
+         ( ( ( MINOR )  & 0x0F ) << 20 ) |                                             \
+         ( ( ( BUGFIX ) & 0x0F ) << 16 ) |                                             \
+         ( ( ( STAGE )  & 0xFF ) <<  8 ) |                                             \
+         ( ( ( REV )    & 0xFF )       ) )
+
+#define        NumVersionExtractMajor( VERSION )                               ( (uint8_t)( ( ( VERSION ) >> 24 ) & 0xFF ) )
+#define        NumVersionExtractMinorAndBugFix( VERSION )              ( (uint8_t)( ( ( VERSION ) >> 16 ) & 0xFF ) )
+#define        NumVersionExtractMinor( VERSION )                               ( (uint8_t)( ( ( VERSION ) >> 20 ) & 0x0F ) )
+#define        NumVersionExtractBugFix( VERSION )                              ( (uint8_t)( ( ( VERSION ) >> 16 ) & 0x0F ) )
+#define        NumVersionExtractStage( VERSION )                               ( (uint8_t)( ( ( VERSION ) >>  8 ) & 0xFF ) )
+#define        NumVersionExtractRevision( VERSION )                    ( (uint8_t)(   ( VERSION )         & 0xFF ) )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       NumVersionCompare
+
+       @abstract       Compares two NumVersion values and returns the following values:
+       
+               left < right -> -1
+               left > right ->  1
+               left = right ->  0
+*/
+
+#if( TARGET_LANGUAGE_C_LIKE )
+       int     NumVersionCompare( uint32_t inLeft, uint32_t inRight );
+#endif
+
+#if 0
+#pragma mark == Binary Constants ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        binary_4
+       
+       @abstract       Macro to generate an 4-bit constant using binary notation (e.g. binary_4( 1010 ) == 0xA).
+*/
+
+#define        binary_4( a )                                           binary_4_hex_wrap( hex_digit4( a ) )
+#define binary_4_hex_wrap( a )                         binary_4_hex( a )
+#define binary_4_hex( a )                                      ( 0x ## a )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        binary_8
+       
+       @abstract       Macro to generate an 8-bit constant using binary notation (e.g. binary_8( 01111011 ) == 0x7B).
+*/
+
+#define        binary_8( a )                                           binary_8_hex_wrap( hex_digit8( a ) )
+#define binary_8_hex_wrap( a )                         binary_8_hex( a )
+#define binary_8_hex( a )                                      ( 0x ## a )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        binary_16
+       
+       @abstract       Macro to generate an 16-bit constant using binary notation (e.g. binary_16( 01111011, 01111011 ) == 0x7B7B).
+*/
+
+#define        binary_16( a, b )                                       binary_16_hex_wrap( hex_digit8( a ), hex_digit8( b ) )
+#define binary_16_hex_wrap( a, b )                     binary_16_hex( a, b )
+#define binary_16_hex( a, b )                          ( 0x ## a ## b )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        binary_32
+       
+       @abstract       Macro to generate an 32-bit constant using binary notation 
+                               (e.g. binary_32( 01111011, 01111011, 01111011, 01111011 ) == 0x7B7B7B7B).
+*/
+
+#define        binary_32( a, b, c, d )                         binary_32_hex_wrap( hex_digit8( a ), hex_digit8( b ), hex_digit8( c ), hex_digit8( d ) )
+#define binary_32_hex_wrap( a, b, c, d )       binary_32_hex( a, b, c, d )
+#define binary_32_hex( a, b, c, d )                    ( 0x ## a ## b ## c ## d )
+
+// Binary Constant Helpers
+
+#define hex_digit8( a )                                                HEX_DIGIT_ ## a
+#define hex_digit4( a )                                                HEX_DIGIT_ ## 0000 ## a
+
+#define HEX_DIGIT_00000000                                     00
+#define HEX_DIGIT_00000001                                     01
+#define HEX_DIGIT_00000010                                     02
+#define HEX_DIGIT_00000011                                     03
+#define HEX_DIGIT_00000100                                     04
+#define HEX_DIGIT_00000101                                     05
+#define HEX_DIGIT_00000110                                     06
+#define HEX_DIGIT_00000111                                     07
+#define HEX_DIGIT_00001000                                     08
+#define HEX_DIGIT_00001001                                     09
+#define HEX_DIGIT_00001010                                     0A
+#define HEX_DIGIT_00001011                                     0B
+#define HEX_DIGIT_00001100                                     0C
+#define HEX_DIGIT_00001101                                     0D
+#define HEX_DIGIT_00001110                                     0E
+#define HEX_DIGIT_00001111                                     0F
+#define HEX_DIGIT_00010000                                     10
+#define HEX_DIGIT_00010001                                     11
+#define HEX_DIGIT_00010010                                     12
+#define HEX_DIGIT_00010011                                     13
+#define HEX_DIGIT_00010100                                     14
+#define HEX_DIGIT_00010101                                     15
+#define HEX_DIGIT_00010110                                     16
+#define HEX_DIGIT_00010111                                     17
+#define HEX_DIGIT_00011000                                     18
+#define HEX_DIGIT_00011001                                     19
+#define HEX_DIGIT_00011010                                     1A
+#define HEX_DIGIT_00011011                                     1B
+#define HEX_DIGIT_00011100                                     1C
+#define HEX_DIGIT_00011101                                     1D
+#define HEX_DIGIT_00011110                                     1E
+#define HEX_DIGIT_00011111                                     1F
+#define HEX_DIGIT_00100000                                     20
+#define HEX_DIGIT_00100001                                     21
+#define HEX_DIGIT_00100010                                     22
+#define HEX_DIGIT_00100011                                     23
+#define HEX_DIGIT_00100100                                     24
+#define HEX_DIGIT_00100101                                     25
+#define HEX_DIGIT_00100110                                     26
+#define HEX_DIGIT_00100111                                     27
+#define HEX_DIGIT_00101000                                     28
+#define HEX_DIGIT_00101001                                     29
+#define HEX_DIGIT_00101010                                     2A
+#define HEX_DIGIT_00101011                                     2B
+#define HEX_DIGIT_00101100                                     2C
+#define HEX_DIGIT_00101101                                     2D
+#define HEX_DIGIT_00101110                                     2E
+#define HEX_DIGIT_00101111                                     2F
+#define HEX_DIGIT_00110000                                     30
+#define HEX_DIGIT_00110001                                     31
+#define HEX_DIGIT_00110010                                     32
+#define HEX_DIGIT_00110011                                     33
+#define HEX_DIGIT_00110100                                     34
+#define HEX_DIGIT_00110101                                     35
+#define HEX_DIGIT_00110110                                     36
+#define HEX_DIGIT_00110111                                     37
+#define HEX_DIGIT_00111000                                     38
+#define HEX_DIGIT_00111001                                     39
+#define HEX_DIGIT_00111010                                     3A
+#define HEX_DIGIT_00111011                                     3B
+#define HEX_DIGIT_00111100                                     3C
+#define HEX_DIGIT_00111101                                     3D
+#define HEX_DIGIT_00111110                                     3E
+#define HEX_DIGIT_00111111                                     3F
+#define HEX_DIGIT_01000000                                     40
+#define HEX_DIGIT_01000001                                     41
+#define HEX_DIGIT_01000010                                     42
+#define HEX_DIGIT_01000011                                     43
+#define HEX_DIGIT_01000100                                     44
+#define HEX_DIGIT_01000101                                     45
+#define HEX_DIGIT_01000110                                     46
+#define HEX_DIGIT_01000111                                     47
+#define HEX_DIGIT_01001000                                     48
+#define HEX_DIGIT_01001001                                     49
+#define HEX_DIGIT_01001010                                     4A
+#define HEX_DIGIT_01001011                                     4B
+#define HEX_DIGIT_01001100                                     4C
+#define HEX_DIGIT_01001101                                     4D
+#define HEX_DIGIT_01001110                                     4E
+#define HEX_DIGIT_01001111                                     4F
+#define HEX_DIGIT_01010000                                     50
+#define HEX_DIGIT_01010001                                     51
+#define HEX_DIGIT_01010010                                     52
+#define HEX_DIGIT_01010011                                     53
+#define HEX_DIGIT_01010100                                     54
+#define HEX_DIGIT_01010101                                     55
+#define HEX_DIGIT_01010110                                     56
+#define HEX_DIGIT_01010111                                     57
+#define HEX_DIGIT_01011000                                     58
+#define HEX_DIGIT_01011001                                     59
+#define HEX_DIGIT_01011010                                     5A
+#define HEX_DIGIT_01011011                                     5B
+#define HEX_DIGIT_01011100                                     5C
+#define HEX_DIGIT_01011101                                     5D
+#define HEX_DIGIT_01011110                                     5E
+#define HEX_DIGIT_01011111                                     5F
+#define HEX_DIGIT_01100000                                     60
+#define HEX_DIGIT_01100001                                     61
+#define HEX_DIGIT_01100010                                     62
+#define HEX_DIGIT_01100011                                     63
+#define HEX_DIGIT_01100100                                     64
+#define HEX_DIGIT_01100101                                     65
+#define HEX_DIGIT_01100110                                     66
+#define HEX_DIGIT_01100111                                     67
+#define HEX_DIGIT_01101000                                     68
+#define HEX_DIGIT_01101001                                     69
+#define HEX_DIGIT_01101010                                     6A
+#define HEX_DIGIT_01101011                                     6B
+#define HEX_DIGIT_01101100                                     6C
+#define HEX_DIGIT_01101101                                     6D
+#define HEX_DIGIT_01101110                                     6E
+#define HEX_DIGIT_01101111                                     6F
+#define HEX_DIGIT_01110000                                     70
+#define HEX_DIGIT_01110001                                     71
+#define HEX_DIGIT_01110010                                     72
+#define HEX_DIGIT_01110011                                     73
+#define HEX_DIGIT_01110100                                     74
+#define HEX_DIGIT_01110101                                     75
+#define HEX_DIGIT_01110110                                     76
+#define HEX_DIGIT_01110111                                     77
+#define HEX_DIGIT_01111000                                     78
+#define HEX_DIGIT_01111001                                     79
+#define HEX_DIGIT_01111010                                     7A
+#define HEX_DIGIT_01111011                                     7B
+#define HEX_DIGIT_01111100                                     7C
+#define HEX_DIGIT_01111101                                     7D
+#define HEX_DIGIT_01111110                                     7E
+#define HEX_DIGIT_01111111                                     7F
+#define HEX_DIGIT_10000000                                     80
+#define HEX_DIGIT_10000001                                     81
+#define HEX_DIGIT_10000010                                     82
+#define HEX_DIGIT_10000011                                     83
+#define HEX_DIGIT_10000100                                     84
+#define HEX_DIGIT_10000101                                     85
+#define HEX_DIGIT_10000110                                     86
+#define HEX_DIGIT_10000111                                     87
+#define HEX_DIGIT_10001000                                     88
+#define HEX_DIGIT_10001001                                     89
+#define HEX_DIGIT_10001010                                     8A
+#define HEX_DIGIT_10001011                                     8B
+#define HEX_DIGIT_10001100                                     8C
+#define HEX_DIGIT_10001101                                     8D
+#define HEX_DIGIT_10001110                                     8E
+#define HEX_DIGIT_10001111                                     8F
+#define HEX_DIGIT_10010000                                     90
+#define HEX_DIGIT_10010001                                     91
+#define HEX_DIGIT_10010010                                     92
+#define HEX_DIGIT_10010011                                     93
+#define HEX_DIGIT_10010100                                     94
+#define HEX_DIGIT_10010101                                     95
+#define HEX_DIGIT_10010110                                     96
+#define HEX_DIGIT_10010111                                     97
+#define HEX_DIGIT_10011000                                     98
+#define HEX_DIGIT_10011001                                     99
+#define HEX_DIGIT_10011010                                     9A
+#define HEX_DIGIT_10011011                                     9B
+#define HEX_DIGIT_10011100                                     9C
+#define HEX_DIGIT_10011101                                     9D
+#define HEX_DIGIT_10011110                                     9E
+#define HEX_DIGIT_10011111                                     9F
+#define HEX_DIGIT_10100000                                     A0
+#define HEX_DIGIT_10100001                                     A1
+#define HEX_DIGIT_10100010                                     A2
+#define HEX_DIGIT_10100011                                     A3
+#define HEX_DIGIT_10100100                                     A4
+#define HEX_DIGIT_10100101                                     A5
+#define HEX_DIGIT_10100110                                     A6
+#define HEX_DIGIT_10100111                                     A7
+#define HEX_DIGIT_10101000                                     A8
+#define HEX_DIGIT_10101001                                     A9
+#define HEX_DIGIT_10101010                                     AA
+#define HEX_DIGIT_10101011                                     AB
+#define HEX_DIGIT_10101100                                     AC
+#define HEX_DIGIT_10101101                                     AD
+#define HEX_DIGIT_10101110                                     AE
+#define HEX_DIGIT_10101111                                     AF
+#define HEX_DIGIT_10110000                                     B0
+#define HEX_DIGIT_10110001                                     B1
+#define HEX_DIGIT_10110010                                     B2
+#define HEX_DIGIT_10110011                                     B3
+#define HEX_DIGIT_10110100                                     B4
+#define HEX_DIGIT_10110101                                     B5
+#define HEX_DIGIT_10110110                                     B6
+#define HEX_DIGIT_10110111                                     B7
+#define HEX_DIGIT_10111000                                     B8
+#define HEX_DIGIT_10111001                                     B9
+#define HEX_DIGIT_10111010                                     BA
+#define HEX_DIGIT_10111011                                     BB
+#define HEX_DIGIT_10111100                                     BC
+#define HEX_DIGIT_10111101                                     BD
+#define HEX_DIGIT_10111110                                     BE
+#define HEX_DIGIT_10111111                                     BF
+#define HEX_DIGIT_11000000                                     C0
+#define HEX_DIGIT_11000001                                     C1
+#define HEX_DIGIT_11000010                                     C2
+#define HEX_DIGIT_11000011                                     C3
+#define HEX_DIGIT_11000100                                     C4
+#define HEX_DIGIT_11000101                                     C5
+#define HEX_DIGIT_11000110                                     C6
+#define HEX_DIGIT_11000111                                     C7
+#define HEX_DIGIT_11001000                                     C8
+#define HEX_DIGIT_11001001                                     C9
+#define HEX_DIGIT_11001010                                     CA
+#define HEX_DIGIT_11001011                                     CB
+#define HEX_DIGIT_11001100                                     CC
+#define HEX_DIGIT_11001101                                     CD
+#define HEX_DIGIT_11001110                                     CE
+#define HEX_DIGIT_11001111                                     CF
+#define HEX_DIGIT_11010000                                     D0
+#define HEX_DIGIT_11010001                                     D1
+#define HEX_DIGIT_11010010                                     D2
+#define HEX_DIGIT_11010011                                     D3
+#define HEX_DIGIT_11010100                                     D4
+#define HEX_DIGIT_11010101                                     D5
+#define HEX_DIGIT_11010110                                     D6
+#define HEX_DIGIT_11010111                                     D7
+#define HEX_DIGIT_11011000                                     D8
+#define HEX_DIGIT_11011001                                     D9
+#define HEX_DIGIT_11011010                                     DA
+#define HEX_DIGIT_11011011                                     DB
+#define HEX_DIGIT_11011100                                     DC
+#define HEX_DIGIT_11011101                                     DD
+#define HEX_DIGIT_11011110                                     DE
+#define HEX_DIGIT_11011111                                     DF
+#define HEX_DIGIT_11100000                                     E0
+#define HEX_DIGIT_11100001                                     E1
+#define HEX_DIGIT_11100010                                     E2
+#define HEX_DIGIT_11100011                                     E3
+#define HEX_DIGIT_11100100                                     E4
+#define HEX_DIGIT_11100101                                     E5
+#define HEX_DIGIT_11100110                                     E6
+#define HEX_DIGIT_11100111                                     E7
+#define HEX_DIGIT_11101000                                     E8
+#define HEX_DIGIT_11101001                                     E9
+#define HEX_DIGIT_11101010                                     EA
+#define HEX_DIGIT_11101011                                     EB
+#define HEX_DIGIT_11101100                                     EC
+#define HEX_DIGIT_11101101                                     ED
+#define HEX_DIGIT_11101110                                     EE
+#define HEX_DIGIT_11101111                                     EF
+#define HEX_DIGIT_11110000                                     F0
+#define HEX_DIGIT_11110001                                     F1
+#define HEX_DIGIT_11110010                                     F2
+#define HEX_DIGIT_11110011                                     F3
+#define HEX_DIGIT_11110100                                     F4
+#define HEX_DIGIT_11110101                                     F5
+#define HEX_DIGIT_11110110                                     F6
+#define HEX_DIGIT_11110111                                     F7
+#define HEX_DIGIT_11111000                                     F8
+#define HEX_DIGIT_11111001                                     F9
+#define HEX_DIGIT_11111010                                     FA
+#define HEX_DIGIT_11111011                                     FB
+#define HEX_DIGIT_11111100                                     FC
+#define HEX_DIGIT_11111101                                     FD
+#define HEX_DIGIT_11111110                                     FE
+#define HEX_DIGIT_11111111                                     FF
+
+#if 0
+#pragma mark == Debugging ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       CommonServicesTest
+
+       @abstract       Unit test.
+*/
+
+#if( DEBUG )
+       #if( TARGET_LANGUAGE_C_LIKE )
+               OSStatus        CommonServicesTest( void );
+       #endif
+#endif
+
+#ifdef __cplusplus
+       }
+#endif
+
+#endif // __COMMON_SERVICES__
diff --git a/mDNSWindows/DNSSD.c b/mDNSWindows/DNSSD.c
new file mode 100644 (file)
index 0000000..24bc560
--- /dev/null
@@ -0,0 +1,1720 @@
+/*
+ * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+    
+$Log: DNSSD.c,v $
+Revision 1.3  2004/05/11 03:08:53  bradley
+Updated TXT Record API based on latest proposal. This still includes dynamic TXT record building for
+a final CVS snapshot for private libraries before this functionality is removed from the public API.
+
+Revision 1.2  2004/05/03 10:34:24  bradley
+Implemented preliminary version of the TXTRecord API.
+
+Revision 1.1  2004/01/30 02:45:21  bradley
+High-level implementation of the DNS-SD API. Supports both "direct" (compiled-in mDNSCore) and "client"
+(IPC<->service) usage. Conditionals can exclude either "direct" or "client" to reduce code size.
+
+*/
+
+#include       <ctype.h>
+#include       <stdlib.h>
+#include       <stdio.h>
+#include       <string.h>
+
+#include       "CommonServices.h"
+#include       "DebugServices.h"
+
+#include       "DNSSDDirect.h"
+#include       "RMxClient.h"
+
+#include       "DNSSD.h"
+
+#ifdef __cplusplus
+       extern "C" {
+#endif
+
+//===========================================================================================================================
+//     Constants
+//===========================================================================================================================
+
+#define        DEBUG_NAME              "[DNS-SD] "
+
+//===========================================================================================================================
+//     Prototypes
+//===========================================================================================================================
+
+DEBUG_LOCAL int DomainEndsInDot( const char *dom );
+
+//===========================================================================================================================
+//     Globals
+//===========================================================================================================================
+
+#if( DNS_SD_CLIENT_ENABLED )
+       const char *                    gDNSSDServer                    = NULL;
+       DEBUG_LOCAL     bool            gDNSSDServerCompatible  = false;
+#endif
+
+#if 0
+#pragma mark == General ==
+#endif
+
+//===========================================================================================================================
+//     DNSServiceInitialize
+//===========================================================================================================================
+
+DNSServiceErrorType    DNSServiceInitialize( DNSServiceInitializeFlags inFlags, int inCacheEntryCount )
+{
+       DNSServiceErrorType             err;
+       
+       #if( DNS_SD_CLIENT_ENABLED )
+               err = RMxClientInitialize();
+               if( err == kNoErr )
+               {
+                       // Perform a version check to see if the server is compatible.
+                       
+                       if( !( inFlags & kDNSServiceInitializeFlagsNoServerCheck ) )
+                       {
+                               err = DNSServiceCheckVersion();
+                               if( err == kNoErr )
+                               {
+                                       goto exit;
+                               }
+                       }
+                       else
+                       {
+                               // Version check disabled so just assume the server is compatible.
+                               
+                               gDNSSDServerCompatible = true;
+                               goto exit;
+                       }
+               }
+       #endif
+       
+       #if( DNS_SD_DIRECT_ENABLED )
+               #if( DNS_SD_CLIENT_ENABLED )
+                       dlog( kDebugLevelNotice, DEBUG_NAME "server missing or incompatible...falling back to direct implementation\n" );
+               #endif
+               err = DNSServiceInitialize_direct( inFlags, inCacheEntryCount );
+               goto exit;
+       #else
+               DEBUG_UNUSED( inFlags );
+               DEBUG_UNUSED( inCacheEntryCount );
+               
+               err = kUnsupportedErr;
+               goto exit;
+       #endif
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     DNSServiceFinalize
+//===========================================================================================================================
+
+void   DNSServiceFinalize( void )
+{
+       #if( DNS_SD_CLIENT_ENABLED )
+               RMxClientFinalize();
+       #endif
+       
+       #if( DNS_SD_DIRECT_ENABLED )
+               DNSServiceFinalize_direct();
+       #endif
+}
+
+//===========================================================================================================================
+//     DNSServiceCheckVersion
+//===========================================================================================================================
+
+DNSServiceErrorType    DNSServiceCheckVersion( void )
+{      
+       DNSServiceErrorType             err;
+       
+       #if( DNS_SD_CLIENT_ENABLED )
+               err = DNSServiceCheckVersion_client( gDNSSDServer );
+               if( err == kNoErr )
+               {
+                       gDNSSDServerCompatible = true;
+               }
+       #else
+               err = kUnsupportedErr;
+       #endif
+       
+       return( err );
+}
+
+#if 0
+#pragma mark -
+#pragma mark == Properties ==
+#endif
+
+//===========================================================================================================================
+//     DNSServiceCopyProperty
+//===========================================================================================================================
+
+DNSServiceErrorType    DNSServiceCopyProperty( DNSPropertyCode inCode, DNSPropertyData *outData )
+{      
+       DNSServiceErrorType             err;
+       
+       #if( DNS_SD_CLIENT_ENABLED )
+               if( gDNSSDServerCompatible )
+               {
+                       err = DNSServiceCopyProperty_client( gDNSSDServer, inCode, outData );
+                       goto exit;
+               }
+       #else
+               DEBUG_UNUSED( inCode );
+               DEBUG_UNUSED( outData );
+       #endif
+       
+       #if( DNS_SD_DIRECT_ENABLED )
+               err = kUnsupportedErr;
+               goto exit;
+       #else
+               err = kUnsupportedErr;
+               goto exit;
+       #endif
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     DNSServiceReleaseProperty
+//===========================================================================================================================
+
+DNSServiceErrorType    DNSServiceReleaseProperty( DNSPropertyData *inData )
+{      
+       DNSServiceErrorType             err;
+       
+       #if( DNS_SD_CLIENT_ENABLED )
+               if( gDNSSDServerCompatible )
+               {
+                       err = DNSServiceReleaseProperty_client( inData );
+                       goto exit;
+               }
+       #else
+               DEBUG_UNUSED( inData );
+       #endif
+       
+       #if( DNS_SD_DIRECT_ENABLED )
+               err = kUnsupportedErr;
+               goto exit;
+       #else
+               err = kUnsupportedErr;
+               goto exit;
+       #endif
+       
+exit:
+       return( err );
+}
+
+#if 0
+#pragma mark -
+#pragma mark == Unix Domain Socket Access ==
+#endif
+
+//===========================================================================================================================
+//     DNSServiceRefSockFD
+//===========================================================================================================================
+
+int    DNSServiceRefSockFD( DNSServiceRef inRef )
+{
+       DEBUG_UNUSED( inRef );
+       
+       dlog( kDebugLevelError, "DNSServiceRefSockFD is not supported\n" );
+       return( -1 );
+}
+
+//===========================================================================================================================
+//     DNSServiceProcessResult
+//===========================================================================================================================
+
+DNSServiceErrorType    DNSServiceProcessResult( DNSServiceRef inRef )
+{
+       DEBUG_UNUSED( inRef );
+       
+       dlog( kDebugLevelError, "DNSServiceProcessResult is not supported\n" );
+       return( kDNSServiceErr_Unsupported );
+}
+
+//===========================================================================================================================
+//     DNSServiceRefDeallocate
+//===========================================================================================================================
+
+void   DNSServiceRefDeallocate( DNSServiceRef inRef )
+{
+       #if( DNS_SD_CLIENT_ENABLED )
+               if( gDNSSDServerCompatible )
+               {
+                       DNSServiceRefDeallocate_client( inRef );
+                       goto exit;
+               }
+       #endif
+       
+       #if( DNS_SD_DIRECT_ENABLED )
+               DNSServiceRefDeallocate_direct( inRef );
+               goto exit;
+       #else
+               DEBUG_UNUSED( inRef );
+
+               goto exit;
+       #endif
+       
+exit:
+       return;
+}
+
+#if 0
+#pragma mark -
+#pragma mark == Domain Enumeration ==
+#endif
+
+//===========================================================================================================================
+//     DNSServiceEnumerateDomains
+//===========================================================================================================================
+
+DNSServiceErrorType
+       DNSServiceEnumerateDomains(
+               DNSServiceRef *                                 outRef,
+               const DNSServiceFlags                   inFlags,
+               const uint32_t                                  inInterfaceIndex,
+               const DNSServiceDomainEnumReply inCallBack,
+               void *                                                  inContext )
+{
+       DNSServiceErrorType             err;
+       
+       #if( DNS_SD_CLIENT_ENABLED )
+               if( gDNSSDServerCompatible )
+               {
+                       err = DNSServiceEnumerateDomains_client( outRef, gDNSSDServer, inFlags, inInterfaceIndex, inCallBack, inContext );
+                       goto exit;
+               }
+       #endif
+       
+       #if( DNS_SD_DIRECT_ENABLED )
+               err = DNSServiceEnumerateDomains_direct( outRef, inFlags, inInterfaceIndex, inCallBack, inContext );
+               goto exit;
+       #else
+               DEBUG_UNUSED( outRef );
+               DEBUG_UNUSED( inFlags );
+               DEBUG_UNUSED( inInterfaceIndex );
+               DEBUG_UNUSED( inCallBack );
+               DEBUG_UNUSED( inContext );
+               
+               err = kUnsupportedErr;
+               goto exit;
+       #endif
+       
+exit:
+       return( err );
+}
+
+#if 0
+#pragma mark -
+#pragma mark == Service Registration ==
+#endif
+
+//===========================================================================================================================
+//     DNSServiceRegister
+//===========================================================================================================================
+
+DNSServiceErrorType
+       DNSServiceRegister(
+               DNSServiceRef *                 outRef,
+               DNSServiceFlags                 inFlags,
+               uint32_t                                inInterfaceIndex,
+               const char *                    inName,
+               const char *                    inType,
+               const char *                    inDomain,
+               const char *                    inHost,
+               uint16_t                                inPort,
+               uint16_t                                inTXTSize,
+               const void *                    inTXT,
+               DNSServiceRegisterReply inCallBack,
+               void *                                  inContext )
+{
+       DNSServiceErrorType             err;
+       
+       #if( DNS_SD_CLIENT_ENABLED )
+               if( gDNSSDServerCompatible )
+               {
+                       err = DNSServiceRegister_client( outRef, gDNSSDServer, inFlags, inInterfaceIndex, inName, inType, inDomain, 
+                               inHost, inPort, inTXTSize, inTXT, inCallBack, inContext );
+                       goto exit;
+               }
+       #endif
+       
+       #if( DNS_SD_DIRECT_ENABLED )
+               err = DNSServiceRegister_direct( outRef, inFlags, inInterfaceIndex, inName, inType, inDomain, inHost, inPort, 
+                       inTXTSize, inTXT, inCallBack, inContext );
+               goto exit;
+       #else
+               DEBUG_UNUSED( outRef );
+               DEBUG_UNUSED( inFlags );
+               DEBUG_UNUSED( inInterfaceIndex );
+               DEBUG_UNUSED( inName );
+               DEBUG_UNUSED( inType );
+               DEBUG_UNUSED( inDomain );
+               DEBUG_UNUSED( inHost );
+               DEBUG_UNUSED( inPort );
+               DEBUG_UNUSED( inTXTSize );
+               DEBUG_UNUSED( inTXT );
+               DEBUG_UNUSED( inCallBack );
+               DEBUG_UNUSED( inContext );
+               
+               err = kUnsupportedErr;
+               goto exit;
+       #endif
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     DNSServiceAddRecord
+//===========================================================================================================================
+
+DNSServiceErrorType
+       DNSServiceAddRecord(
+               DNSServiceRef   inRef,
+               DNSRecordRef *  outRecordRef,
+               DNSServiceFlags inFlags,
+               uint16_t                inRRType,
+               uint16_t                inRDataSize,
+               const void *    inRData,
+               uint32_t                inTTL )
+{
+       DNSServiceErrorType             err;
+       
+       #if( DNS_SD_CLIENT_ENABLED )
+               if( gDNSSDServerCompatible )
+               {
+                       err = DNSServiceAddRecord_client( inRef, outRecordRef, inFlags, inRRType, inRDataSize, inRData, inTTL );
+                       goto exit;
+               }
+       #endif
+       
+       #if( DNS_SD_DIRECT_ENABLED )
+               err = DNSServiceAddRecord_direct( inRef, outRecordRef, inFlags, inRRType, inRDataSize, inRData, inTTL );
+               goto exit;
+       #else
+               DEBUG_UNUSED( inRef );
+               DEBUG_UNUSED( outRecordRef );
+               DEBUG_UNUSED( inFlags );
+               DEBUG_UNUSED( inRRType );
+               DEBUG_UNUSED( inRDataSize );
+               DEBUG_UNUSED( inRData );
+               DEBUG_UNUSED( inTTL );
+               
+               err = kUnsupportedErr;
+               goto exit;
+       #endif
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     DNSServiceUpdateRecord
+//===========================================================================================================================
+
+DNSServiceErrorType
+       DNSServiceUpdateRecord(
+           DNSServiceRef       inRef,
+           DNSRecordRef        inRecordRef,
+           DNSServiceFlags     inFlags,
+           uint16_t            inRDataSize,
+           const void *        inRData,
+           uint32_t            inTTL )
+{
+       DNSServiceErrorType             err;
+       
+       #if( DNS_SD_CLIENT_ENABLED )
+               if( gDNSSDServerCompatible )
+               {
+                       err = DNSServiceUpdateRecord_client( inRef, inRecordRef, inFlags, inRDataSize, inRData, inTTL );
+                       goto exit;
+               }
+       #endif
+       
+       #if( DNS_SD_DIRECT_ENABLED )
+               err = DNSServiceUpdateRecord_direct( inRef, inRecordRef, inFlags, inRDataSize, inRData, inTTL );
+               goto exit;
+       #else
+               DEBUG_UNUSED( inRef );
+               DEBUG_UNUSED( inRecordRef );
+               DEBUG_UNUSED( inFlags );
+               DEBUG_UNUSED( inRDataSize );
+               DEBUG_UNUSED( inRData );
+               DEBUG_UNUSED( inTTL );
+               
+               err = kUnsupportedErr;
+               goto exit;
+       #endif
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     DNSServiceRemoveRecord
+//===========================================================================================================================
+
+DNSServiceErrorType DNSServiceRemoveRecord( DNSServiceRef inRef, DNSRecordRef inRecordRef, DNSServiceFlags inFlags )
+{
+       DNSServiceErrorType             err;
+       
+       #if( DNS_SD_CLIENT_ENABLED )
+               if( gDNSSDServerCompatible )
+               {
+                       err = DNSServiceRemoveRecord_client( inRef, inRecordRef, inFlags );
+                       goto exit;
+               }
+       #endif
+       
+       #if( DNS_SD_DIRECT_ENABLED )
+               err = DNSServiceRemoveRecord_direct( inRef, inRecordRef, inFlags );
+               goto exit;
+       #else
+               DEBUG_UNUSED( inRef );
+               DEBUG_UNUSED( inRecordRef );
+               DEBUG_UNUSED( inFlags );
+               
+               err = kUnsupportedErr;
+               goto exit;
+       #endif
+       
+exit:
+       return( err );
+}
+
+#if 0
+#pragma mark -
+#pragma mark == Service Discovery ==
+#endif
+
+//===========================================================================================================================
+//     DNSServiceBrowse
+//===========================================================================================================================
+
+DNSServiceErrorType
+       DNSServiceBrowse(
+               DNSServiceRef *                 outRef,
+               DNSServiceFlags                 inFlags,
+               uint32_t                                inInterfaceIndex,
+               const char *                    inType,   
+               const char *                    inDomain,
+               DNSServiceBrowseReply   inCallBack,
+               void *                                  inContext )
+{
+       DNSServiceErrorType             err;
+       
+       #if( DNS_SD_CLIENT_ENABLED )
+               if( gDNSSDServerCompatible )
+               {
+                       err = DNSServiceBrowse_client( outRef, gDNSSDServer, inFlags, inInterfaceIndex, inType, inDomain, 
+                               inCallBack, inContext );
+                       goto exit;
+               }
+       #endif
+       
+       #if( DNS_SD_DIRECT_ENABLED )
+               err = DNSServiceBrowse_direct( outRef, inFlags, inInterfaceIndex, inType, inDomain, inCallBack, inContext );
+               goto exit;
+       #else
+               DEBUG_UNUSED( outRef );
+               DEBUG_UNUSED( inFlags );
+               DEBUG_UNUSED( inInterfaceIndex );
+               DEBUG_UNUSED( inType );
+               DEBUG_UNUSED( inDomain );
+               DEBUG_UNUSED( inCallBack );
+               DEBUG_UNUSED( inContext );
+               
+               err = kUnsupportedErr;
+               goto exit;
+       #endif
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     DNSServiceResolve
+//===========================================================================================================================
+
+DNSServiceErrorType
+       DNSServiceResolve( 
+               DNSServiceRef *                 outRef,
+               DNSServiceFlags                 inFlags,
+               uint32_t                                inInterfaceIndex,
+               const char *                    inName,     
+               const char *                    inType,  
+               const char *                    inDomain,   
+               DNSServiceResolveReply  inCallBack,
+               void *                                  inContext )
+{
+       DNSServiceErrorType             err;
+       
+       #if( DNS_SD_CLIENT_ENABLED )
+               if( gDNSSDServerCompatible )
+               {
+                       err = DNSServiceResolve_client( outRef, gDNSSDServer, inFlags, inInterfaceIndex, inName, inType, inDomain, 
+                               inCallBack, inContext );
+                       goto exit;
+               }
+       #endif
+       
+       #if( DNS_SD_DIRECT_ENABLED )
+               err = DNSServiceResolve_direct( outRef, inFlags, inInterfaceIndex, inName, inType, inDomain, inCallBack, inContext );
+               goto exit;
+       #else
+               DEBUG_UNUSED( outRef );
+               DEBUG_UNUSED( inFlags );
+               DEBUG_UNUSED( inInterfaceIndex );
+               DEBUG_UNUSED( inName );
+               DEBUG_UNUSED( inType );
+               DEBUG_UNUSED( inDomain );
+               DEBUG_UNUSED( inCallBack );
+               DEBUG_UNUSED( inContext );
+               
+               err = kUnsupportedErr;
+               goto exit;
+       #endif
+       
+exit:
+       return( err );
+}
+
+#if 0
+#pragma mark -
+#pragma mark == Special Purpose ==
+#endif
+
+//===========================================================================================================================
+//     DNSServiceConstructFullName
+//
+//     Copied from dnssd_clientstub.c with minimal changes to support NULL/empty name, type, and domain.
+//===========================================================================================================================
+
+int    DNSServiceConstructFullName( char *fullName, const char *service, const char *regtype, const char *domain )
+{
+       size_t len;
+       unsigned char c;
+       char *fn = fullName;
+       const char *s = service;
+       const char *r = regtype;
+       const char *d = domain;
+       
+       if (service && *service)
+       {
+               while(*s)
+               {
+                       c = (unsigned char) *s++;
+                       if (c == '.' || (c == '\\')) *fn++ = '\\';              // escape dot and backslash literals
+                       else if (c <= ' ')                                      // escape non-printable characters
+                       {
+                               *fn++ = '\\';
+                               *fn++ = (char) ('0' + (c / 100));
+                               *fn++ = (char) ('0' + (c / 10) % 10);
+                               c = (unsigned char)('0' + (c % 10));
+                       }
+                       *fn++ = (char) c;
+               }
+               *fn++ = '.';
+       }
+       
+       if (regtype && *regtype)
+       {
+               len = strlen(regtype);
+               if (DomainEndsInDot(regtype)) len--;
+               if (len < 4) return -1;                                 // regtype must end in _udp or _tcp
+               if (strncmp((regtype + len - 4), "_tcp", 4) && strncmp((regtype + len - 4), "_udp", 4)) return -1;
+               while(*r)
+                       *fn++ = *r++;
+               if (!DomainEndsInDot(regtype)) *fn++ = '.';
+       }
+       
+       if (!domain || !(*domain))
+       {
+               domain = "local.";
+               d = domain;
+       }
+       len = strlen(domain);
+       if (!len) return -1;
+       while(*d) 
+               *fn++ = *d++;                                           
+       if (!DomainEndsInDot(domain)) *fn++ = '.';
+       *fn = '\0';
+       return 0;
+}
+
+//===========================================================================================================================
+//     DNSServiceCreateConnection
+//===========================================================================================================================
+
+DNSServiceErrorType    DNSServiceCreateConnection( DNSServiceRef *outRef )
+{
+       DNSServiceErrorType             err;
+       
+       #if( DNS_SD_CLIENT_ENABLED )
+               if( gDNSSDServerCompatible )
+               {
+                       err = DNSServiceCreateConnection_client( outRef, gDNSSDServer );
+                       goto exit;
+               }
+       #endif
+       
+       #if( DNS_SD_DIRECT_ENABLED )
+               err = DNSServiceCreateConnection_direct( outRef );
+               goto exit;
+       #else
+               DEBUG_UNUSED( outRef );
+
+               err = kUnsupportedErr;
+               goto exit;
+       #endif
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     DNSServiceRegisterRecord
+//===========================================================================================================================
+
+DNSServiceErrorType
+       DNSServiceRegisterRecord(
+               DNSServiceRef                                   inRef,
+               DNSRecordRef *                                  outRecordRef,
+               DNSServiceFlags                                 inFlags,
+               uint32_t                                                inInterfaceIndex,
+               const char *                                    inName,   
+               uint16_t                                                inRRType,
+               uint16_t                                                inRRClass,
+               uint16_t                                                inRDataSize,
+               const void *                                    inRData,
+               uint32_t                                                inTTL,
+               DNSServiceRegisterRecordReply   inCallBack,
+               void *                                                  inContext )
+{
+       DNSServiceErrorType             err;
+       
+       #if( DNS_SD_CLIENT_ENABLED )
+               if( gDNSSDServerCompatible )
+               {
+                       err = DNSServiceRegisterRecord_client( inRef, outRecordRef, inFlags, inInterfaceIndex, inName, 
+                               inRRType, inRRClass, inRDataSize, inRData, inTTL, inCallBack, inContext );
+                       goto exit;
+               }
+       #endif
+       
+       #if( DNS_SD_DIRECT_ENABLED )
+               err = DNSServiceRegisterRecord_direct( inRef, outRecordRef, inFlags, inInterfaceIndex, inName, 
+                       inRRType, inRRClass, inRDataSize, inRData, inTTL, inCallBack, inContext );
+               goto exit;
+       #else
+               DEBUG_UNUSED( inRef );
+               DEBUG_UNUSED( outRecordRef );
+               DEBUG_UNUSED( inFlags );
+               DEBUG_UNUSED( inInterfaceIndex );
+               DEBUG_UNUSED( inName );
+               DEBUG_UNUSED( inRRType );
+               DEBUG_UNUSED( inRRClass );
+               DEBUG_UNUSED( inRDataSize );
+               DEBUG_UNUSED( inRData );
+               DEBUG_UNUSED( inTTL );
+               DEBUG_UNUSED( inCallBack );
+               DEBUG_UNUSED( inContext );
+               
+               err = kUnsupportedErr;
+               goto exit;
+       #endif
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     DNSServiceQueryRecord
+//===========================================================================================================================
+
+DNSServiceErrorType
+       DNSServiceQueryRecord(
+               DNSServiceRef *                         outRef,
+               DNSServiceFlags                         inFlags,
+               uint32_t                                        inInterfaceIndex,
+               const char *                            inName,     
+               uint16_t                                        inRRType,
+               uint16_t                                        inRRClass,
+               DNSServiceQueryRecordReply      inCallBack,
+               void *                                          inContext )
+{
+       DNSServiceErrorType             err;
+       
+       #if( DNS_SD_CLIENT_ENABLED )
+               if( gDNSSDServerCompatible )
+               {
+                       err = DNSServiceQueryRecord_client( outRef, gDNSSDServer, inFlags, inInterfaceIndex, inName, inRRType, inRRClass, 
+                               inCallBack, inContext );
+                       goto exit;
+               }
+       #endif
+       
+       #if( DNS_SD_DIRECT_ENABLED )
+               err = DNSServiceQueryRecord_direct( outRef, inFlags, inInterfaceIndex, inName, inRRType, inRRClass, 
+                       inCallBack, inContext );
+               goto exit;
+       #else
+               DEBUG_UNUSED( outRef );
+               DEBUG_UNUSED( inFlags );
+               DEBUG_UNUSED( inName );
+               DEBUG_UNUSED( inInterfaceIndex );
+               DEBUG_UNUSED( inName );
+               DEBUG_UNUSED( inRRType );
+               DEBUG_UNUSED( inRRClass );
+               DEBUG_UNUSED( inCallBack );
+               DEBUG_UNUSED( inContext );
+               
+               err = kUnsupportedErr;
+               goto exit;
+       #endif
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     DNSServiceReconfirmRecord
+//===========================================================================================================================
+
+void
+       DNSServiceReconfirmRecord(
+               DNSServiceFlags inFlags,
+               uint32_t                inInterfaceIndex,
+               const char *    inName,   
+               uint16_t                inRRType,
+               uint16_t                inRRClass,
+               uint16_t                inRDataSize,
+               const void *    inRData )
+{
+       #if( DNS_SD_CLIENT_ENABLED )
+               if( gDNSSDServerCompatible )
+               {
+                       DNSServiceReconfirmRecord_client( gDNSSDServer, inFlags, inInterfaceIndex, inName, inRRType, inRRClass, 
+                               inRDataSize, inRData );
+                       goto exit;
+               }
+       #endif
+       
+       #if( DNS_SD_DIRECT_ENABLED )
+               DNSServiceReconfirmRecord_direct( inFlags, inInterfaceIndex, inName, inRRType, inRRClass, inRDataSize, inRData );
+               goto exit;
+       #else
+               DEBUG_UNUSED( inFlags );
+               DEBUG_UNUSED( inInterfaceIndex );
+               DEBUG_UNUSED( inName );
+               DEBUG_UNUSED( inRRType );
+               DEBUG_UNUSED( inRRClass );
+               DEBUG_UNUSED( inRDataSize );
+               DEBUG_UNUSED( inRData );
+
+               goto exit;
+       #endif
+       
+exit:
+       return;
+}
+
+#if 0
+#pragma mark -
+#pragma mark == Utilities ==
+#endif
+
+//===========================================================================================================================
+//     DomainEndsInDot
+//
+//     Copied from dnssd_clientstub.c.
+//===========================================================================================================================
+
+DEBUG_LOCAL int DomainEndsInDot( const char *dom )
+{
+       check( dom );
+       
+       while(*dom && *(dom + 1))
+       {
+               if (*dom == '\\')       // advance past escaped byte sequence
+               {               
+                       if (*(dom + 1) >= '0' && *(dom + 1) <= '9') dom += 4;
+                       else dom += 2;
+               }
+               else dom++;             // else read one character
+       }
+       return (*dom == '.');
+}
+
+#if 0
+#pragma mark -
+#pragma mark == TXT Record Building ==
+#endif
+
+//===========================================================================================================================
+//     Structures
+//===========================================================================================================================
+
+typedef struct _TXTRecordRef_t         _TXTRecordRef_t;
+struct _TXTRecordRef_t
+{
+       uint8_t *               txt;
+       uint16_t                size;
+};
+
+//===========================================================================================================================
+//     Prototypes
+//===========================================================================================================================
+
+DEBUG_LOCAL DNSServiceErrorType
+       TXTRecordGetValuePtrInternal( 
+               uint16_t                inTXTSize, 
+               const void *    inTXTBytes, 
+               const char *    inKey, 
+               uint8_t **              outItem, 
+               uint16_t *              outItemSize, 
+               const void **   outValue, 
+               uint8_t *               outValueSize );
+
+DEBUG_LOCAL DNSServiceErrorType
+       TXTRecordGetItemAtIndexInternal( 
+               uint16_t                inTXTSize, 
+               const void *    inTXTBytes, 
+               uint16_t                inIndex, 
+               uint8_t **              outItem, 
+               uint16_t *              outItemSize, 
+               char *                  inKeyBuffer, 
+               const void **   outValue, 
+               uint8_t *               outValueSize );
+
+DEBUG_LOCAL int        TXTRecordMemEqv( const void *inLeft, size_t inLeftSize, const void *inRight, size_t inRightSize );
+
+//===========================================================================================================================
+//     TXTRecordCreate
+//===========================================================================================================================
+
+DNSServiceErrorType    TXTRecordCreate( TXTRecordRef *outRef )
+{
+       DNSServiceErrorType             err;
+       TXTRecordRef                    obj;
+       
+       require_action_expect( outRef, exit, err = kDNSServiceErr_BadParam );
+               
+       obj = (TXTRecordRef) calloc( 1, sizeof( *obj ) );
+       require_action( obj, exit, err = kDNSServiceErr_NoMemory );
+       
+       *outRef = obj;
+       err = kDNSServiceErr_NoError;
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     TXTRecordDeallocate
+//===========================================================================================================================
+
+void   TXTRecordDeallocate( TXTRecordRef inRef )
+{
+       check( inRef );
+       if( inRef )
+       {
+               if( inRef->txt ) free( inRef->txt );
+               free( inRef );
+       }
+}
+
+//===========================================================================================================================
+//     TXTRecordSetValue
+//===========================================================================================================================
+
+DNSServiceErrorType    TXTRecordSetValue( TXTRecordRef inRef, const char *inKey, uint8_t inValueSize, const void *inValue )
+{
+       DNSServiceErrorType             err;
+       const char *                    p;
+       size_t                                  keySize;
+       uint8_t *                               item;
+       uint8_t *                               itemEnd;
+       uintptr_t                               itemOffset;
+       uint16_t                                oldItemSize;
+       uint16_t                                newItemSize;
+       uint16_t                                delta;
+       uint8_t *                               txt;
+       
+       require_action_expect( inRef, exit, err = kDNSServiceErr_BadParam );
+       require_action_expect( inKey, exit, err = kDNSServiceErr_BadParam );
+       require_action_expect( inValue || ( inValueSize == 0 ), exit, err = kDNSServiceErr_BadParam );
+       
+       // Make sure the key is printable US-ASCII values (0x20-0x7E), excluding '=' (0x3D).
+       
+       for( p = inKey; *p != '\0'; ++p )
+       {
+               if( ( *p < 0x20 ) || ( *p > 0x7E ) || ( *p == 0x3D ) )
+               {
+                       break;
+               }
+       }
+       keySize = (size_t)( p - inKey );
+       require_action( ( keySize > 0 ) && ( keySize <= 255 ) && ( *p == '\0' ), exit, err = kDNSServiceErr_Invalid );
+       
+       // Make sure the total item size does not exceed 255 bytes.
+       
+       newItemSize = (uint16_t) keySize;
+       if( inValue ) newItemSize += 1;         // Add '=' (only if there is a non-NULL value)
+       newItemSize = (uint16_t)( newItemSize + inValueSize );
+       require_action( newItemSize <= 255, exit, err = kDNSServiceErr_Invalid );
+       
+       // Search for an existing item with the same key. If found, replace its value. Otherwise, append a new item.
+       
+       err = TXTRecordGetValuePtrInternal( inRef->size, inRef->txt, inKey, &item, &oldItemSize, NULL, NULL );
+       if( err == kDNSServiceErr_NoError )
+       {
+               if( newItemSize > oldItemSize )
+               {
+                       // Expand the buffer then shift subsequent item(s) forward to make room for the larger value.
+                       // Note: this saves off and restores the item pointer since the pointer is invalidated by realloc.
+                       
+                       itemOffset = (uintptr_t)( item - inRef->txt );
+                       delta = (uint16_t)( newItemSize - oldItemSize );
+                       txt = (uint8_t *) realloc( inRef->txt, (size_t)( inRef->size + delta ) );
+                       require_action( txt, exit, err = kDNSServiceErr_NoMemory );
+                       
+                       item    = txt + itemOffset;
+                       itemEnd = item + ( 1 + oldItemSize );
+                       memmove( item + ( 1 + newItemSize ), itemEnd, (size_t)( ( inRef->txt + inRef->size ) - itemEnd ) );
+                       inRef->txt  = txt;
+                       inRef->size = (uint16_t)( inRef->size + delta );
+               }
+               else if( newItemSize < oldItemSize )
+               {
+                       // Shift subsequent item(s) backward to take up the slack then shrink the buffer to fit.
+                       // Note: this saves off and restores the item pointer since the pointer is invalidated by realloc.
+                       
+                       itemEnd = item + ( 1 + oldItemSize );
+                       memmove( item + ( 1 + newItemSize ), itemEnd, (size_t)( ( inRef->txt + inRef->size ) - itemEnd ) );
+                       
+                       itemOffset = (uintptr_t)( item - inRef->txt );
+                       inRef->size -= ( oldItemSize - newItemSize );
+                       txt = (uint8_t *) realloc( inRef->txt, inRef->size );
+                       require_action( txt, exit, err = kDNSServiceErr_NoMemory );
+                       
+                       item            = txt + itemOffset;
+                       inRef->txt      = txt;
+               }
+       }
+       else
+       {
+               // Resize the buffer to hold the new item.
+               
+               delta = (uint16_t)( 1 + newItemSize );
+               txt = (uint8_t *) realloc( inRef->txt, (size_t)( inRef->size + delta ) );
+               require_action( txt, exit, err = kDNSServiceErr_NoMemory );
+               
+               item            = txt + inRef->size;
+               inRef->txt  = txt;
+               inRef->size     = (uint16_t)( inRef->size + delta );
+       }
+       
+       // Write the new key/value pair to the TXT record in the form key[=<value>].
+       // Note: This always writes the entire item to handle case changes in the key.
+       
+       *item++ = (uint8_t) newItemSize;
+       memcpy( item, inKey, keySize );
+       item += keySize;
+       if( inValue ) *item++ = '=';    // Add '=' (only if there is a non-NULL value)
+       memcpy( item, inValue, inValueSize );
+       err = kDNSServiceErr_NoError;
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     TXTRecordRemoveValue
+//===========================================================================================================================
+
+DNSServiceErrorType    TXTRecordRemoveValue( TXTRecordRef inRef, const char *inKey )
+{
+       DNSServiceErrorType             err;
+       uint8_t *                               item;
+       uint8_t *                               itemEnd;
+       uint16_t                                size;
+       uint8_t *                               txt;
+       uint8_t *                               txtEnd;
+       
+       err = TXTRecordGetValuePtrInternal( inRef->size, inRef->txt, inKey, &item, &size, NULL, NULL );
+       require_noerr_quiet( err, exit );
+       
+       // Shift subsequent item(s) back to take up the slack of removing the item.
+       
+       itemEnd = item + ( 1 + size );
+       txtEnd  = inRef->txt + inRef->size;
+       if( itemEnd < txtEnd )
+       {
+               memmove( item, itemEnd, (size_t)( txtEnd - itemEnd ) );
+       }
+       
+       // Shrink the buffer to fit. If size goes to 0, use free because realloc with size 0 is not consistent across platforms.
+       
+       inRef->size = (uint16_t)( inRef->size - ( (uint16_t)( itemEnd - item ) ) );
+       if( inRef->size > 0 )
+       {
+               txt = (uint8_t *) realloc( inRef->txt, inRef->size );
+               require_action_quiet( txt, exit, err = kDNSServiceErr_Unknown );
+       }
+       else
+       {
+               free( inRef->txt );
+               txt = NULL;
+       }
+       inRef->txt = txt;
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     TXTRecordGetLength
+//===========================================================================================================================
+
+uint16_t       TXTRecordGetLength( TXTRecordRef inRef )
+{
+       check( inRef );
+       
+       if( inRef && inRef->txt )
+       {
+               return( inRef->size );
+       }
+       return( 0 );
+}
+
+//===========================================================================================================================
+//     TXTRecordGetBytesPtr
+//===========================================================================================================================
+
+const void *   TXTRecordGetBytesPtr( TXTRecordRef inRef )
+{
+       check( inRef );
+       
+       if( inRef && inRef->txt )
+       {
+               return( inRef->txt );
+       }
+       return( NULL );
+}
+
+#if 0
+#pragma mark -
+#pragma mark == TXT Record Parsing ==
+#endif
+
+//===========================================================================================================================
+//     TXTRecordGetValuePtr
+//===========================================================================================================================
+
+DNSServiceErrorType
+       TXTRecordGetValuePtr( 
+               uint16_t                inTXTSize, 
+               const void *    inTXTBytes, 
+               const char *    inKey, 
+               const void **   outValue, 
+               uint8_t *               outValueSize )
+{
+       return( TXTRecordGetValuePtrInternal( inTXTSize, inTXTBytes, inKey, NULL, NULL, outValue, outValueSize ) );
+}
+
+//===========================================================================================================================
+//     TXTRecordGetCount
+//===========================================================================================================================
+
+uint16_t       TXTRecordGetCount( uint16_t inTXTSize, const void *inTXTBytes )
+{
+       uint16_t                        n;
+       const uint8_t *         p;
+       const uint8_t *         q;
+       
+       require_action( inTXTBytes, exit, n = 0 );
+       
+       n = 0;
+       p = (const uint8_t *) inTXTBytes;
+       q = p + inTXTSize;
+       while( p < q )
+       {
+               ++n;
+               p += ( 1 + *p );
+               require_action( p <= q, exit, n = 0 );
+       }
+       
+exit:
+       return( n );
+}
+
+//===========================================================================================================================
+//     TXTRecordGetItemAtIndex
+//===========================================================================================================================
+
+DNSServiceErrorType
+       TXTRecordGetItemAtIndex( 
+               uint16_t                inTXTSize, 
+               const void *    inTXTBytes, 
+               uint16_t                inIndex, 
+               char *                  inKeyBuffer, 
+               const void **   outValue, 
+               uint8_t *               outValueSize )
+{
+       return( TXTRecordGetItemAtIndexInternal( inTXTSize, inTXTBytes, inIndex, NULL, NULL, inKeyBuffer, outValue, outValueSize ) );
+}
+
+#if 0
+#pragma mark -
+#pragma mark == TXT Record Internal ==
+#endif
+
+//===========================================================================================================================
+//     TXTRecordGetValuePtrInternal
+//===========================================================================================================================
+
+DEBUG_LOCAL DNSServiceErrorType
+       TXTRecordGetValuePtrInternal( 
+               uint16_t                inTXTSize, 
+               const void *    inTXTBytes, 
+               const char *    inKey, 
+               uint8_t **              outItem, 
+               uint16_t *              outItemSize, 
+               const void **   outValue, 
+               uint8_t *               outValueSize )
+{
+       DNSServiceErrorType             err;
+       size_t                                  keySize;
+       const uint8_t *                 p;
+       const uint8_t *                 q;
+       const uint8_t *                 r;
+       const uint8_t *                 key;
+       const uint8_t *                 keyEnd;
+       const uint8_t *                 value;
+       const uint8_t *                 valueEnd;
+       
+       require_action_quiet( inTXTBytes, exit, err = kDNSServiceErr_NoSuchKey );
+       require_action_expect( inKey, exit, err = kDNSServiceErr_BadParam );
+       keySize = strlen( inKey );
+       
+       // The following initializations are not necessary, but some compilers warn because they cannot detect it.
+       
+       keyEnd   = NULL;
+       value    = NULL;
+       valueEnd = NULL;
+       
+       // Find the item with the specified key.
+       
+       p = (const uint8_t *) inTXTBytes;
+       q = p + inTXTSize;
+       while( p < q )
+       {
+               // Parse the key/value tokens. No '=' means the key takes up the entire item.
+               
+               r = p + ( 1 + *p );
+               require_action( r <= q, exit, err = kDNSServiceErr_Invalid );
+               
+               key             = p + 1;
+               keyEnd  = (const uint8_t *) memchr( key, '=', *p );
+               if( keyEnd )
+               {
+                       value = keyEnd + 1;
+               }
+               else
+               {
+                       keyEnd  = r;
+                       value   = r;
+               }
+               valueEnd = r;
+               if( TXTRecordMemEqv( key, (size_t)( keyEnd - key ), inKey, keySize ) == 0 )
+               {
+                       break;
+               }
+               
+               p = r;
+               check( p <= q );
+       }
+       require_action_quiet( p < q, exit, err = kDNSServiceErr_NoSuchKey );    
+       
+       // Fill in the results the caller wants.
+       
+       if( outItem )           *outItem                = (uint8_t *) p;
+       if( outItemSize )       *outItemSize    = *p;
+       if( outValue )          *outValue               = ( value == keyEnd ) ? NULL : value;   // NULL value ptr means no value.
+       if( outValueSize )      *outValueSize   = (uint8_t)( valueEnd - value );
+       err = kDNSServiceErr_NoError;
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     TXTRecordGetItemAtIndexInternal
+//===========================================================================================================================
+
+DEBUG_LOCAL DNSServiceErrorType
+       TXTRecordGetItemAtIndexInternal( 
+               uint16_t                inTXTSize, 
+               const void *    inTXTBytes, 
+               uint16_t                inIndex, 
+               uint8_t **              outItem, 
+               uint16_t *              outItemSize, 
+               char *                  inKeyBuffer, 
+               const void **   outValue, 
+               uint8_t *               outValueSize )
+{
+       DNSServiceErrorType             err;
+       uint16_t                                n;
+       const uint8_t *                 p;
+       const uint8_t *                 q;
+       const uint8_t *                 r;
+       const uint8_t *                 key;
+       const uint8_t *                 keyEnd;
+       const uint8_t *                 value;
+       const uint8_t *                 valueEnd;
+       
+       require_action_quiet( inTXTBytes, exit, err = kDNSServiceErr_Invalid );
+       
+       // Find the Nth item in the TXT record.
+       
+       n = 0;
+       p = (const uint8_t *) inTXTBytes;
+       q = p + inTXTSize;
+       while( p < q )
+       {
+               if( n == inIndex ) break;
+               ++n;
+               
+               p += ( 1 + *p );
+               require_action( p <= q, exit, err = kDNSServiceErr_Invalid );
+       }
+       require_action_quiet( p < q, exit, err = kDNSServiceErr_Invalid );
+       
+       // Item found. Parse the key/value tokens. No '=' means the key takes up the entire item.
+       
+       r = p + ( 1 + *p );
+       require_action( r <= q, exit, err = kDNSServiceErr_Invalid );
+       
+       key             = p + 1;
+       keyEnd  = (const uint8_t *) memchr( key, '=', *p );
+       if( keyEnd )
+       {
+               value = keyEnd + 1;
+       }
+       else
+       {
+               keyEnd  = r;
+               value   = r;
+       }
+       valueEnd = r;
+       
+       // Fill in the results the caller wants.
+       
+       if( outItem )           *outItem                = (uint8_t *) p;
+       if( outItemSize )       *outItemSize    = *p;
+       if( inKeyBuffer )
+       {
+               n = (uint16_t)( keyEnd - key );
+               memcpy( inKeyBuffer, key, n );
+               inKeyBuffer[ n ] = '\0';
+       }
+       if( outValue )          *outValue               = ( value == keyEnd ) ? NULL : value;   // NULL value ptr means no value.
+       if( outValueSize )      *outValueSize   = (uint8_t)( valueEnd - value );
+       err = kDNSServiceErr_NoError;
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     TXTRecordMemEqv
+//===========================================================================================================================
+
+DEBUG_LOCAL int        TXTRecordMemEqv( const void *inLeft, size_t inLeftSize, const void *inRight, size_t inRightSize )
+{
+       const uint8_t *         p1;
+       const uint8_t *         p2;
+       const uint8_t *         end;
+       int                                     c1;
+       int                                     c2;
+       
+       if( inLeftSize < inRightSize ) return( -1 );
+       if( inLeftSize > inRightSize ) return(  1 );
+       
+       p1  = (const uint8_t *) inLeft;
+       p2  = (const uint8_t *) inRight;
+       end = p1 + inLeftSize;
+       while( p1 < end )
+       {
+               c1 = tolower( *p1 );
+               c2 = tolower( *p2 );
+               if( c1 < c2 ) return( -1 );
+               if( c1 > c2 ) return(  1 );
+               
+               ++p1;
+               ++p2;
+       }
+       return( 0 );
+}
+
+#if( DEBUG )
+//===========================================================================================================================
+//     TXTRecordTest
+//===========================================================================================================================
+
+DNSServiceErrorType    TXTRecordTest( void );
+
+DNSServiceErrorType    TXTRecordTest( void )
+{
+       DNSServiceErrorType             err;
+       const char *                    s;
+       TXTRecordRef                    ref;
+       const void *                    txt;
+       uint16_t                                size;
+       uint16_t                                n;
+       char                                    key[ 256 ];
+       const void *                    value;
+       uint8_t                                 valueSize;
+       
+       // Create Existing Test
+       
+       s = "\014Anon Allowed"
+               "\010Options="
+               "\025InstalledPlugins=JPEG";
+       size = (uint16_t) strlen( s );
+       
+       n = TXTRecordGetCount( size, s );
+       require_action( n == 3, exit, err = kDNSServiceErr_Unknown );
+       
+       err = TXTRecordGetValuePtr( size, s, "test", NULL, NULL );
+       require_action( err != kDNSServiceErr_NoError, exit, err = kDNSServiceErr_Unknown );
+       
+       err = TXTRecordGetValuePtr( size, s, "Anon", NULL, NULL );
+       require_action( err != kDNSServiceErr_NoError, exit, err = kDNSServiceErr_Unknown );
+       
+       err = TXTRecordGetValuePtr( size, s, "Allowed", NULL, NULL );
+       require_action( err != kDNSServiceErr_NoError, exit, err = kDNSServiceErr_Unknown );
+       
+       err = TXTRecordGetValuePtr( size, s, "", NULL, NULL );
+       require_action( err != kDNSServiceErr_NoError, exit, err = kDNSServiceErr_Unknown );
+       
+       err = TXTRecordGetValuePtr( size, s, "Anon Allowed", &value, &valueSize );
+       require_noerr( err, exit );
+       require_action( value == NULL, exit, err = kDNSServiceErr_Unknown );
+       require_action( valueSize == 0, exit, err = kDNSServiceErr_Unknown );
+       
+       err = TXTRecordGetValuePtr( size, s, "Options", &value, &valueSize );
+       require_noerr( err, exit );
+       require_action( value != NULL, exit, err = kDNSServiceErr_Unknown );
+       require_action( valueSize == 0, exit, err = kDNSServiceErr_Unknown );
+       
+       err = TXTRecordGetValuePtr( size, s, "InstalledPlugins", &value, &valueSize );
+       require_noerr( err, exit );
+       require_action( valueSize == 4, exit, err = kDNSServiceErr_Unknown );
+       require_action( memcmp( value, "JPEG", 4 ) == 0, exit, err = kDNSServiceErr_Unknown );
+       
+       key[ 0 ] = '\0';
+       err = TXTRecordGetItemAtIndex( size, s, 0, key, &value, &valueSize );
+       require_noerr( err, exit );
+       require_action( strcmp( key, "Anon Allowed" ) == 0, exit, err = kDNSServiceErr_Unknown );
+       require_action( value == NULL, exit, err = kDNSServiceErr_Unknown );
+       require_action( valueSize == 0, exit, err = kDNSServiceErr_Unknown );
+       
+       key[ 0 ] = '\0';
+       err = TXTRecordGetItemAtIndex( size, s, 1, key, &value, &valueSize );
+       require_noerr( err, exit );
+       require_action( strcmp( key, "Options" ) == 0, exit, err = kDNSServiceErr_Unknown );
+       require_action( value != NULL, exit, err = kDNSServiceErr_Unknown );
+       require_action( valueSize == 0, exit, err = kDNSServiceErr_Unknown );
+       
+       key[ 0 ] = '\0';
+       err = TXTRecordGetItemAtIndex( size, s, 2, key, &value, &valueSize );
+       require_noerr( err, exit );
+       require_action( strcmp( key, "InstalledPlugins" ) == 0, exit, err = kDNSServiceErr_Unknown );
+       require_action( value != NULL, exit, err = kDNSServiceErr_Unknown );
+       require_action( valueSize == 4, exit, err = kDNSServiceErr_Unknown );
+       require_action( memcmp( value, "JPEG", valueSize ) == 0, exit, err = kDNSServiceErr_Unknown );
+       
+       key[ 0 ] = '\0';
+       err = TXTRecordGetItemAtIndex( size, s, 3, key, &value, &valueSize );
+       require_action( err != kDNSServiceErr_NoError, exit, err = kDNSServiceErr_Unknown );
+               
+       // Empty Test
+       
+       err = TXTRecordCreate( &ref );
+       require_noerr( err, exit );
+       
+       txt = TXTRecordGetBytesPtr( ref );
+       require_action( txt == NULL, exit, err = kDNSServiceErr_Unknown );
+       size = TXTRecordGetLength( ref );
+       require_action( size == 0, exit, err = kDNSServiceErr_Unknown );
+                       
+       TXTRecordDeallocate( ref );
+       
+       // Create Single Test
+       
+       err = TXTRecordCreate( &ref );
+       require_noerr( err, exit );
+       
+       err = TXTRecordSetValue( ref, "Anon Allowed", 0, NULL );
+       require_noerr( err, exit );
+       
+       txt = TXTRecordGetBytesPtr( ref );
+       require_action( txt, exit, err = kDNSServiceErr_Unknown );
+       size = TXTRecordGetLength( ref );
+       require_action( size == 13, exit, err = kDNSServiceErr_Unknown );
+       require_action( memcmp( txt, "\014Anon Allowed", size ) == 0, exit, err = kDNSServiceErr_Unknown );
+       
+       n = TXTRecordGetCount( size, txt );
+       require_action( n == 1, exit, err = kDNSServiceErr_Unknown );
+       
+       err = TXTRecordGetValuePtr( size, txt, "test", NULL, NULL );
+       require_action( err != kDNSServiceErr_NoError, exit, err = kDNSServiceErr_Unknown );
+       
+       err = TXTRecordGetValuePtr( size, txt, "Anon", NULL, NULL );
+       require_action( err != kDNSServiceErr_NoError, exit, err = kDNSServiceErr_Unknown );
+       
+       err = TXTRecordGetValuePtr( size, txt, "Allowed", NULL, NULL );
+       require_action( err != kDNSServiceErr_NoError, exit, err = kDNSServiceErr_Unknown );
+       
+       err = TXTRecordGetValuePtr( size, txt, "", NULL, NULL );
+       require_action( err != kDNSServiceErr_NoError, exit, err = kDNSServiceErr_Unknown );
+       
+       err = TXTRecordGetValuePtr( size, txt, "Anon Allowed", &value, &valueSize );
+       require_noerr( err, exit );
+       require_action( value == NULL, exit, err = kDNSServiceErr_Unknown );
+       require_action( valueSize == 0, exit, err = kDNSServiceErr_Unknown );
+       
+       err = TXTRecordGetValuePtr( size, txt, "aNoN aLlOwEd", &value, &valueSize );
+       require_noerr( err, exit );
+       require_action( value == NULL, exit, err = kDNSServiceErr_Unknown );
+       require_action( valueSize == 0, exit, err = kDNSServiceErr_Unknown );
+       
+       TXTRecordDeallocate( ref );
+       
+       // Create Multiple Test
+       
+       err = TXTRecordCreate( &ref );
+       require_noerr( err, exit );
+       
+       err = TXTRecordSetValue( ref, "Anon Allowed", 0, NULL );
+       require_noerr( err, exit );
+       
+       err = TXTRecordSetValue( ref, "Options", 0, "" );
+       require_noerr( err, exit );
+       
+       err = TXTRecordSetValue( ref, "InstalledPlugins", 4, "JPEG" );
+       require_noerr( err, exit );
+       
+       txt = TXTRecordGetBytesPtr( ref );
+       require_action( txt, exit, err = kDNSServiceErr_Unknown );
+       size = TXTRecordGetLength( ref );
+       require_action( size == 44, exit, err = kDNSServiceErr_Unknown );
+       require_action( memcmp( txt, 
+               "\014Anon Allowed"
+               "\010Options="
+               "\025InstalledPlugins=JPEG", 
+               size ) == 0, exit, err = kDNSServiceErr_Unknown );
+       
+       n = TXTRecordGetCount( size, txt );
+       require_action( n == 3, exit, err = kDNSServiceErr_Unknown );
+       
+       err = TXTRecordGetValuePtr( size, txt, "test", NULL, NULL );
+       require_action( err != kDNSServiceErr_NoError, exit, err = kDNSServiceErr_Unknown );
+       
+       err = TXTRecordGetValuePtr( size, txt, "Anon", NULL, NULL );
+       require_action( err != kDNSServiceErr_NoError, exit, err = kDNSServiceErr_Unknown );
+       
+       err = TXTRecordGetValuePtr( size, txt, "Allowed", NULL, NULL );
+       require_action( err != kDNSServiceErr_NoError, exit, err = kDNSServiceErr_Unknown );
+       
+       err = TXTRecordGetValuePtr( size, txt, "", NULL, NULL );
+       require_action( err != kDNSServiceErr_NoError, exit, err = kDNSServiceErr_Unknown );
+       
+       err = TXTRecordGetValuePtr( size, txt, "Anon Allowed", &value, &valueSize );
+       require_noerr( err, exit );
+       require_action( value == NULL, exit, err = kDNSServiceErr_Unknown );
+       require_action( valueSize == 0, exit, err = kDNSServiceErr_Unknown );
+       
+       err = TXTRecordGetValuePtr( size, txt, "Options", &value, &valueSize );
+       require_noerr( err, exit );
+       require_action( value != NULL, exit, err = kDNSServiceErr_Unknown );
+       require_action( valueSize == 0, exit, err = kDNSServiceErr_Unknown );
+       
+       err = TXTRecordGetValuePtr( size, txt, "InstalledPlugins", &value, &valueSize );
+       require_noerr( err, exit );
+       require_action( valueSize == 4, exit, err = kDNSServiceErr_Unknown );
+       require_action( memcmp( value, "JPEG", 4 ) == 0, exit, err = kDNSServiceErr_Unknown );
+       
+       TXTRecordDeallocate( ref );
+       
+       // Remove Single Test
+       
+       err = TXTRecordCreate( &ref );
+       require_noerr( err, exit );
+       
+       err = TXTRecordSetValue( ref, "Anon Allowed", 0, NULL );
+       require_noerr( err, exit );
+       
+       err = TXTRecordRemoveValue( ref, "Anon Allowed" );
+       require_noerr( err, exit );
+       
+       txt = TXTRecordGetBytesPtr( ref );
+       require_action( txt == NULL, exit, err = kDNSServiceErr_Unknown );
+       size = TXTRecordGetLength( ref );
+       require_action( size == 0, exit, err = kDNSServiceErr_Unknown );
+       
+       TXTRecordDeallocate( ref );
+       
+       // Remove Multiple Test
+       
+       err = TXTRecordCreate( &ref );
+       require_noerr( err, exit );
+       
+       err = TXTRecordSetValue( ref, "Anon Allowed", 0, NULL );
+       require_noerr( err, exit );
+       
+       err = TXTRecordSetValue( ref, "Options", 0, "" );
+       require_noerr( err, exit );
+       
+       err = TXTRecordSetValue( ref, "InstalledPlugins", 4, "JPEG" );
+       require_noerr( err, exit );
+       
+       err = TXTRecordRemoveValue( ref, "Options" );
+       require_noerr( err, exit );
+
+       txt = TXTRecordGetBytesPtr( ref );
+       require_action( txt, exit, err = kDNSServiceErr_Unknown );
+       size = TXTRecordGetLength( ref );
+       require_action( size == 35, exit, err = kDNSServiceErr_Unknown );
+       require_action( memcmp( txt, 
+               "\014Anon Allowed"
+               "\025InstalledPlugins=JPEG", 
+               size ) == 0, exit, err = kDNSServiceErr_Unknown );
+       
+       n = TXTRecordGetCount( size, txt );
+       require_action( n == 2, exit, err = kDNSServiceErr_Unknown );
+
+       err = TXTRecordRemoveValue( ref, "Anon Allowed" );
+       require_noerr( err, exit );
+
+       txt = TXTRecordGetBytesPtr( ref );
+       require_action( txt, exit, err = kDNSServiceErr_Unknown );
+       size = TXTRecordGetLength( ref );
+       require_action( size == 22, exit, err = kDNSServiceErr_Unknown );
+       require_action( memcmp( txt, 
+               "\025InstalledPlugins=JPEG", 
+               size ) == 0, exit, err = kDNSServiceErr_Unknown );
+       
+       n = TXTRecordGetCount( size, txt );
+       require_action( n == 1, exit, err = kDNSServiceErr_Unknown );
+       
+       err = TXTRecordRemoveValue( ref, "InstalledPlugins" );
+       require_noerr( err, exit );
+
+       txt = TXTRecordGetBytesPtr( ref );
+       require_action( txt == NULL, exit, err = kDNSServiceErr_Unknown );
+       size = TXTRecordGetLength( ref );
+       require_action( size == 0, exit, err = kDNSServiceErr_Unknown );
+               
+       TXTRecordDeallocate( ref );
+       
+       // Replace Test
+       
+       err = TXTRecordCreate( &ref );
+       require_noerr( err, exit );
+
+       err = TXTRecordSetValue( ref, "Anon Allowed", 0, NULL );
+       require_noerr( err, exit );
+       
+       err = TXTRecordSetValue( ref, "Anon Allowed", 0, NULL );
+       require_noerr( err, exit );
+       
+       err = TXTRecordSetValue( ref, "Options", 0, "" );
+       require_noerr( err, exit );
+       
+       err = TXTRecordSetValue( ref, "Options", 0, "" );
+       require_noerr( err, exit );
+       
+       err = TXTRecordSetValue( ref, "InstalledPlugins", 4, "JPEG" );
+       require_noerr( err, exit );
+       
+       err = TXTRecordSetValue( ref, "InstalledPlugins", 4, "JPEG" );
+       require_noerr( err, exit );
+       
+       txt = TXTRecordGetBytesPtr( ref );
+       require_action( txt, exit, err = kDNSServiceErr_Unknown );
+       size = TXTRecordGetLength( ref );
+       require_action( size == 44, exit, err = kDNSServiceErr_Unknown );
+       require_action( memcmp( txt, 
+               "\014Anon Allowed"
+               "\010Options="
+               "\025InstalledPlugins=JPEG", 
+               size ) == 0, exit, err = kDNSServiceErr_Unknown );
+       
+       err = TXTRecordSetValue( ref, "Anon Allowed", 4, "test" );
+       require_noerr( err, exit );
+       
+       err = TXTRecordSetValue( ref, "Anon Allowed", 0, "" );
+       require_noerr( err, exit );
+       
+       err = TXTRecordSetValue( ref, "Anon Allowed", 0, NULL );
+       require_noerr( err, exit );
+       
+       err = TXTRecordSetValue( ref, "Anon Allowed", 0, "" );
+       require_noerr( err, exit );
+       
+       err = TXTRecordSetValue( ref, "Anon Allowed", 4, "test" );
+       require_noerr( err, exit );
+       
+       txt = TXTRecordGetBytesPtr( ref );
+       require_action( txt, exit, err = kDNSServiceErr_Unknown );
+       size = TXTRecordGetLength( ref );
+       require_action( size == 49, exit, err = kDNSServiceErr_Unknown );
+       require_action( memcmp( txt, 
+               "\021Anon Allowed=test"
+               "\010Options="
+               "\025InstalledPlugins=JPEG", 
+               size ) == 0, exit, err = kDNSServiceErr_Unknown );
+       
+       TXTRecordDeallocate( ref );
+       
+exit:  
+       return( err );
+}
+#endif // DEBUG
+
+#ifdef __cplusplus
+       }
+#endif
diff --git a/mDNSWindows/DNSSD.h b/mDNSWindows/DNSSD.h
new file mode 100644 (file)
index 0000000..11cd6e3
--- /dev/null
@@ -0,0 +1,1689 @@
+/*
+ * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+
+$Log: DNSSD.h,v $
+Revision 1.7  2004/05/11 03:08:53  bradley
+Updated TXT Record API based on latest proposal. This still includes dynamic TXT record building for
+a final CVS snapshot for private libraries before this functionality is removed from the public API.
+
+Revision 1.6  2004/05/06 18:42:58  ksekar
+General dns_sd.h API cleanup, including the following radars:
+<rdar://problem/3592068>: Remove flags with zero value
+<rdar://problem/3479569>: Passing in NULL causes a crash.
+
+Revision 1.5  2004/05/03 10:34:24  bradley
+Implemented preliminary version of the TXTRecord API.
+
+Revision 1.4  2004/04/15 01:00:05  bradley
+Removed support for automatically querying for A/AAAA records when resolving names. Platforms
+without .local name resolving support will need to manually query for A/AAAA records as needed.
+
+Revision 1.3  2004/04/09 21:03:14  bradley
+Changed port numbers to use network byte order for consistency with other platforms.
+
+Revision 1.2  2004/04/08 09:43:42  bradley
+Changed callback calling conventions to __stdcall so they can be used with C# delegates.
+
+Revision 1.1  2004/01/30 02:45:21  bradley
+High-level implementation of the DNS-SD API. Supports both "direct" (compiled-in mDNSCore) and "client"
+(IPC<->service) usage. Conditionals can exclude either "direct" or "client" to reduce code size.
+
+*/
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @header         DNSSD.h
+       
+       @abstract       DNS Service Discovery provides registration, domain and service discovery, and name resolving support.
+       
+       @discussion     
+       
+       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.
+*/
+
+#ifndef _DNS_SD_H
+#define _DNS_SD_H
+
+#include       "CommonServices.h"
+
+#ifdef __cplusplus
+       extern "C" {
+#endif
+
+#if 0
+#pragma mark == Configuration ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        DNS_SD_DIRECT_ENABLED
+
+       @abstract       Enables or disables DNS-SD direct.
+*/
+
+#if( !defined( DNS_SD_DIRECT_ENABLED ) )
+       #define DNS_SD_DIRECT_ENABLED           1
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        DNS_SD_CLIENT_ENABLED
+
+       @abstract       Enables or disables DNS-SD client.
+*/
+
+#if( !defined( DNS_SD_CLIENT_ENABLED ) )
+       #define DNS_SD_CLIENT_ENABLED           1
+#endif
+
+#if 0
+#pragma mark == Types ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @typedef        DNSServiceRef
+
+       @abstract       Reference to a DNSService object.
+       
+       @discussion
+       
+       Note: client is responsible for serializing access to these structures if they are shared between concurrent threads.
+*/
+
+typedef struct _DNSServiceRef_t *              DNSServiceRef;
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @typedef        DNSRecordRef
+
+       @abstract       Reference to a DNSRecord object.
+       
+       @discussion
+       
+       Note: client is responsible for serializing access to these structures if they are shared between concurrent threads.
+*/
+
+typedef struct _DNSRecordRef_t *               DNSRecordRef;
+
+#if 0
+#pragma mark == Flags ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @typedef        DNSServiceFlags
+
+       @abstract       General flags used in DNS-SD functions.
+       
+       @constant       kDNSServiceFlagsNone
+                                       No flags (makes it clearer to use this symbolic constant rather than using a 0).
+                                       
+       @constant       kDNSServiceFlagsMoreComing
+                                       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 
+                                       (i.e. "Finished", for now), and then update their UI. When MoreComing is not set (i.e. 
+                                       "Finished") 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.
+
+       @constant       kDNSServiceFlagsAdd
+                                       Service or domain has been added during browsing/querying or domain enumeration.
+
+       @constant       kDNSServiceFlagsDefault
+                                       Default domain has been added during domain enumeration.
+       
+       @constant       kDNSServiceFlagsNoAutoRename
+                                       Auto renaming should not be performed. Only valid if a name is explicitly specified when 
+                                       registering a service (i.e. the default name is not used).
+
+       @constant       kDNSServiceFlagsShared
+                                       Shared flag for registering individual records on a connected DNSServiceRef. Indicates that there 
+                                       may be multiple records with this name on the network (e.g. PTR records).
+
+       @constant       kDNSServiceFlagsUnique
+                                       Shared flag for registering individual records on a connected DNSServiceRef. Indicates that the 
+                                       record's name is to be unique on the network (e.g. SRV records).
+
+       @constant       kDNSServiceFlagsBrowseDomains
+                                       Enumerates domains recommended for browsing.
+
+       @constant       kDNSServiceFlagsRegistrationDomains
+                                       Enumerates domains recommended for registration.
+*/
+
+typedef uint32_t               DNSServiceFlags;
+enum
+{
+       kDNSServiceFlagsNone                            = 0, 
+       
+       kDNSServiceFlagsMoreComing                      = ( 1 << 0 ),
+       
+       kDNSServiceFlagsAdd                                     = ( 1 << 1 ),
+       kDNSServiceFlagsDefault                         = ( 1 << 2 ),
+
+       kDNSServiceFlagsNoAutoRename            = ( 1 << 3 ),
+
+       kDNSServiceFlagsShared                          = ( 1 << 4 ),
+       kDNSServiceFlagsUnique                          = ( 1 << 5 ),
+
+       kDNSServiceFlagsBrowseDomains           = ( 1 << 6 ),
+       kDNSServiceFlagsRegistrationDomains     = ( 1 << 7 )
+};
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @enum           DNSServiceInitializeFlags
+
+       @abstract       Flags used with DNSServiceInitialize.
+       
+       @constant       kDNSServiceInitializeFlagsAdvertise
+                                       Indicates that interfaces should be advertised on the network. Software that only performs searches 
+                                       do not need to set this flag.
+
+       @constant       kDNSServiceInitializeFlagsNoServerCheck
+                                       No check for a valid server should be performed. Only applicable if client support is enabled.
+*/
+
+typedef uint32_t               DNSServiceInitializeFlags;
+
+#define        kDNSServiceInitializeFlagsNone                          0
+#define        kDNSServiceInitializeFlagsAdvertise                     ( 1 << 0 )
+#define        kDNSServiceInitializeFlagsNoServerCheck         ( 1 << 1 )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        kDNSServiceMaxDomainName
+
+       @abstract       Maximum length, in bytes, of a domain name represented as an escaped C-String
+*/
+
+#define kDNSServiceMaxDomainName                               1005
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        kDNSServiceInterfaceIndexAny
+
+       @abstract       Interface index to indicate any interface.
+*/
+
+#define        kDNSServiceInterfaceIndexAny                    0
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        kDNSServiceInterfaceIndexAny
+
+       @abstract       Use the local interface only.
+*/
+
+#define        kDNSServiceInterfaceIndexLocalOnly              ( (uint32_t) ~0 )
+
+#if 0
+#pragma mark == Errors ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @typedef        DNSServiceErrorType
+
+       @abstract       Possible error code values.
+*/
+
+typedef int32_t                DNSServiceErrorType;
+enum
+{
+       // Error codes are in the range FFFE FF00 (-65792) to FFFE FFFF (-65537)
+
+       kDNSServiceErr_NoError                                  = 0,
+       kDNSServiceErr_Unknown                                  = -65537,       // 0xFFFE FFFF (first error code)
+       kDNSServiceErr_NoSuchName                               = -65538,
+       kDNSServiceErr_NoMemory                                 = -65539,
+       kDNSServiceErr_BadParam                                 = -65540,
+       kDNSServiceErr_BadReference                             = -65541,
+       kDNSServiceErr_BadState                                 = -65542,
+       kDNSServiceErr_BadFlags                                 = -65543,
+       kDNSServiceErr_Unsupported                              = -65544,
+       kDNSServiceErr_NotInitialized                   = -65545,
+       kDNSServiceErr_NoCache                                  = -65546,
+       kDNSServiceErr_AlreadyRegistered                = -65547,
+       kDNSServiceErr_NameConflict                             = -65548,
+       kDNSServiceErr_Invalid                                  = -65549,
+       kDNSServiceErr_Incompatible                             = -65551,
+       kDNSServiceErr_BadInterfaceIndex                = -65552, 
+       kDNSServiceErr_Refused                                  = -65553, 
+       kDNSServiceErr_NoSuchRecord                             = -65554,
+       kDNSServiceErr_NoAuth                                   = -65555,
+       kDNSServiceErr_NoSuchKey                                = -65556, 
+       kDNSServiceErr_NoValue                                  = -65557, 
+       kDNSServiceErr_BufferTooSmall                   = -65558, 
+       
+       // TCP Connection Status
+
+       kDNSServiceErr_ConnectionPending                = -65570,
+       kDNSServiceErr_ConnectionFailed                 = -65571,
+       kDNSServiceErr_ConnectionEstablished    = -65572, 
+
+       // Non-error values
+
+       kDNSServiceErr_GrowCache                                = -65790,
+       kDNSServiceErr_ConfigChanged                    = -65791,
+       kDNSServiceErr_MemFree                                  = -65792        // 0xFFFE FF00 (last error code)
+};
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @var            gDNSSDServer
+
+       @abstract       Global controlling the server to communicate with. Set to NULL for local operation.
+*/
+
+extern const char *            gDNSSDServer;
+
+#if 0
+#pragma mark == DNS Classes ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @enum           DNSServiceDNSClass
+
+       @abstract       DNS Class
+*/
+
+typedef enum                                                                                   // From RFC 1035
+{
+       kDNSServiceDNSClass_IN                                  = 1,            // Internet
+       kDNSServiceDNSClass_CS                                  = 2,            // CSNET
+       kDNSServiceDNSClass_CH                                  = 3,            // CHAOS
+       kDNSServiceDNSClass_HS                                  = 4,            // Hesiod
+       kDNSServiceDNSClass_NONE                                = 254,          // Used in DNS UPDATE [RFC 2136]
+
+       kDNSServiceDNSClass_Mask                                = 0x7FFF,       // Multicast DNS uses the bottom 15 bits to identify the record class...
+       kDNSServiceDNSClass_UniqueRRSet                 = 0x8000,       // ... and the top bit indicates that all other cached records are now invalid
+
+       kDNSServiceDNSQClass_ANY                                = 255,          // Not a DNS class, but a DNS query class, meaning "all classes"
+       kDNSServiceDNSQClass_UnicastResponse    = 0x8000        // Top bit set in a question means "unicast response acceptable"
+       
+}      DNSServiceDNSClass;
+
+#if 0
+#pragma mark == DNS Types ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @enum           DNSServiceDNSType
+
+       @abstract       DNS Type
+*/
+
+typedef enum                                                   // From RFC 1035
+{
+       kDNSServiceDNSType_A            = 1,    // Address
+       kDNSServiceDNSType_NS           = 2,    // Name Server
+       kDNSServiceDNSType_MD           = 3,    // Mail Destination
+       kDNSServiceDNSType_MF           = 4,    // Mail Forwarder
+       kDNSServiceDNSType_CNAME        = 5,    // Canonical Name
+       kDNSServiceDNSType_SOA          = 6,    // Start of Authority
+       kDNSServiceDNSType_MB           = 7,    // Mailbox
+       kDNSServiceDNSType_MG           = 8,    // Mail Group
+       kDNSServiceDNSType_MR           = 9,    // Mail Rename
+       kDNSServiceDNSType_NULL         = 10,   // NULL RR
+       kDNSServiceDNSType_WKS          = 11,   // Well-known-service
+       kDNSServiceDNSType_PTR          = 12,   // Domain name pointer
+       kDNSServiceDNSType_HINFO        = 13,   // Host information
+       kDNSServiceDNSType_MINFO        = 14,   // Mailbox information
+       kDNSServiceDNSType_MX           = 15,   // Mail Exchanger
+       kDNSServiceDNSType_TXT          = 16,   // Arbitrary text string
+       kDNSServiceDNSType_AAAA         = 28,   // IPv6 address
+       kDNSServiceDNSType_SRV          = 33,   // Service record
+       kDNSServiceDNSTypeQType_ANY = 255       // Not a DNS type, but a DNS query type, meaning "all types"
+       
+}      DNSServiceDNSType;
+
+#if 0
+#pragma mark == General ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function  DNSServiceInitialize
+       
+       @abstract       Initializes DNS-SD.
+       
+       @param          inFlags                         Flags to control the initialization process (only applicable for DNS-SD direct).
+       @param          inCacheEntryCount       Size of the cache (only applicable for DNS-SD direct).
+*/
+
+DNSServiceErrorType    DNSServiceInitialize( DNSServiceInitializeFlags inFlags, int inCacheEntryCount );
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function  DNSServiceFinalize
+       
+       @abstract       Finalizes DNS-SD.
+*/
+
+void   DNSServiceFinalize( void );
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function  DNSServiceCheckVersion
+       
+       @abstract       Performs a version check. Mainly only needed when client-mode is enabled to verify the server is compatible.
+*/
+
+DNSServiceErrorType    DNSServiceCheckVersion( void );
+
+#if 0
+#pragma mark == Properties ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @typedef   DNSPropertyCode
+       
+       @abstract       Identifies a property.
+*/
+
+typedef uint32_t       DNSPropertyCode;
+
+#define        kDNSPropertyCodeVersion         0x76657273 // 'vers'
+       // Field:       "version"
+       // Format:      <w:serverCurrentVersion> <w:serverOldestClientVersion> <w:serverOldestServerVersion> 
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @struct            DNSPropertyData
+       
+       @abstract       Data for a property.
+*/
+
+typedef struct DNSPropertyData         DNSPropertyData;
+struct DNSPropertyData
+{
+       DNSPropertyCode         code;
+       
+       union
+       {
+               struct  // version
+               {
+                       uint32_t                clientCurrentVersion;
+                       uint32_t                clientOldestServerVersion;
+                       uint32_t                serverCurrentVersion;
+                       uint32_t                serverOldestClientVersion;
+                       
+               }       version;
+       
+       }       u;
+};
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function  DNSServiceCopyProperty
+       
+       @abstract       Copies a property into a newly allocated buffer.
+       
+       @param          inCode          Property to copy.
+       @param          outData         Receives the copied property data. Must be release with DNSServiceReleaseProperty.
+*/
+
+DNSServiceErrorType    DNSServiceCopyProperty( DNSPropertyCode inCode, DNSPropertyData *outData );
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function  DNSServiceReleaseProperty
+       
+       @abstract       Releases a property copied with a successful call to DNSServiceCopyProperty.
+*/
+
+DNSServiceErrorType    DNSServiceReleaseProperty( DNSPropertyData *inData );
+
+#if 0
+#pragma mark == Unix Domain Socket Access ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function  DNSServiceRefSockFD
+       
+       @param          inRef   A DNSServiceRef initialized by any of the DNSService calls.
+       
+       @result         The DNSServiceRef's underlying socket descriptor, or -1 on error.
+       
+       @discussion
+       
+       Access underlying Unix domain socket for an initialized DNSServiceRef. The DNS Service Discovery implmementation uses 
+       this socket to communicate between the client and the mDNSResponder daemon. The application MUST NOT directly read 
+       from or write to this socket. Access to the socket is provided so that it can be used as a run loop source, or in a 
+       select() loop: when data is available for reading on the socket, DNSServiceProcessResult() should be called, which will 
+       extract the daemon's reply from the socket, and pass it to the appropriate application callback. By using a run loop 
+       or select(), results from the daemon can be processed asynchronously. Without using these constructs, 
+       DNSServiceProcessResult() will block until the response from the daemon arrives. The client is responsible for ensuring 
+       that the data on the socket is processed in a timely fashion - the daemon may terminate its connection with a client 
+       that does not clear its socket buffer.
+*/
+
+int    DNSServiceRefSockFD( DNSServiceRef inRef );
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function  DNSServiceProcessResult
+       
+       @param          inRef   A DNSServiceRef initialized by any of the DNSService calls that take a callback parameter.
+       
+       @result         Returns kDNSServiceErr_NoError on success, otherwise returns an error code indicating the specific failure 
+                               that occurred.
+       
+       @discussion
+       
+       Read a reply from the daemon, calling the appropriate application callback. This call will block until the daemon's 
+       response is received. Use DNSServiceRefSockFD() in conjunction with a run loop or select() to determine the presence 
+       of a response from the server before calling this function to process the reply without blocking. Call this function 
+       at any point if it is acceptable to block until the daemon's response arrives. Note that the client is responsible 
+       for ensuring that DNSServiceProcessResult() is called whenever there is a reply from the daemon - the daemon may 
+       terminate its connection with a client that does not process the daemon's responses.
+*/
+
+DNSServiceErrorType    DNSServiceProcessResult( DNSServiceRef inRef );
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function  DNSServiceRefDeallocate
+       
+       @param          inRef   A DNSServiceRef initialized by any of the DNSService calls.
+               
+       @discussion
+       
+       Terminate a connection with the daemon and free memory associated with the DNSServiceRef. Any services or records 
+       registered with this DNSServiceRef will be deregistered. Any Browse, Resolve, or Query operations called with this 
+       reference will be terminated.
+       
+       Note: If the reference's underlying socket is used in a run loop or select() call, it should be removed BEFORE 
+       DNSServiceRefDeallocate() is called, as this function closes the reference's socket. 
+       
+       Note: If the reference was initialized with DNSServiceCreateConnection(), any DNSRecordRefs created via this reference 
+       will be invalidated by this call - the resource records are deregistered, and their DNSRecordRefs may not be used in 
+       subsequent functions. Similarly, if the reference was initialized with DNSServiceRegister, and an extra resource record 
+       was added to the service via DNSServiceAddRecord(), the DNSRecordRef created by the Add() call is invalidated when this 
+       function is called - the DNSRecordRef may not be used in subsequent functions.
+
+       Note: This call is to be used only with the DNSServiceRef defined by this API. It is not compatible with 
+       dns_service_discovery_ref objects defined in the legacy Mach-based DNSServiceDiscovery.h API.
+*/
+
+void   DNSServiceRefDeallocate( DNSServiceRef inRef );
+
+#if 0
+#pragma mark == Domain Enumeration ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @typedef   DNSServiceDomainEnumReply
+       
+       @abstract       Callback function for DNSServiceEnumerateDomains.
+       
+       @param          inRef
+                                       The DNSServiceRef initialized by DNSServiceEnumerateDomains().
+
+       @param          inFlags
+                                       Possible values are:
+                                       1 (MoreComing)
+                                       2 (Add/Remove)
+                                       4 (Add Default)
+
+       @param          inInterfaceIndex
+                                        Specifies the interface on which the domain exists. (The index for a given interface is determined 
+                                        via the if_nametoindex() family of calls). 
+               
+       @param          inErrorCode
+                                       Will be kDNSServiceErr_NoError (0) on success, otherwise indicates the failure that occurred (other 
+                                       parameters are undefined if errorCode is nonzero).
+       
+       @param          inDomain
+                                       The name of the domain.
+       
+       @param          inContext
+                                        The context pointer passed to DNSServiceEnumerateDomains.
+*/
+
+typedef void
+       ( CALLBACK_COMPAT *DNSServiceDomainEnumReply )(
+               DNSServiceRef                   inRef,
+               DNSServiceFlags                 inFlags,
+               uint32_t                                inInterfaceIndex,
+               DNSServiceErrorType             inErrorCode,
+               const char *                    inDomain,       
+               void *                                  inContext );
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function  DNSServiceEnumerateDomains
+       
+       @abstract       Asynchronously enumerate domains available for browsing and registration.
+       
+       @param          outRef
+                                       A pointer to an uninitialized DNSServiceRef. May be passed to DNSServiceRefDeallocate() to cancel the 
+                                       enumeration.
+
+       @param          inFlags
+                                       Possible values are:
+                                       64 (BrowseDomains) to enumerate domains recommended for browsing.
+                                       128 (RegistrationDomains) to enumerate domains recommended for registration.
+
+       @param          inInterfaceIndex
+                                       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.      
+
+       @param          inCallBack
+                                       The function to be called when a domain is found or the call asynchronously fails.
+
+       @param          inContext
+                                       An application context pointer which is passed to the callback function (may be NULL).
+
+       @result         Returns kDNSServiceErr_NoError on success (any subsequent, asynchronous errors are delivered to the 
+                               callback), otherwise returns an error code indicating the error that occurred (the callback is not invoked 
+                               and the DNSServiceRef is not initialized).
+       
+       @discussion
+       
+       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.
+*/
+
+DNSServiceErrorType
+       DNSServiceEnumerateDomains(
+               DNSServiceRef *                                 outRef,
+               const DNSServiceFlags                   inFlags,
+               const uint32_t                                  inInterfaceIndex,
+               const DNSServiceDomainEnumReply inCallBack,
+               void *                                                  inContext );    // may be NULL
+
+#if 0
+#pragma mark == Service Registration ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @typedef   DNSServiceRegisterReply
+       
+       @abstract       Callback function for DNSServiceRegister.
+       
+       @param          inRef
+                                       The DNSServiceRef initialized by DNSServiceRegister().
+
+       @param          inFlags
+                                       Currently unused, reserved for future use.
+               
+       @param          inErrorCode
+                                       Will be kDNSServiceErr_NoError on success, otherwise will indicate the failure that occurred 
+                                       (including name conflicts, if the kDNSServiceFlagsNoAutoRenameOnConflict flag was passed to the 
+                                       callout). Other parameters are undefined if errorCode is nonzero.
+       
+       @param          inName
+                                       The service name registered (if the application did not specify a name in DNSServiceRegister(), this 
+                                       indicates what name was automatically chosen).
+       
+       @param          inType
+                                       The type of service registered, as it was passed to the callout.
+       
+       @param          inDomain
+                                       The domain on which the service was registered (if the application did not specify a domain in 
+                                       DNSServiceRegister(), this indicates the default domain on which the service was registered).
+
+       @param          inContext
+                                        The context pointer that was passed to the callout.
+*/
+
+typedef void
+       ( CALLBACK_COMPAT *DNSServiceRegisterReply )(
+               DNSServiceRef                   inRef,
+               DNSServiceFlags                 inFlags,
+               DNSServiceErrorType     inErrorCode,
+               const char *                    inName,  
+               const char *                    inType, 
+               const char *                    inDomain,       
+               void *                                  inContext );
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function  DNSServiceRegister
+       
+       @abstract       Register a service that is discovered via Browse() and Resolve() calls.
+       
+       @param          outRef
+                                       A pointer to an uninitialized DNSServiceRef. If this call succeeds, the reference may be passed to 
+                                       DNSServiceRefDeallocate() to deregister the service.
+
+       @param          inInterfaceIndex
+                                       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).
+
+       @param          inFlags
+                                       Indicates the renaming behavior on name conflict (most applications will pass 0). See flag definitions 
+                                       above for details.
+
+       @param          inName
+                                       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).
+
+       @param          inType
+                                       The service type followed by the protocol, separated by a dot (e.g. "_ftp._tcp"). The transport protocol 
+                                       must be "_tcp" or "_udp".
+
+       @param          inDomain
+                                       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).
+
+       @param          inHost
+                                       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().
+
+       @param          inPort
+                                       The port on which the service accepts connections in network byte order. 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.
+
+       @param          inTXTSize
+                                       The length of the txtRecord, in bytes. Must be zero if the txtRecord is NULL.
+
+       @param          inTXT
+                                       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> ...
+
+       @param          inCallBack
+                                       The function to be called when the registration completes or asynchronously fails. The client MAY pass 
+                                       NULL for the callback - The client will NOT be notified 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().
+
+       @param          inContext
+                                       An application context pointer which is passed to the callback function (may be NULL).
+
+       @result         Returns kDNSServiceErr_NoError on success (any subsequent, asynchronous errors are delivered to the 
+                               callback), otherwise returns an error code indicating the error that occurred (the callback is never invoked 
+                               and the DNSServiceRef is not initialized).
+*/
+
+DNSServiceErrorType
+       DNSServiceRegister(
+               DNSServiceRef *                 outRef,
+               DNSServiceFlags                 inFlags,
+               uint32_t                                inInterfaceIndex,
+               const char *                    inName,                 // may be NULL
+               const char *                    inType,
+               const char *                    inDomain,               // may be NULL
+               const char *                    inHost,                 // may be NULL
+               uint16_t                                inPort,
+               uint16_t                                inTXTSize,
+               const void *                    inTXT,                  // may be NULL
+               DNSServiceRegisterReply inCallBack,             // may be NULL
+               void *                                  inContext );    // may be NULL
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function  DNSServiceAddRecord
+       
+       @abstract       Add a record to a registered service.
+       
+       @param          inRef
+                                       A DNSServiceRef initialized by DNSServiceRegister().
+       
+       @param          inRecordRef
+                                       A pointer to an uninitialized DNSRecordRef. Upon succesfull completion of this call, this ref may be 
+                                       passed to DNSServiceUpdateRecord() or DNSServiceRemoveRecord(). If the above DNSServiceRef is passed 
+                                       to DNSServiceRefDeallocate(), RecordRef is also invalidated and may not be used further.
+
+       @param          inFlags
+                                       Currently ignored, reserved for future use.
+
+       @param          inRRType
+                                       The type of the record (e.g. TXT, SRV, etc), as defined in nameser.h.
+
+       @param          inRDataSize
+                                       The length, in bytes, of the rdata.
+
+       @param          inRData
+                                       The raw rdata to be contained in the added resource record.
+
+       @param          inTTL
+                                       The time to live of the resource record, in seconds.
+
+       @result         Returns kDNSServiceErr_NoError on success, otherwise returns an error code indicating the error that 
+                               occurred (the RecordRef is not initialized).
+       
+       @discussion
+       
+       The name of the record will be the same as the registered service's name. The record can later be updated or 
+       deregistered by passing the RecordRef initialized by this function to DNSServiceUpdateRecord() or 
+       DNSServiceRemoveRecord().
+*/
+
+DNSServiceErrorType
+       DNSServiceAddRecord(
+               DNSServiceRef           inRef,
+               DNSRecordRef *          inRecordRef,
+               DNSServiceFlags         inFlags,
+               uint16_t                        inRRType,
+               uint16_t                        inRDataSize,
+               const void *            inRData,
+               uint32_t                        inTTL );
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function  DNSServiceUpdateRecord
+       
+       @abstract       Update a registered resource record.
+       
+       @param          inRef
+                                       A DNSServiceRef that was initialized by DNSServiceRegister() or DNSServiceCreateConnection().
+       
+       @param          inRecordRef
+                                       A DNSRecordRef initialized by DNSServiceAddRecord, or NULL to update the service's primary txt record.
+
+       @param          inFlags
+                                       Currently ignored, reserved for future use.
+
+       @param          inRDataSize
+                                       The length, in bytes, of the new rdata.
+
+       @param          inRData
+                                       The new rdata to be contained in the updated resource record.
+
+       @param          inTTL
+                                       The time to live of the updated resource record, in seconds.
+
+       @result         Returns kDNSServiceErr_NoError on success, otherwise returns an error code indicating the error that occurred.
+       
+       @discussion
+       
+       The record must either be:
+               - The primary txt record of a service registered via DNSServiceRegister()
+               - A record added to a registered service via DNSServiceAddRecord()
+               - An individual record registered by DNSServiceRegisterRecord()
+*/
+
+DNSServiceErrorType
+       DNSServiceUpdateRecord(
+               DNSServiceRef           inRef,
+               DNSRecordRef            inRecordRef,    // may be NULL
+               DNSServiceFlags         inFlags,
+               uint16_t                        inRDataSize,
+               const void *            inRData,
+               uint32_t                        inTTL );
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function  DNSServiceRemoveRecord
+       
+       @abstract       Remove a record previously added to a service record set via DNSServiceAddRecord(), or deregister 
+                               an record registered individually via DNSServiceRegisterRecord().
+       
+       @param          inRef
+                                       A DNSServiceRef that was initialized by DNSServiceRegister() or DNSServiceCreateConnection().
+       
+       @param          inRecordRef
+                                       A DNSRecordRef initialized by a successful call to DNSServiceAddRecord() or DNSServiceRegisterRecord().
+
+       @param          inFlags
+                                       Currently ignored, reserved for future use.
+
+       @result         Returns kDNSServiceErr_NoError on success, otherwise returns an error code indicating the error that occurred.
+*/
+
+DNSServiceErrorType
+       DNSServiceRemoveRecord(
+               DNSServiceRef   inRef,
+               DNSRecordRef    inRecordRef,
+               DNSServiceFlags inFlags );
+
+#if 0
+#pragma mark == Service Discovery ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @typedef   DNSServiceBrowseReply
+       
+       @abstract       Callback function for DNSServiceBrowse.
+       
+       @param          inRef
+                                       The DNSServiceRef initialized by DNSServiceBrowse().
+
+       @param          inFlags
+                                       Possible values are MoreComing and Add/Remove. See flag definitions for details.
+
+       @param          inInterfaceIndex
+                                       The interface on which the service is advertised. This index should be passed to DNSServiceResolve() 
+                                       when resolving the service. 
+               
+       @param          inErrorCode
+                                       Will be kDNSServiceErr_NoError (0) on success, otherwise will indicate the failure that occurred.
+                                       Other parameters are undefined if the errorCode is nonzero.
+       
+       @param          inName
+                                       The service name discovered.
+       
+       @param          inType
+                                       The service type, as passed in to DNSServiceBrowse().
+       
+       @param          inDomain
+                                       The domain on which the service was discovered (if the application did not specify a domain in 
+                                       DNSServicBrowse(), this indicates the domain on which the service was discovered).
+
+       @param          inContext
+                                        The context pointer that was passed to the callout.
+*/
+
+typedef void
+       ( CALLBACK_COMPAT *DNSServiceBrowseReply )(
+               DNSServiceRef                   inRef,
+               DNSServiceFlags                 inFlags,
+               uint32_t                                inInterfaceIndex,
+               DNSServiceErrorType     inErrorCode,
+               const char *                    inName, 
+               const char *                    inType, 
+               const char *                    inDomain,       
+               void *                                  inContext );
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function  DNSServiceBrowse
+       
+       @abstract       Browse for instances of a service.
+       
+       @param          outRef
+                                       A pointer to an uninitialized DNSServiceRef. May be passed to DNSServiceRefDeallocate() to terminate 
+                                       the browse.
+
+       @param          inFlags
+                                       Currently ignored, reserved for future use.
+               
+       @param          inInterfaceIndex
+                                       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.
+       
+       @param          inType
+                                       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".
+       
+       @param          inDomain
+                                       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).
+       
+       @param          inCallBack
+                                       The function to be called when an instance of the service being browsed for is found, or if the call 
+                                       asynchronously fails.
+
+       @param          inContext
+                                        An application context pointer which is passed to the callback function (may be NULL).
+       
+       @result         Returns kDNSServiceErr_NoError on success (any subsequent, asynchronous errors are delivered to the 
+                               callback), otherwise returns an error code indicating the error that occurred (the callback is not invoked 
+                               and the DNSServiceRef is not initialized).
+*/
+
+DNSServiceErrorType
+       DNSServiceBrowse(
+               DNSServiceRef *                 outRef,
+               DNSServiceFlags                 inFlags,
+               uint32_t                                inInterfaceIndex,
+               const char *                    inType, 
+               const char *                    inDomain,                       // may be NULL
+               DNSServiceBrowseReply   inCallBack,
+               void *                                  inContext );            // may be NULL
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @typedef   DNSServiceResolveReply
+       
+       @abstract       Callback function for DNSServiceResolve.
+       
+       @param          inRef
+                                       The DNSServiceRef initialized by DNSServiceResolve().
+
+       @param          inFlags
+                                       Currently unused, reserved for future use.
+
+       @param          inInterfaceIndex
+                                       The interface on which the service was resolved. 
+
+       @param          inErrorCode
+                                       Will be kDNSServiceErr_NoError (0) on success, otherwise will indicate the failure that occurred. 
+                                       Other parameters are undefined if the errorCode is nonzero.
+
+       @param          inFullName
+                                       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.
+
+       @param          inHostName
+                                       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.
+
+       @param          inPort
+                                       The port number on which connections are accepted for this service in network byte order.
+
+       @param          inTXTSize
+                                       The length of the txt record, in bytes.
+
+       @param          inTXT
+                                       The service's primary txt record, in standard txt record format.
+       
+       @param          inContext
+                                       The context pointer that was passed to the callout.
+*/
+
+typedef void
+       ( CALLBACK_COMPAT *DNSServiceResolveReply )(
+               DNSServiceRef                   inRef,
+               DNSServiceFlags                 inFlags,
+               uint32_t                                inInterfaceIndex,
+               DNSServiceErrorType             inErrorCode,
+               const char *                    inFullName,     
+               const char *                    inHostName,
+               uint16_t                                inPort,
+               uint16_t                                inTXTSize,
+               const char *                    inTXT,
+               void *                                  inContext );
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function  DNSServiceResolve
+       
+       @abstract       Resolve a service name discovered via DNSServiceBrowse() to a target host name, port number, and txt record.
+       
+       @param          outRef
+                                       A pointer to an uninitialized DNSServiceRef. May be passed to DNSServiceRefDeallocate() to terminate 
+                                       the resolve.
+
+       @param          inFlags
+                                       Currently unused, reserved for future use.
+
+       @param          inInterfaceIndex
+                                       The interface on which to resolve the service. The client should pass the interface on which the 
+                                       servicename was discovered, i.e. the inInterfaceIndex passed to the DNSServiceBrowseReply callback, or 0 
+                                       to resolve the named service on all available interfaces.
+
+       @param          inName
+                                       The service name to be resolved.
+
+       @param          inType
+                                       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". 
+
+       @param          inDomain
+                                       The domain on which the service is registered, i.e. the domain passed to the DNSServiceBrowseReply 
+                                       callback.
+
+       @param          inCallBack
+                                       The function to be called when a result is found, or if the call asynchronously fails.
+
+       @param          inContext
+                                       An application context pointer which is passed to the callback function (may be NULL).
+
+       @result         Returns kDNSServiceErr_NoError on success (any subsequent, asynchronous errors are delivered to the 
+                               callback), otherwise returns an error code indicating the error that occurred (the callback is never 
+                               invoked and the DNSServiceRef is not initialized). The context pointer that was passed to the callout.
+       
+       @discussion
+       
+       Resolve a service name discovered via DNSServiceBrowse() to a target host name, port number, and txt record.
+
+       Note: Applications should NOT use DNSServiceResolve() solely for txt record monitoring - use DNSServiceQueryRecord() 
+       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 
+       DNSServiceRefDeallocate().
+
+       Note: DNSServiceResolve() 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, 
+       DNSServiceQueryRecord() should be used.
+*/
+
+DNSServiceErrorType
+       DNSServiceResolve( 
+               DNSServiceRef *                 outRef,
+               DNSServiceFlags                 inFlags,
+               uint32_t                                inInterfaceIndex,
+               const char *                    inName,  
+               const char *                    inType, 
+               const char *                    inDomain,       
+               DNSServiceResolveReply  inCallBack,
+               void *                                  inContext );    // may be NULL
+
+#if 0
+#pragma mark == Special Purpose ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function  DNSServiceConstructFullName
+       
+       @abstract       Concatenate a three-part domain name (as returned by the above callbacks) into a properly-escaped full 
+                               domain name. Note that callbacks in the above functions ALREADY ESCAPE strings where necessary.
+       
+       @param          outFullName
+                                       A pointer to a buffer that where the resulting full domain name is to be written. The buffer must be 
+                                       kDNSServiceDiscoveryMaxDomainName (1005) bytes in length to accommodate the longest legal domain name 
+                                       without buffer overrun.
+
+       @param          inName
+                                       The service name - any dots or slashes must NOT be escaped. May be NULL (to construct a PTR record 
+                                       name, e.g. "_ftp._tcp.apple.com").
+
+       @param          inType
+                                       The service type followed by the protocol, separated by a dot (e.g. "_ftp._tcp"). 
+
+       @param          inDomain
+                                       The domain name, e.g. "apple.com". Any literal dots or backslashes must be escaped.
+
+       @result         Returns 0 on success, -1 on error.
+       
+       @discussion
+       
+       DNS Naming Conventions:
+
+       The following functions refer to resource records by their full domain name, unlike the above
+       functions which divide the name into servicename/regtype/domain fields. In the above functions,
+       a dot (".") is considered to be a literal dot in the servicename field (e.g. "Dr. Pepper") and 
+       a label separator in the regtype ("_ftp._tcp") or domain ("apple.com") fields. Literal dots in 
+       the domain field would be escaped with a backslash, and literal backslashes would be escaped with
+       a second backslash (this is generally not an issue, as domain names on the Internet today almost 
+       never use characters other than letters, digits, or hyphens, and the dots are label separators).
+       Furthermore, this is transparent to the caller, so long as the fields are passed between functions 
+       without manipulation. However, the following, special-purpose calls use a single, full domain name. 
+       As such, all dots are considered to be label separators, unless escaped, and all backslashes are 
+       considered to be escape characters, unless preceded by a second backslash. For example, the name 
+       "Dr. Smith \ Dr. Johnson" could be passed literally as a service name parameter in the above calls, 
+       but in the special purpose call, the dots and backslash would have to be escaped 
+       (e.g. "Dr\. Smith \\ Dr\. Johnson._ftp._tcp.apple.com" for an ftp service on the apple.com domain).
+*/
+
+int
+       DNSServiceConstructFullName(
+               char *                  outFullName,
+               const char *    inName,         // may be NULL
+               const char *    inType,
+               const char *    inDomain );
+       
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function  DNSServiceCreateConnection
+       
+       @abstract       Create a connection to the daemon allowing efficient registration of multiple individual records.
+       
+       @param          outRef
+                                       A pointer to an uninitialized DNSServiceRef. Deallocating the reference (via DNSServiceRefDeallocate()) 
+                                       severs the connection and deregisters all records registered on this connection.
+
+       @result         Returns kDNSServiceErr_NoError on success, otherwise returns an error code indicating the specific failure 
+                               that occurred (in which case the DNSServiceRef is not initialized).
+
+*/
+
+DNSServiceErrorType    DNSServiceCreateConnection( DNSServiceRef *outRef );
+ //---------------------------------------------------------------------------------------------------------------------------
+/*! @typedef   DNSServiceRegisterRecordReply
+       
+       @abstract       Callback function for DNSServiceRegisterRecord.
+       
+       @param          inRef
+                                       The connected DNSServiceRef initialized by DNSServiceCreateConnection().
+
+       @param          inRecordRef
+                                       The DNSRecordRef initialized by DNSServiceRegisterRecord(). If the above DNSServiceRef is passed to 
+                                       DNSServiceRefDeallocate(), this DNSRecordRef is invalidated, and may not be used further.
+
+       @param          inFlags
+                                       Currently unused, reserved for future use.
+
+       @param          inErrorCode
+                                       Will be kDNSServiceErr_NoError on success, otherwise will indicate the failure that occurred (including 
+                                       name conflicts). Other parameters are undefined if errorCode is nonzero.
+
+       @param          inContext
+                                       The context pointer that was passed to the callout.
+*/
+
+ typedef void
+       ( CALLBACK_COMPAT *DNSServiceRegisterRecordReply )(
+               DNSServiceRef                   inRef,
+               DNSRecordRef                    inRecordRef,
+               DNSServiceFlags                 inFlags,
+               DNSServiceErrorType             inErrorCode,
+               void *                                  inContext );
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function  DNSServiceRegisterRecord
+       
+       @abstract       Register an individual resource record on a connected DNSServiceRef. 
+       
+       @param          inRef
+                                       A DNSServiceRef initialized by DNSServiceCreateConnection().
+
+       @param          inRecordRef
+                                       A pointer to an uninitialized DNSRecordRef. Upon succesfull completion of this call, this ref may be 
+                                       passed to DNSServiceUpdateRecord() or DNSServiceRemoveRecord(). (To deregister ALL records registered 
+                                       on a single connected DNSServiceRef and deallocate each of their corresponding DNSServiceRecordRefs, 
+                                       call DNSServiceRefDealloocate()).
+
+       @param          inFlags
+                                       Possible values are Shared/Unique (see flag type definitions for details).
+
+       @param          inInterfaceIndex
+                                       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.
+
+       @param          inFullName
+                                       The full domain name of the resource record.
+
+       @param          inRRType
+                                       The numerical type of the resource record (e.g. PTR, SRV, etc), as defined in nameser.h.
+
+       @param          inRRClass
+                                       The class of the resource record, as defined in nameser.h (usually 1 for the Internet class).
+
+       @param          inRDataSize
+                                       Length, in bytes, of the rdata.
+
+       @param          inRData
+                                       A pointer to the raw rdata, as it is to appear in the DNS record.
+
+       @param          inTTL
+                                       The time to live of the resource record, in seconds.
+
+       @param          inCallBack
+                                       The function to be called when a result is found, or if the call asynchronously fails (e.g. because 
+                                       of a name conflict).
+
+       @param          inContext
+                                       An application context pointer which is passed to the callback function (may be NULL).
+
+       @result         Returns kDNSServiceErr_NoError on success (any subsequent, asynchronous errors are delivered to the 
+                               callback), otherwise returns an error code indicating the error that occurred (the callback is never 
+                               invoked and the DNSRecordRef is not initialized).
+
+       @discussion
+       
+       Note that name conflicts occurring for records registered via this call must be handled by the client in the callback.
+*/
+
+DNSServiceErrorType
+       DNSServiceRegisterRecord(
+               DNSServiceRef                                   inRef,
+               DNSRecordRef *                                  inRecordRef,
+               DNSServiceFlags                                 inFlags,
+               uint32_t                                                inInterfaceIndex,
+               const char *                                    inFullName,     
+               uint16_t                                                inRRType,
+               uint16_t                                                inRRClass,
+               uint16_t                                                inRDataSize,
+               const void *                                    inRData,
+               uint32_t                                                inTTL,
+               DNSServiceRegisterRecordReply   inCallBack,
+               void *  inContext );
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @typedef   DNSServiceQueryRecordReply
+       
+       @abstract       Callback function for DNSServiceQueryRecord.
+       
+       @param          inRef
+                                       The DNSServiceRef initialized by DNSServiceQueryRecord().
+
+       @param          inFlags
+                                       Possible values are Finished/MoreComing and Add/Remove. The Remove flag is set for PTR records with 
+                                       a TTL of 0.
+
+       @param          inInterfaceIndex
+                                       The interface on which the query was resolved (the index for a given interface is determined via the 
+                                       if_nametoindex() family of calls).
+
+       @param          inErrorCode
+                                       Will be kDNSServiceErr_NoError on success, otherwise will indicate the failure that occurred. Other 
+                                       parameters are undefined if errorCode is nonzero.
+
+       @param          inFullName
+                                       The resource record's full domain name.
+
+       @param          inRRType
+                                       The resource record's type (e.g. PTR, SRV, etc) as defined in nameser.h.
+
+       @param          inRRClass
+                                       The class of the resource record, as defined in nameser.h (usually 1).
+
+       @param          inRDataSize
+                                       The length, in bytes, of the resource record rdata.
+
+       @param          inRData
+                                       The raw rdata of the resource record.
+
+       @param          inTTL
+                                       The resource record's time to live, in seconds.
+
+       @param          inContext
+                                       The context pointer that was passed to the callout.
+ */
+
+typedef void
+       ( CALLBACK_COMPAT *DNSServiceQueryRecordReply )(
+               DNSServiceRef                   inRef,
+               DNSServiceFlags                 inFlags,
+               uint32_t                                inInterfaceIndex,
+               DNSServiceErrorType             inErrorCode,
+               const char *                    inFullName,     
+               uint16_t                                inRRType,
+               uint16_t                                inRRClass,
+               uint16_t                                inRDataSize,
+               const void *                    inRData,
+               uint32_t                                inTTL,
+               void *                                  inContext );
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function  DNSServiceQueryRecord
+       
+       @abstract       Query for an arbitrary DNS record.
+
+       @param          outRef
+                                       A pointer to an uninitialized DNSServiceRef.
+
+       @param          inFlags
+                                       Currently unused, reserved for future use.
+
+       @param          inInterfaceIndex
+                                       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.
+
+       @param          inName
+                                       The full domain name of the resource record to be queried for.
+
+       @param          inRRType
+                                       The numerical type of the resource record to be queried for (e.g. PTR, SRV, etc) as defined in nameser.h.
+
+       @param          inRRClass
+                                       The class of the resource record, as defined in nameser.h (usually 1 for the Internet class).
+
+       @param          inCallBack
+                                       The function to be called when a result is found, or if the call asynchronously fails.
+
+       @param          inContext
+                                       An application context pointer which is passed to the callback function (may be NULL).
+
+       @result         Returns kDNSServiceErr_NoError on success (any subsequent, asynchronous errors are delivered to the 
+                               callback), otherwise returns an error code indicating the error that occurred (the callback is never 
+                               invoked and the DNSServiceRef is not initialized).
+
+       @discussion
+       
+       Note that name conflicts occurring for records registered via this call must be handled by the client in the callback.
+*/
+DNSServiceErrorType
+       DNSServiceQueryRecord(
+               DNSServiceRef *                         outRef,
+               DNSServiceFlags                         inFlags,
+               uint32_t                                        inInterfaceIndex,
+               const char *                            inName, 
+               uint16_t                                        inRRType,
+               uint16_t                                        inRRClass,
+               DNSServiceQueryRecordReply      inCallBack,
+               void *                                          inContext );    // may be NULL
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function  DNSServiceReconfirmRecord
+       
+       @abstract       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.
+
+       @param          inFlags
+                                       Currently unused, reserved for future use.
+
+       @param          inName
+                                       The resource record's full domain name.
+
+       @param          inRRType
+                                       The resource record's type (e.g. PTR, SRV, etc) as defined in nameser.h.
+
+       @param          inRRClass
+                                       The class of the resource record, as defined in nameser.h (usually 1).
+
+       @param          inRDataSize
+                                       The length, in bytes, of the resource record rdata.
+
+       @param          inRData
+                                       The raw rdata of the resource record.
+*/
+void
+       DNSServiceReconfirmRecord(
+               DNSServiceFlags inFlags,
+               uint32_t                inInterfaceIndex,
+               const char *    inName, 
+               uint16_t                inRRType,
+               uint16_t                inRRClass,
+               uint16_t                inRDataSize,
+               const void *    inRData );
+
+#if 0
+#pragma mark == TXT Record Building ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @typedef        TXTRecordRef
+
+       @abstract       Reference to a TXTRecord object representing a DNS-SD TXT record.
+       
+       @discussion
+       
+       Note: client is responsible for serializing access to these structures if they are shared between concurrent threads.
+*/
+
+typedef struct _TXTRecordRef_t *               TXTRecordRef;
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function  TXTRecordCreate
+       
+       @abstract       Creates an empty TXTRecordRef.
+       
+       @param          outRef
+                                       A pointer to an uninitialized TXTRecordRef. Filled in on success.
+       
+       @result         Returns kDNSServiceErr_NoError on success.
+                               Returns kDNSServiceErr_BadParam if the reference pointer is NULL.
+                               Returns kDNSServiceErr_NoMemory if there is not enough memory to create the TXTRecord.
+       
+       @discussion
+       
+       Once you've created a TXTRecordRef, you can pass it to TXTRecordSetValue and other functions to add "key=value" 
+       pairs to it. Finally, you can extract the raw bytes again to pass to DNSServiceRegister() or DNSServiceUpdateRecord().
+       
+       A typical calling sequence for TXT record construction is something like:
+       
+       TXTRecordCreate();
+       TXTRecordSetValue();
+       TXTRecordSetValue();
+       TXTRecordSetValue();
+       ...
+       DNSServiceRegister( ... TXTRecordGetLength(), TXTRecordGetBytesPtr() ... );
+       TXTRecordDeallocate();
+*/
+
+DNSServiceErrorType    TXTRecordCreate( TXTRecordRef *outRef );
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function  TXTRecordDeallocate
+       
+       @abstract       Releases the memory associated with a TXTRecordRef.
+       
+       @param          inRef
+                                       A TXTRecordRef initialized by calling TXTRecordCreate.
+*/
+
+void   TXTRecordDeallocate( TXTRecordRef inRef );
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function  TXTRecordSetValue
+       
+       @abstract       Adds a key (optionally with a value) to a TXTRecordRef.
+       
+       @param          inRef
+                                       A TXTRecordRef initialized by TXTRecordCreate.
+                                       
+       @param          inKey
+                                       Null-terminated key of the value to add. Must be at least 1 character and consist of only printable 
+                                       US-ASCII characters (0x20-0x7E), excluding '=' (0x3D). Should be 14 characters or less (not counting 
+                                       the terminating null). Keys are case insensitive (i.e. key "test" replaces key "TEST").
+                                       
+       @param          inValue
+                                       Pointer to value to add. For values that represent textual data, UTF-8 is STRONGLY recommended.
+                                       If NULL, then the key will be added with no value.
+                                       If non-NULL but valueSize is zero, then "key=" will be added with an empty value.
+       
+       @param          inValueSize
+                                       Number of bytes in the value. Must be 0 if inValue is NULL.
+       
+       @result         Returns kDNSServiceErr_NoError on success.
+                               Returns kDNSServiceErr_BadParam if the parameters are illegal or not supported.
+                               Returns kDNSServiceErr_Invalid if the key string contains illegal characters.
+                               Returns kDNSServiceErr_NoMemory if there is not enough memory to set the value.
+       
+       @discussion
+       
+       If the key is already present in the TXTRecordRef, then the current value will be replaced with the new value.
+       Keys may be 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 the TXT record).
+       - Present with non-empty value ("key=value" appears in the 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>
+*/
+
+DNSServiceErrorType
+       TXTRecordSetValue( 
+               TXTRecordRef    inRef, 
+               const char *    inKey, 
+               uint8_t                 inValueSize,    // may be zero
+               const void *    inValue );              // may be NULL
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function  TXTRecordRemoveValue
+
+       @abstract       Removes a key from a TXTRecordRef.
+       
+       @param          inRef
+                                       A TXTRecordRef initialized by TXTRecordCreate.
+                                       
+       @param          inKey
+                                       Null-terminated key to remove. Note: keys are case insensitive.
+
+       @result         Returns kDNSServiceErr_NoError on success.
+                               Returns kDNSServiceErr_NoSuchKey if the key is not present in the TXTRecordRef.
+                               Returns kDNSServiceErr_BadParam if the parameters are illegal or not supported.
+*/
+
+DNSServiceErrorType    TXTRecordRemoveValue( TXTRecordRef inRef, const char *inKey );
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function  TXTRecordGetLength
+       
+       @abstract       Returns the number of raw bytes inside a TXTRecordRef.
+       
+       @param          inRef
+                                       A TXTRecordRef initialized by TXTRecordCreate.
+       
+       @result         Returns the number of raw bytes inside a TXTRecordRef which you can pass directly to DNSServiceRegister()
+                               or to DNSServiceUpdateRecord(). Returns 0 if the TXTRecordRef is empty.
+
+       @discussion
+       
+       The length may become invalid if you subsequently make changes to the TXTRecordRef by calling TXTRecordSetValue() 
+       or TXTRecordRemoveValue().
+*/
+
+uint16_t       TXTRecordGetLength( TXTRecordRef inRef );
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function  TXTRecordGetBytesPtr
+       
+       @abstract       Returns a pointer to the raw bytes inside the TXTRecordRef.
+       
+       @param          inRef
+                                       A TXTRecordRef initialized by TXTRecordCreate.
+
+       @result         Returns a pointer to the raw bytes inside the TXTRecordRef which you can pass directly to 
+                               DNSServiceRegister() or to DNSServiceUpdateRecord(). Returns NULL if the TXTRecordRef is empty.
+
+       @discussion
+       
+       The pointer may become invalid if you subsequently make changes to the TXTRecordRef by calling TXTRecordSetValue() 
+       or TXTRecordRemoveValue().
+*/
+
+const void *   TXTRecordGetBytesPtr( TXTRecordRef inRef );
+
+#if 0
+#pragma mark == TXT Record Parsing ==
+#endif
+
+/*---------------------------------------------------------------------------------------------------------------------------
+       A typical calling sequence for TXT record parsing is something like:
+       Receive TXT record data in the DNSServiceResolve() callback then:
+       
+       cosnt void *    value1Ptr;
+       uint8_t                 value1Size;
+       
+       err = TXTRecordGetValuePtr( txtSize, txtRecord, "key1", &value1Ptr, &value1Size );
+       if( err == kDNSServiceErr_NoError )
+       {
+               // "key1" found. Do work with "value1Ptr" data if needed.
+       }
+       ...
+       return;
+       
+       If you wish to retain the values after returning from the DNSServiceResolve() callback, then you need to copy the data 
+       to your own storage using memcpy() or something similar so it does not go out of scope until you're done with it.
+
+       If for some reason you need to parse a TXT record you built yourself using the TXT record construction functions above, 
+       then you can do that using TXTRecordGetLength and TXTRecordGetBytesPtr functions:
+       
+       TXTRecordGetValue( TXTRecordGetLength( x ), TXTRecordGetBytesPtr( x ), "key1", &value1Ptr, &value1Size );
+
+       Most applications only fetch keys they know about from a TXT record and ignore the rest.
+       However, some debugging tools wish to fetch and display all keys. To do that, use the TXTRecordGetCount() and 
+       TXTRecordGetItemAtIndex() functions.
+*/
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function  TXTRecordGetValuePtr
+       
+       @abstract       Allows you to retrieve the value for a given key from a TXT Record.
+       
+       @param          inTXTSize
+                                       Number of bytes in the TXT record.
+       
+       @param          inTXTBytes
+                                       Pointer to the raw TXT record bytes.
+       
+       @param          inKey
+                                       A null-terminated key to search for. Note: keys are case insensitive.
+
+       @param          outValue
+                                       Pointer to be filled in with a pointer to the value within the TXT record bytes.
+                                       Resulting pointer will be NULL if the key is present, but has no value.
+                                       Resulting pointer will be non-NULL and size zero if the key is present, but has an empty value.
+                                       Resulting pointer will be non-NULL and size non-zero if key is present and has a non-empty value.
+                                       May be NULL if only interested in the value size or if the key is present.
+       
+       @param          outValueSize
+                                       Pointer to receive the size of the value.
+                                       Size will be 0 if there is no value or the value is empty.
+                                       May be NULL if not interested in getting the size.
+
+       @result         Returns kDNSServiceErr_NoError if a key with the specified name is found.
+                               Returns kDNSServiceErr_NoSuchKey if the key does not exist in the TXTRecordRef.
+                               Returns kDNSServiceErr_BadParam if the parameters are illegal or not supported.
+                               Returns kDNSServiceErr_Invalid if the TXT record is malformed.
+       
+       @discussion
+       
+       The pointer may become invalid if you subsequently make changes to the TXT record by calling TXTRecordSetValue() 
+       or TXTRecordRemoveValue().
+*/
+
+DNSServiceErrorType
+       TXTRecordGetValuePtr( 
+               uint16_t                inTXTSize, 
+               const void *    inTXTBytes, 
+               const char *    inKey, 
+               const void **   outValue,                       // may be NULL
+               uint8_t *               outValueSize );         // may be NULL
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function  TXTRecordGetCount
+       
+       @abstract       Returns the total number of keys in the TXT Record.
+       
+       @param          inTXTSize
+                                       Number of bytes in the TXT record.
+       
+       @param          inTXTBytes
+                                       Pointer to the raw TXT record bytes.
+
+       @result         Returns the total number of keys in the TXT Record.
+       
+       @discussion
+       
+       The count can be used with TXTRecordGetItemAtIndex() to iterate through the keys.
+       The count may become invalid if you subsequently make changes to the TXT record by calling TXTRecordSetValue() 
+       or TXTRecordRemoveValue().      
+*/
+
+uint16_t       TXTRecordGetCount( uint16_t inTXTSize, const void *inTXTBytes );
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function  TXTRecordGetItemAtIndex
+       
+       @abstract       Allows you to retrieve a key name, given an index into a TXT Record.
+       
+       @param          inTXTSize
+                                       Number of bytes in the TXT record.
+       
+       @param          inTXTBytes
+                                       Pointer to the raw TXT record bytes.
+                                       
+       @param          inIndex
+                                       Index of item to get. The index is 0-based (0 is the first item).
+                                       Legal index values range from 0 to TXTRecordGetCount() - 1.
+                                       
+       @param          inKeyBuffer
+                                       A string buffer used to store the null-terminated key name. The buffer must be at least 256 bytes
+                                       in order to hold the maximum possible key name.
+                                       May be NULL if not interested in the key name.
+
+       @param          outValue
+                                       Pointer to be filled in with a pointer to the value within the TXT record bytes.
+                                       Resulting pointer will be NULL if the key is present, but has no value.
+                                       Resulting pointer will be non-NULL and size zero if the key is present, but has an empty value.
+                                       Resulting pointer will be non-NULL and size non-zero if key is present and has a non-empty value.
+                                       May be NULL if only interested in the value size or if the key is present.
+       
+       @param          outValueSize
+                                       Pointer to receive the size of the value.
+                                       Size will be 0 if there is no value or the value is empty.
+                                       May be NULL if not interested in getting the size.
+
+       @result         Returns kDNSServiceErr_NoError if a key with the specified name is found.
+                               Returns kDNSServiceErr_Invalid if the index is greater than TXTRecordGetCount() - 1 or the TXT record is malformed.
+                               Returns kDNSServiceErr_BadParam if the parameters are illegal or not supported.
+       
+       @discussion
+       
+       It also possible to iterate through keys in a TXT record by simply calling TXTRecordGetItemAtIndex() repeatedly, 
+       beginning with index zero and increasing until TXTRecordGetItemAtIndex() returns an non-zero error code.
+       The pointer may become invalid if you subsequently make changes to the TXTRecordRef by calling TXTRecordSetValue() 
+       or TXTRecordRemoveValue().
+*/
+
+DNSServiceErrorType
+       TXTRecordGetItemAtIndex( 
+               uint16_t                inTXTSize, 
+               const void *    inTXTBytes, 
+               uint16_t                inIndex, 
+               char *                  inKeyBuffer,            // may be NULL
+               const void **   outValue,                       // may be NULL
+               uint8_t *               outValueSize );         // may be NULL
+
+#ifdef __cplusplus
+       }
+#endif
+
+#endif // _DNS_SD_H
diff --git a/mDNSWindows/DNSSDDirect.c b/mDNSWindows/DNSSDDirect.c
new file mode 100644 (file)
index 0000000..c20a97e
--- /dev/null
@@ -0,0 +1,1863 @@
+/*
+ * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+    
+$Log: DNSSDDirect.c,v $
+Revision 1.7  2004/06/05 00:04:27  cheshire
+<rdar://problem/3668639>: wide-area domains should be returned in reg. domain enumeration
+
+Revision 1.6  2004/05/08 12:25:50  bradley
+Changed to use symbolic enums to prevent some compilers from treating it as a sign conversion.
+
+Revision 1.5  2004/05/06 18:42:58  ksekar
+General dns_sd.h API cleanup, including the following radars:
+<rdar://problem/3592068>: Remove flags with zero value
+<rdar://problem/3479569>: Passing in NULL causes a crash.
+
+Revision 1.4  2004/04/15 06:55:50  bradley
+Changed resolving to manually query for SRV and TXT records instead of using mDNS_StartResolveService.
+This avoids extra A/AAAA record queries and allows local-only resolves to work with normal services.
+
+Revision 1.3  2004/04/15 01:00:05  bradley
+Removed support for automatically querying for A/AAAA records when resolving names. Platforms
+without .local name resolving support will need to manually query for A/AAAA records as needed.
+
+Revision 1.2  2004/04/09 21:03:14  bradley
+Changed port numbers to use network byte order for consistency with other platforms.
+
+Revision 1.1  2004/01/30 02:46:15  bradley
+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.
+
+*/
+
+#include       <stdlib.h>
+
+#include       "CommonServices.h"
+#include       "DebugServices.h"
+
+#include       "DNSSD.h"
+
+#if( DNS_SD_DIRECT_ENABLED )
+
+#include       "mDNSClientAPI.h"
+
+#include       "DNSSDDirect.h"
+
+#ifdef __cplusplus
+       extern "C" {
+#endif
+
+#if 0
+#pragma mark == Constants ==
+#endif
+
+//===========================================================================================================================
+//     Constants
+//===========================================================================================================================
+
+#define        DEBUG_NAME              "[DNS-SD Direct] "
+
+typedef uint32_t               DNSServiceRegisterFlags;
+
+#define        kDNSServiceRegisterFlagsAutoName                                ( 1 << 0 )
+#define        kDNSServiceRegisterFlagsAutoNameOnFree                  ( 1 << 1 )
+#define        kDNSServiceRegisterFlagsRenameOnConflict                ( 1 << 2 )
+
+#if 0
+#pragma mark == Structures ==
+#endif
+
+//===========================================================================================================================
+//     Structures
+//===========================================================================================================================
+
+typedef void ( *DNSServiceRefReleaseCallBack )( DNSServiceRef inRef );
+
+// DNSServiceRef
+
+typedef struct _DNSServiceRef_t        _DNSServiceRef_t;
+struct _DNSServiceRef_t
+{
+       DNSServiceRef                                                                   next;
+       DNSServiceRefReleaseCallBack                                    releaseCallBack;
+       void *                                                                                  context;
+       
+       union
+       {
+               struct  // EnumerateDomains
+               {
+                       DNSQuestion                                                             question;
+                       mDNSBool                                                                questionActive;
+                       DNSQuestion                                                             defaultQuestion;
+                       mDNSBool                                                                defaultQuestionActive;
+                       DNSServiceDomainEnumReply                               callback;
+               
+               }       domain;
+
+               struct  // Register
+               {
+                       ServiceRecordSet *                                              set;
+                       domainlabel                                                             name;
+                       DNSServiceRegisterFlags                                 flags;
+                       DNSServiceRegisterReply                                 callback;
+                       
+               }       reg;
+
+               struct  // Browse
+               {
+                       DNSQuestion                                                             question;
+                       mDNSBool                                                                questionActive;
+                       DNSServiceBrowseReply                                   callback;
+                       
+               }       browse;
+               
+               struct  // Resolve
+               {
+                       DNSServiceFlags                                                 flags;
+                       DNSQuestion                                                             srvQuestion;
+                       mDNSBool                                                                srvQuestionActive;
+                       const ResourceRecord *                                  srvAnswer;
+                       DNSQuestion                                                             txtQuestion;
+                       mDNSBool                                                                txtQuestionActive;
+                       const ResourceRecord *                                  txtAnswer;
+                       DNSServiceResolveReply                                  callback;
+                       
+               }       resolve;
+                               
+               struct  // CreateConnection
+               {
+                       DNSRecordRef                                                    records;
+                       
+               }       connection;
+               
+               struct  // Query
+               {
+                       DNSQuestion                                                             question;
+                       mDNSBool                                                                questionActive;
+                       DNSServiceQueryRecordReply                              callback;
+                       
+               }       query;
+               
+       }       u;
+};
+
+// DNSRecordRef
+
+typedef struct _DNSRecordRef_t _DNSRecordRef_t;
+struct _DNSRecordRef_t
+{
+       union
+       {
+               struct  // Service-based records (i.e. DNSServiceRegister-based DNSServiceRef's)
+               {
+                       ExtraResourceRecord                                     extra;
+                       
+               }       service;
+               
+               struct  // Connection-based records (i.e. DNSServiceCreateConnection-based DNSServiceRef's)
+               {
+                       DNSRecordRef                                            next;
+                       DNSServiceRef                                           owner;
+                       DNSServiceRegisterRecordReply           callback;
+                       void *                                                          context;
+                       AuthRecord                                                      rr;
+                       
+               }       connection;
+       
+       }       u;
+       
+       // WARNING: Do not add fields after the resource record. That is where oversized RData space is allocated.
+};
+
+#define        kDNSRecordServiceFixedSize                      sizeof_field( _DNSRecordRef_t, u.service )
+#define        kDNSRecordConnectionFixedSize           sizeof_field( _DNSRecordRef_t, u.connection )
+
+#if 0
+#pragma mark == Prototypes ==
+#endif
+
+//===========================================================================================================================
+//     Prototypes
+//===========================================================================================================================
+
+// General
+
+#define        DNSServiceLock()        mDNSPlatformLock( gMDNSPtr )
+#define        DNSServiceUnlock()      mDNSPlatformUnlock( gMDNSPtr )
+
+DEBUG_LOCAL void       DNSServiceMDNSCallBack( mDNS * const inMDNS, mStatus inStatus );
+
+// Domain Enumeration
+
+DEBUG_LOCAL void       DNSServiceEnumerateDomainsRelease_direct( DNSServiceRef inRef );
+DEBUG_LOCAL void
+       DNSServiceEnumerateDomainsCallBack_direct( 
+               mDNS * const                                    inMDNS, 
+               DNSQuestion *                                   inQuestion, 
+               const ResourceRecord * const    inAnswer, 
+               mDNSBool                                                inAddRecord );
+
+// Service Discovery
+
+DEBUG_LOCAL void       DNSServiceBrowseRelease_direct( DNSServiceRef inRef );
+DEBUG_LOCAL void
+       DNSServiceBrowseCallBack_direct( 
+               mDNS * const                                    inMDNS, 
+               DNSQuestion *                                   inQuestion, 
+               const ResourceRecord * const    inAnswer, 
+               mDNSBool                                                inAddRecord );
+
+DEBUG_LOCAL void       DNSServiceResolveRelease_direct( DNSServiceRef inRef );
+DEBUG_LOCAL void
+       DNSServiceResolveCallBack_direct(
+               mDNS * const                                    inMDNS, 
+               DNSQuestion *                                   inQuestion, 
+               const ResourceRecord * const    inAnswer, 
+               mDNSBool                                                inAddRecord );
+
+// Service Registration
+
+DEBUG_LOCAL void       DNSServiceRegisterRelease_direct( DNSServiceRef inRef );
+DEBUG_LOCAL void       DNSServiceRegisterCallBack_direct( mDNS * const inMDNS, ServiceRecordSet * const inSet, mStatus inResult );
+DEBUG_LOCAL void       DNSServiceRegisterFree_direct( DNSServiceRef inRef );
+
+DEBUG_LOCAL void       DNSServiceUpdateRecordCallBack_direct( mDNS * const inMDNS, AuthRecord * const inRR, RData *inOldRData );
+
+// Special Purpose
+
+DEBUG_LOCAL void                       DNSServiceCreateConnectionRelease_direct( DNSServiceRef inRef );
+DEBUG_LOCAL DNSRecordRef       DNSServiceConnectionRecordRemove_direct( DNSServiceRef inRef, DNSRecordRef inRecordRef );
+
+DEBUG_LOCAL void                       DNSServiceRegisterRecordCallBack_direct( mDNS *const inMDNS, AuthRecord *const inRR, mStatus inResult );
+
+DEBUG_LOCAL void                       DNSServiceQueryRecordRelease_direct( DNSServiceRef inRef );
+DEBUG_STATIC void
+       DNSServiceQueryRecordCallBack_direct(
+               mDNS * const                                    inMDNS, 
+               DNSQuestion *                                   inQuestion, 
+               const ResourceRecord * const    inAnswer, 
+               mDNSBool                                                inAddRecord );
+
+#if 0
+#pragma mark == Globals ==
+#endif
+
+//===========================================================================================================================
+//     Globals
+//===========================================================================================================================
+
+mDNS                                                   gMDNS;
+DEBUG_LOCAL mDNS *                             gMDNSPtr                                = NULL;
+DEBUG_LOCAL CacheRecord *              gMDNSCache                              = NULL;
+DEBUG_LOCAL DNSServiceRef              gDNSServiceRefList              = NULL;
+DEBUG_LOCAL DNSServiceRef              gDNSCurrentServiceRef   = NULL;
+DEBUG_LOCAL DNSRecordRef               gDNSCurrentRecord               = NULL;
+
+#if 0
+#pragma mark -
+#pragma mark == General ==
+#endif
+
+//===========================================================================================================================
+//     DNSServiceInitialize_direct
+//===========================================================================================================================
+
+DNSServiceErrorType    DNSServiceInitialize_direct( DNSServiceInitializeFlags inFlags, int inCacheEntryCount )
+{
+       DNSServiceErrorType             err;
+       mDNSBool                                advertise;
+       
+       dlog( kDebugLevelTrace, DEBUG_NAME "initializing (flags=0x%08X, cache=%d/%d)\n", (int) inFlags, 
+               inCacheEntryCount, ( inCacheEntryCount == 0 ) ? kDNSServiceCacheEntryCountDefault : inCacheEntryCount );
+       
+       // Allocate the record cache.
+       
+       if( inCacheEntryCount == 0 )
+       {
+               inCacheEntryCount = kDNSServiceCacheEntryCountDefault;
+       }
+       gMDNSCache = (CacheRecord *) malloc( inCacheEntryCount * sizeof( *gMDNSCache ) );
+       require_action( gMDNSCache, exit, err = kDNSServiceErr_NoMemory );
+       
+       // Initialize mDNS.
+       
+       if( inFlags & kDNSServiceInitializeFlagsAdvertise )
+       {
+               advertise = mDNS_Init_AdvertiseLocalAddresses;
+       }
+       else
+       {
+               advertise = mDNS_Init_DontAdvertiseLocalAddresses;
+       }
+       err = mDNS_Init( &gMDNS, NULL, gMDNSCache, (mDNSu32) inCacheEntryCount, advertise, DNSServiceMDNSCallBack, NULL );
+       require_noerr( err, exit );
+       err = gMDNS.mDNSPlatformStatus;
+       require_noerr( err, exit );
+       
+       gMDNSPtr = &gMDNS;
+       
+exit:
+       dlog( kDebugLevelTrace, DEBUG_NAME "initializing done (err=%d %m)\n", err, err );
+       if( err )
+       {
+               DNSServiceFinalize_direct();
+       }
+       return( err );
+}
+
+//===========================================================================================================================
+//     DNSServiceFinalize_direct
+//===========================================================================================================================
+
+void   DNSServiceFinalize_direct( void )
+{
+       dlog( kDebugLevelTrace, DEBUG_NAME "finalizing\n" );
+       
+       if( gMDNSPtr )
+       {
+               mDNS_Close( &gMDNS );
+               gMDNSPtr = NULL;
+       }
+       if( gMDNSCache )
+       {
+               free( gMDNSCache );
+               gMDNSCache = mDNSNULL;
+       }
+       
+       dlog( kDebugLevelTrace, DEBUG_NAME "finalizing done\n" );
+}
+
+//===========================================================================================================================
+//     DNSServiceMDNSCallBack
+//===========================================================================================================================
+
+DEBUG_LOCAL void       DNSServiceMDNSCallBack( mDNS * const inMDNS, mStatus inStatus )
+{
+       DEBUG_USE_ONLY( inMDNS );
+       check( inMDNS );
+       
+       dlog( kDebugLevelTrace, DEBUG_NAME "MDNS callback (status=%d)\n", inStatus );
+       
+       if( inStatus == mStatus_ConfigChanged )
+       {
+               // Notify all callbacks that the configuration has changed so they can do any additional processing.
+               //
+               // Warning: This is likely to call a user callback, which may change the object lists. Any code walking 
+               // Warning: or changing these lists must use the "current" ptr mechanism to protect against this.
+               
+               DNSServiceLock();
+               dlog( kDebugLevelTrace, DEBUG_NAME "handling ConfigChanged\n" );
+               
+               check_string( !gDNSCurrentServiceRef, "somebody is already using gDNSCurrentServiceRef!" );
+               gDNSCurrentServiceRef = gDNSServiceRefList;
+               while( gDNSCurrentServiceRef )
+               {
+                       DNSServiceRef           obj;
+                       
+                       obj = gDNSCurrentServiceRef;
+                       gDNSCurrentServiceRef = obj->next;
+                       
+                       // Call the callback with the ConfigChanged error code. Use the releaseCallBack to determine the type.
+                       
+                       if( obj->releaseCallBack == DNSServiceEnumerateDomainsRelease_direct )
+                       {
+                               obj->u.domain.callback( obj, 0, 0, kDNSServiceErr_ConfigChanged, "", obj->context );
+                       }
+                       else if( obj->releaseCallBack == DNSServiceRegisterRelease_direct )
+                       {
+                               // If auto-renaming and the system name has changed then trigger a re-register with the new name.
+                               
+                               if( obj->u.reg.flags & kDNSServiceRegisterFlagsAutoName )
+                               {
+                                       if( !SameDomainLabel( obj->u.reg.name.c, gMDNSPtr->nicelabel.c ) )
+                                       {
+                                               mStatus         err;
+                                       
+                                               obj->u.reg.flags |= kDNSServiceRegisterFlagsAutoNameOnFree;
+                                               err = mDNS_DeregisterService( gMDNSPtr, obj->u.reg.set );
+                                               check_noerr( err );
+                                       }
+                               }
+                               else
+                               {
+                                       check_string( obj->u.reg.callback, "not auto-naming, but no callback?" );
+                                       
+                                       obj->u.reg.callback( obj, 0, kDNSServiceErr_ConfigChanged, "", "", "", obj->context );
+                               }
+                       }
+                       else if( obj->releaseCallBack == DNSServiceBrowseRelease_direct )
+                       {
+                               obj->u.browse.callback( obj, 0, 0, kDNSServiceErr_ConfigChanged, "", "", "", obj->context );
+                       }
+                       else if( obj->releaseCallBack == DNSServiceResolveRelease_direct )
+                       {
+                               obj->u.resolve.callback( obj, 0, 0, kDNSServiceErr_ConfigChanged, "", "", 0, 0, NULL, obj->context );
+                       }
+                       else if( obj->releaseCallBack == DNSServiceCreateConnectionRelease_direct )
+                       {
+                               check_string( !gDNSCurrentRecord, "somebody is already using gDNSCurrentRecord!" );
+                               gDNSCurrentRecord = obj->u.connection.records;
+                               while( gDNSCurrentRecord )
+                               {
+                                       DNSRecordRef            record;
+                                       
+                                       record = gDNSCurrentRecord;
+                                       gDNSCurrentRecord = record->u.connection.next;
+                                       
+                                       record->u.connection.callback( record->u.connection.owner, record, 0, kDNSServiceErr_ConfigChanged, 
+                                               record->u.connection.context );
+                               }
+                       }
+                       else if( obj->releaseCallBack == DNSServiceQueryRecordRelease_direct )
+                       {
+                               obj->u.query.callback( obj, 0, 0, kDNSServiceErr_ConfigChanged, "", 0, 0, 0,NULL, 0, obj->context );
+                       }
+               }
+               DNSServiceUnlock();
+       }
+}
+
+#if 0
+#pragma mark -
+#endif
+
+//===========================================================================================================================
+//     DNSServiceRefDeallocate_direct
+//===========================================================================================================================
+
+void   DNSServiceRefDeallocate_direct( DNSServiceRef inRef )
+{
+       check( inRef );
+       
+       dlog( kDebugLevelNotice, DEBUG_NAME "%s: %#p\n", __ROUTINE__, inRef );
+       
+       DNSServiceLock();
+       if( inRef )
+       {
+               DNSServiceRef *         p;
+               
+               // Remove the object from the list.
+               
+               for( p = &gDNSServiceRefList; *p; p = &( *p )->next )
+               {
+                       if( *p == inRef )
+                       {
+                               break;
+                       }
+               }
+               check( *p );
+               
+               // Release the object if it was found.
+               
+               if( *p )
+               {
+                       *p = inRef->next;
+                       
+                       // If somebody will be looking at this object next, move the current ptr to the next object.
+                       
+                       if( inRef == gDNSCurrentServiceRef )
+                       {
+                               dlog( kDebugLevelInfo, DEBUG_NAME "deleting gDNSCurrentServiceRef (%#p)\n", inRef );
+                               gDNSCurrentServiceRef = inRef->next;
+                       }
+                       
+                       check( inRef->releaseCallBack );
+                       if( inRef->releaseCallBack )
+                       {
+                               inRef->releaseCallBack( inRef );
+                       }
+               }
+       }
+       DNSServiceUnlock();
+}
+
+#if 0
+#pragma mark -
+#pragma mark == Domain Enumeration ==
+#endif
+
+//===========================================================================================================================
+//     DNSServiceEnumerateDomains_direct
+//===========================================================================================================================
+
+DNSServiceErrorType
+       DNSServiceEnumerateDomains_direct(
+               DNSServiceRef *                                 outRef,
+               const DNSServiceFlags                   inFlags,
+               const uint32_t                                  inInterfaceIndex,
+               const DNSServiceDomainEnumReply inCallBack,
+               void *                                                  inContext )
+{
+       DNSServiceErrorType             err;
+       DNSServiceRef                   obj;
+       mDNS_DomainType                 type;
+       mDNS_DomainType                 defaultType;
+       DNSServiceFlags                 flags;
+       mDNSInterfaceID                 interfaceID;
+       
+       obj = NULL;
+       DNSServiceLock();
+       require_action( outRef, exit, err = kDNSServiceErr_BadParam );
+       require_action( ( inFlags == kDNSServiceFlagsBrowseDomains ) || 
+                                       ( inFlags == kDNSServiceFlagsRegistrationDomains ), 
+                                       exit, err = kDNSServiceErr_BadFlags );
+       require_action( inCallBack, exit, err = kDNSServiceErr_BadParam );
+       
+       // Allocate and initialize the object.
+       
+       obj = (DNSServiceRef) calloc( 1, sizeof( *obj ) );
+       require_action( obj, exit, err = kDNSServiceErr_NoMemory );
+       
+       obj->releaseCallBack    = DNSServiceEnumerateDomainsRelease_direct;
+       obj->context                    = inContext;
+       obj->u.domain.callback  = inCallBack;
+       
+       obj->next                               = gDNSServiceRefList;
+       gDNSServiceRefList              = obj;
+                               
+       // Start the browse operations.
+
+       if( inFlags & kDNSServiceFlagsRegistrationDomains )
+       {
+               type            = mDNS_DomainTypeRegistration;
+               defaultType     = mDNS_DomainTypeRegistrationDefault;
+       }
+       else
+       {
+               type            = mDNS_DomainTypeBrowse;
+               defaultType     = mDNS_DomainTypeBrowseDefault;
+       }
+       interfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex( gMDNSPtr, inInterfaceIndex );
+       
+       err = mDNS_GetDomains( gMDNSPtr, &obj->u.domain.question, type, NULL, interfaceID, 
+               DNSServiceEnumerateDomainsCallBack_direct, obj );
+       require_noerr( err, exit );
+       obj->u.domain.questionActive = mDNStrue;
+       
+       err = mDNS_GetDomains( gMDNSPtr, &obj->u.domain.defaultQuestion, defaultType, NULL, interfaceID, 
+               DNSServiceEnumerateDomainsCallBack_direct, obj );
+       require_noerr( err, exit );
+       obj->u.domain.defaultQuestionActive = mDNStrue;
+       
+       // Call back immediately with "local." since that is always available for all types of browsing.
+       
+       flags = kDNSServiceFlagsDefault | kDNSServiceFlagsAdd;
+       inCallBack( obj, flags, inInterfaceIndex, kDNSServiceErr_NoError, "local.", inContext );
+       
+       // Success!
+       
+       *outRef = obj;
+       obj     = NULL;
+       
+exit:
+       if( obj )
+       {       
+               DNSServiceRefDeallocate_direct( obj );
+       }
+       DNSServiceUnlock();
+       return( err );
+}
+
+//===========================================================================================================================
+//     DNSServiceEnumerateDomainsRelease_direct
+//
+//     Warning: Assumes the mDNS platform lock is held.
+//===========================================================================================================================
+
+DEBUG_LOCAL void       DNSServiceEnumerateDomainsRelease_direct( DNSServiceRef inRef )
+{
+       OSStatus                err;
+       
+       check( inRef );
+       
+       if( inRef->u.domain.questionActive )
+       {
+               err = mDNS_StopGetDomains( gMDNSPtr, &inRef->u.domain.question );
+               check_noerr( err );
+       }
+       if( inRef->u.domain.defaultQuestionActive )
+       {
+               err = mDNS_StopGetDomains( gMDNSPtr, &inRef->u.domain.defaultQuestion );
+               check_noerr( err );
+       }
+       free( inRef );
+}
+
+//===========================================================================================================================
+//     DNSServiceEnumerateDomainsCallBack_direct
+//
+//     Warning: Assumes the mDNS platform lock is held (held by mDNS before invoking this callback).
+//===========================================================================================================================
+
+DEBUG_LOCAL void
+       DNSServiceEnumerateDomainsCallBack_direct( 
+               mDNS * const                                    inMDNS, 
+               DNSQuestion *                                   inQuestion, 
+               const ResourceRecord * const    inAnswer, 
+               mDNSBool                                                inAddRecord )
+{
+       DNSServiceRef           obj;
+       DNSServiceFlags         flags;
+       uint32_t                        interfaceIndex;
+       char                            domain[ MAX_ESCAPED_DOMAIN_NAME ];
+       
+       DEBUG_UNUSED( inMDNS );
+       
+       check( inQuestion );
+       obj = (DNSServiceRef) inQuestion->QuestionContext;
+       check( obj );
+       
+       flags = inAddRecord ? kDNSServiceFlagsAdd : kDNSServiceFlagsNone;
+       if( inAddRecord )
+       {
+               if( inQuestion == &obj->u.domain.defaultQuestion )
+               {
+                       flags |= kDNSServiceFlagsDefault;
+               }
+       }
+       interfaceIndex = mDNSPlatformInterfaceIndexfromInterfaceID( &gMDNS, inAnswer->InterfaceID );
+       ConvertDomainNameToCString( &inAnswer->rdata->u.name, domain );
+       
+       obj->u.domain.callback( obj, flags, interfaceIndex, kDNSServiceErr_NoError, domain, obj->context );
+}
+
+#if 0
+#pragma mark -
+#pragma mark == Service Registration ==
+#endif
+
+//===========================================================================================================================
+//     DNSServiceRegister_direct
+//===========================================================================================================================
+
+DNSServiceErrorType
+       DNSServiceRegister_direct(
+               DNSServiceRef *                 outRef,
+               DNSServiceFlags                 inFlags,
+               uint32_t                                inInterfaceIndex,
+               const char *                    inName,
+               const char *                    inType,
+               const char *                    inDomain,
+               const char *                    inHost,
+               uint16_t                                inPort,
+               uint16_t                                inTXTSize,
+               const void *                    inTXT,
+               DNSServiceRegisterReply inCallBack,
+               void *                                  inContext )
+{
+       DNSServiceErrorType             err;
+       DNSServiceRef                   obj;
+       mDNSBool                                autoName;
+       domainname *                    host;
+       domainname                              tempHost;
+       mDNSBool                                ok;
+       size_t                                  size;
+       domainlabel                             name;
+       domainname                              type;
+       domainname                              domain;
+       mDNSIPPort                              port;
+       mDNSInterfaceID                 interfaceID;
+       
+       obj = NULL;
+       DNSServiceLock();
+       require_action( outRef, exit, err = kDNSServiceErr_BadReference );
+       require_action( ( inFlags == 0 ) || ( inFlags == kDNSServiceFlagsNoAutoRename ), exit, err = kDNSServiceErr_BadFlags );
+       autoName = !inName || ( *inName == '\0' );
+       require_action( !autoName || !( inFlags & kDNSServiceFlagsNoAutoRename ), exit, err = kDNSServiceErr_BadParam );
+       require_action( inType, exit, err = kDNSServiceErr_BadParam );
+       require_action( inTXT || ( inTXTSize == 0 ), exit, err = kDNSServiceErr_BadParam );
+       require_action( inCallBack || autoName, exit, err = kDNSServiceErr_BadParam );
+       
+       // Convert all the input strings and make sure they are valid. Use the system name if auto-naming.
+       
+       if( autoName )
+       {
+               name = gMDNSPtr->nicelabel;
+       }
+       else
+       {
+               ok = MakeDomainLabelFromLiteralString( &name, inName );
+               require_action( ok, exit, err = kDNSServiceErr_BadParam );
+       }
+       
+       ok = MakeDomainNameFromDNSNameString( &type, inType ) != NULL;
+       require_action( ok, exit, err = kDNSServiceErr_BadParam );
+       
+       if( !inDomain || ( *inDomain == '\0' ) )
+       {
+               inDomain = "local.";
+       }
+       ok = MakeDomainNameFromDNSNameString( &domain, inDomain ) != NULL;
+       require_action( ok, exit, err = kDNSServiceErr_BadParam );
+       
+       // Set up the host name (if not using the default).
+       
+       host = NULL;
+       if( inHost && ( *inHost != '\0' ) )
+       {
+               host = &tempHost;
+               ok = MakeDomainNameFromDNSNameString( host, inHost ) != NULL;
+               require_action( ok, exit, err = kDNSServiceErr_BadParam );
+               
+               AppendDomainName( host, &domain );
+       }
+       
+       // Allocate and initialize the object.
+       
+       obj = (DNSServiceRef) calloc( 1, sizeof( *obj ) );
+       require_action( obj, exit, err = kDNSServiceErr_NoMemory );
+
+       obj->releaseCallBack    = DNSServiceRegisterRelease_direct;
+       obj->context                    = inContext;
+       obj->u.reg.flags                = 0;
+       if( autoName )
+       {
+               obj->u.reg.flags |= kDNSServiceRegisterFlagsAutoName;
+       }
+       if( !( inFlags & kDNSServiceFlagsNoAutoRename ) )
+       {
+               obj->u.reg.flags |= kDNSServiceRegisterFlagsRenameOnConflict;
+       }
+       obj->u.reg.callback     = inCallBack;
+       
+       // Allocate space for the records, including any extra space to handle an oversized TXT record.
+       
+       size = sizeof( ServiceRecordSet );
+       if( inTXTSize > sizeof( RDataBody ) )
+       {
+               size += ( inTXTSize - sizeof( RDataBody ) );
+       }
+       obj->u.reg.set = (ServiceRecordSet *) calloc( 1, size );
+       require_action( obj->u.reg.set, exit, err = kDNSServiceErr_NoMemory );
+
+       obj->next                               = gDNSServiceRefList;
+       gDNSServiceRefList              = obj;
+       
+       // Register the service with mDNS.
+       
+       port.NotAnInteger = inPort;
+       interfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex( gMDNSPtr, inInterfaceIndex );
+       
+       err = mDNS_RegisterService( gMDNSPtr, obj->u.reg.set, &name, &type, &domain, host, port, 
+               (const mDNSu8 *) inTXT, inTXTSize, NULL, 0, interfaceID, DNSServiceRegisterCallBack_direct, obj );
+       require_noerr( err, exit );
+       
+       // Success!
+       
+       *outRef = obj;
+       obj     = NULL;
+       
+exit:
+       if( obj )
+       {
+               DNSServiceRegisterFree_direct( obj );
+       }
+       DNSServiceUnlock();
+       return( err );
+}
+
+//===========================================================================================================================
+//     DNSServiceRegisterRelease_direct
+//
+//     Warning: Assumes the mDNS platform lock is held.
+//===========================================================================================================================
+
+DEBUG_LOCAL void       DNSServiceRegisterRelease_direct( DNSServiceRef inRef )
+{
+       mStatus         err;
+       
+       check( inRef );
+       
+       // Deregister the service. If an error occurs (which should never happen), we have to assume that mDNS does not
+       // know about the registration and will not call us back with mStatus_MemFree so we free the memory here.
+       // Otherwise, mDNS will call us back with a mStatus_MemFree error code when it is safe for us to free the memory.
+       
+       err = mDNS_DeregisterService( gMDNSPtr, inRef->u.reg.set );
+       check_noerr( err );
+       if( err != mStatus_NoError )
+       {
+               DNSServiceRegisterFree_direct( inRef );
+       }
+}
+
+//===========================================================================================================================
+//     DNSServiceRegisterCallBack_direct
+//
+//     Warning: Assumes the mDNS platform lock is held (held by mDNS before invoking this callback).
+//===========================================================================================================================
+
+DEBUG_LOCAL void       DNSServiceRegisterCallBack_direct( mDNS * const inMDNS, ServiceRecordSet * const inSet, mStatus inResult )
+{
+       DNSServiceRef           obj;
+       mDNSBool                        ok;
+       domainlabel                     name;
+       domainname                      type;
+       domainname                      domain;
+       char                            nameString[ MAX_DOMAIN_LABEL + 1 ];
+       char                            typeString[ MAX_ESCAPED_DOMAIN_NAME ];
+       char                            domainString[ MAX_ESCAPED_DOMAIN_NAME ];
+       
+       DEBUG_UNUSED( inMDNS );
+       DEBUG_UNUSED( inSet );
+       
+       obj = (DNSServiceRef) inSet->ServiceContext;
+       check( obj );
+       
+       if( inResult == mStatus_NoError )
+       {
+               // Successful Registration.
+               
+               if( obj->u.reg.callback )
+               {
+                       ok = DeconstructServiceName( &inSet->RR_SRV.resrec.name, &name, &type, &domain );
+                       check( ok );
+                       
+               ConvertDomainLabelToCString_unescaped( &name, nameString );
+                   ConvertDomainNameToCString( &type, typeString );
+                   ConvertDomainNameToCString( &domain, domainString );
+                       
+                       obj->u.reg.callback( obj, 0, kDNSServiceErr_NoError, nameString, typeString, domainString, obj->context );
+               }
+       }
+       else if( inResult == mStatus_MemFree )
+       {
+               // If the AutoNameOnFree flag is set, it means we should re-register with the system name instead of freeing.
+               // Otherwise, mDNS is done with the memory so we can safely free it.
+               
+               if( obj->u.reg.flags & kDNSServiceRegisterFlagsAutoNameOnFree )
+               {
+                       obj->u.reg.flags &= ~kDNSServiceRegisterFlagsAutoNameOnFree;
+                       obj->u.reg.name = gMDNSPtr->nicelabel;
+                       inResult = mDNS_RenameAndReregisterService( gMDNSPtr, obj->u.reg.set, &obj->u.reg.name );
+                       check_noerr( inResult );
+               }
+               if( inResult != mStatus_NoError )
+               {
+                       DNSServiceRegisterFree_direct( obj );
+               }
+       }
+       else if( inResult == mStatus_NameConflict )
+       {
+               // Name conflict. If the auto renaming flags are enabled silently rename and re-register.
+               // Otherwise, mDNS will not send call us again with mStatus_MemFree so free the memory here.
+               
+               if( obj->u.reg.flags & ( kDNSServiceRegisterFlagsAutoName | kDNSServiceRegisterFlagsRenameOnConflict ) )
+               {
+                       inResult = mDNS_RenameAndReregisterService( gMDNSPtr, obj->u.reg.set, mDNSNULL );
+               }
+               if( inResult != mStatus_NoError )
+               {
+                       if( obj->u.reg.callback )
+                       {
+                               obj->u.reg.callback( obj, 0, kDNSServiceErr_NameConflict, "", "", "", obj->context );
+                       }
+                       DNSServiceRegisterFree_direct( obj );
+               }
+       }
+       else
+       {
+               dlog( kDebugLevelNotice, "unknown register result (%d)\n", inResult );
+               if( obj->u.reg.callback )
+               {
+                       obj->u.reg.callback( obj, 0, inResult, "", "", "", obj->context );
+               }
+       }
+}
+
+//===========================================================================================================================
+//     DNSServiceRegisterFree_direct
+//===========================================================================================================================
+
+DEBUG_LOCAL void       DNSServiceRegisterFree_direct( DNSServiceRef inRef )
+{
+       check( inRef );
+       
+       if( inRef->u.reg.set )
+       {
+               // Note: Each "Extras" record is a "DNSServiceRef", which is just a syntactic wrapper for ExtraResourceRecord.
+               // This avoids the need for casting and simplifies access, but still allows the following loop to work correctly.
+               
+               while( inRef->u.reg.set->Extras )
+               {
+                       ExtraResourceRecord *           extra;
+                       
+                       extra = inRef->u.reg.set->Extras;
+                       inRef->u.reg.set->Extras = extra->next;
+                       
+                       free( extra );
+               }    
+               free( inRef->u.reg.set );
+       }
+       free( inRef );
+}
+
+//===========================================================================================================================
+//     DNSServiceAddRecord_direct
+//===========================================================================================================================
+
+DNSServiceErrorType
+       DNSServiceAddRecord_direct(
+               DNSServiceRef   inRef,
+               DNSRecordRef *  outRecordRef,
+               DNSServiceFlags inFlags,
+               uint16_t                inRRType,
+               uint16_t                inRDataSize,
+               const void *    inRData,
+               uint32_t                inTTL )
+{
+       DNSServiceErrorType                     err;
+       size_t                                          size;
+       DNSRecordRef                            obj;
+       ExtraResourceRecord *           extra;
+       
+       obj = NULL;
+       DNSServiceLock();
+       require_action( inRef, exit, err = kDNSServiceErr_BadReference );
+       require_action( inRef->releaseCallBack == DNSServiceRegisterRelease_direct, exit, err = kDNSServiceErr_BadParam );
+       require_action( inRef->u.reg.set, exit, err = kDNSServiceErr_NotInitialized );
+       require_action( outRecordRef, exit, err = kDNSServiceErr_BadParam );
+       require_action( inFlags == 0, exit, err = kDNSServiceErr_BadFlags );
+       require_action( inRData && ( inRDataSize > 0 ), exit, err = kDNSServiceErr_BadParam );
+       
+       // Allocate and initialize the record. Allocate oversized record space at the end of the record.
+       
+       size = ( inRDataSize > sizeof( RDataBody ) ) ? inRDataSize : sizeof( RDataBody );
+       obj = (DNSRecordRef) calloc( 1, ( kDNSRecordServiceFixedSize - sizeof( RDataBody ) ) + size );
+       require_action( obj, exit, err = kDNSServiceErr_NoMemory );
+       
+       extra                                                           = &obj->u.service.extra;
+       extra->r.resrec.rrtype                          = inRRType;
+       extra->r.resrec.rdlength                        = inRDataSize;
+       extra->r.rdatastorage.MaxRDLength       = (mDNSu16) size;
+       memcpy( extra->r.rdatastorage.u.data, inRData, inRDataSize );
+       
+       // Register the record with mDNS.
+       
+       err = mDNS_AddRecordToService( gMDNSPtr, inRef->u.reg.set, extra, &extra->r.rdatastorage, inTTL );
+       require_noerr( err, exit );
+       
+       // Success!
+       
+       *outRecordRef   = (DNSRecordRef) obj;
+       obj                     = NULL;
+       
+exit:
+       if( obj )
+       {
+               free( obj );
+       }
+       DNSServiceUnlock();
+       return( err );
+}
+
+//===========================================================================================================================
+//     DNSServiceUpdateRecord_direct
+//===========================================================================================================================
+
+DNSServiceErrorType
+       DNSServiceUpdateRecord_direct(
+           DNSServiceRef       inRef,
+           DNSRecordRef        inRecordRef,
+           DNSServiceFlags     inFlags,
+           uint16_t            inRDataSize,
+           const void *        inRData,
+           uint32_t            inTTL )
+{
+       DNSServiceErrorType             err;
+       AuthRecord *                    rr;
+       size_t                                  size;
+       RData *                                 rd;     
+       
+       rd = NULL;
+       DNSServiceLock();
+       require_action( inRef, exit, err = kDNSServiceErr_BadReference );
+       require_action( ( inRef->releaseCallBack == DNSServiceRegisterRelease_direct ) || 
+                                       ( inRef->releaseCallBack == DNSServiceCreateConnectionRelease_direct ), 
+                                       exit, err = kDNSServiceErr_BadParam );
+       require_action( inRef->u.reg.set, exit, err = kDNSServiceErr_NotInitialized );
+       require_action( inFlags == 0, exit, err = kDNSServiceErr_BadFlags );
+       require_action( inRData, exit, err = kDNSServiceErr_BadParam );
+       
+       // Get the embedded AuthRecord from the DNSRecordRef. Determine the type of DNSServiceRef from the releaseCallBack.
+       
+       if( inRef->releaseCallBack == DNSServiceRegisterRelease_direct )
+       {
+               rr = inRecordRef ? &inRecordRef->u.service.extra.r : &inRef->u.reg.set->RR_TXT;
+       }
+       else if( inRef->releaseCallBack == DNSServiceCreateConnectionRelease_direct )
+       {
+               require_action( inRecordRef, exit, err = kDNSServiceErr_BadReference );
+               rr = &inRecordRef->u.connection.rr;
+       }
+       else
+       {
+               dlog( kDebugLevelError, DEBUG_NAME "trying to remove a DNSRecordRef with an unsupported DNSServiceRef\n" );
+               err = kDNSServiceErr_Unsupported;
+               goto exit;
+       }
+       
+       // Allocate and initialize the data. Allocate oversized data at the end of the record.
+       
+       size = ( inRDataSize > sizeof( RDataBody ) ) ? inRDataSize : sizeof( RDataBody );
+       rd = (RData *) calloc( 1, ( sizeof( *rd ) - sizeof( RDataBody ) ) + size );
+       require_action( rd, exit, err = kDNSServiceErr_NoMemory );
+       
+       rd->MaxRDLength = (mDNSu16) size;
+       memcpy( rd->u.data, inRData, inRDataSize );
+       
+       // Update the record. A NULL record means to update the primary TXT record.
+       
+       err = mDNS_Update( gMDNSPtr, rr, inTTL, inRDataSize, rd, DNSServiceUpdateRecordCallBack_direct );
+       require_noerr( err, exit );
+       
+       // Success!
+       
+       rd = NULL;
+       
+exit:
+       if( rd )
+       {
+               free( rd );
+       }
+       DNSServiceUnlock();
+       return( err );
+}
+
+//===========================================================================================================================
+//     DNSServiceUpdateRecord_direct
+//
+//     Warning: It is not safe to make any mDNS calls here.
+//===========================================================================================================================
+
+DEBUG_LOCAL void       DNSServiceUpdateRecordCallBack_direct( mDNS * const inMDNS, AuthRecord * const inRR, RData *inOldRData )
+{
+       DEBUG_UNUSED( inMDNS );
+       
+       check( inOldRData );
+       
+       if( inOldRData != &inRR->rdatastorage )
+       {
+               free( inOldRData );
+       }
+}
+
+//===========================================================================================================================
+//     DNSServiceRemoveRecord_direct
+//===========================================================================================================================
+
+DNSServiceErrorType DNSServiceRemoveRecord_direct( DNSServiceRef inRef, DNSRecordRef inRecordRef, DNSServiceFlags inFlags )
+{
+       DNSServiceErrorType             err;
+       
+       DNSServiceLock();
+       require_action( inRef, exit, err = kDNSServiceErr_BadReference );
+       require_action( ( inRef->releaseCallBack == DNSServiceRegisterRelease_direct ) || 
+                                       ( inRef->releaseCallBack == DNSServiceCreateConnectionRelease_direct ), 
+                                       exit, err = kDNSServiceErr_BadParam );
+       require_action( inRef->u.reg.set, exit, err = kDNSServiceErr_NotInitialized );
+       require_action( inRecordRef, exit, err = kDNSServiceErr_BadParam );
+       require_action( inFlags == 0, exit, err = kDNSServiceErr_BadFlags );
+       
+       // Get the embedded AuthRecord from the DNSRecordRef. Determine the type of DNSServiceRef from the releaseCallBack.
+       
+       if( inRef->releaseCallBack == DNSServiceRegisterRelease_direct )
+       {
+               err = mDNS_RemoveRecordFromService( gMDNSPtr, inRef->u.reg.set, &inRecordRef->u.service.extra );
+               free( inRecordRef );
+               require_noerr( err, exit );
+       }
+       else if( inRef->releaseCallBack == DNSServiceCreateConnectionRelease_direct )
+       {
+               mDNSBool                freeRR;
+               
+               inRecordRef = DNSServiceConnectionRecordRemove_direct( inRef, inRecordRef );
+               require_action( inRecordRef, exit, err = kDNSServiceErr_BadParam );
+               
+               freeRR = ( inRecordRef->u.connection.rr.resrec.RecordType != kDNSRecordTypeShared );
+               err = mDNS_Deregister( gMDNSPtr, &inRecordRef->u.connection.rr );
+               check_noerr( err );
+               if( freeRR || ( err != mStatus_NoError ) )
+               {
+                       free( inRecordRef );
+               }
+       }
+       else
+       {
+               dlog( kDebugLevelError, DEBUG_NAME "trying to remove a DNSRecordRef with an unsupported DNSServiceRef\n" );
+               err = kDNSServiceErr_Unsupported;
+               goto exit;
+       }
+       
+exit:
+       DNSServiceUnlock();
+       return( err );
+}
+
+#if 0
+#pragma mark -
+#pragma mark == Service Discovery ==
+#endif
+
+//===========================================================================================================================
+//     DNSServiceBrowse_direct
+//===========================================================================================================================
+
+DNSServiceErrorType
+       DNSServiceBrowse_direct(
+               DNSServiceRef *                 outRef,
+               DNSServiceFlags                 inFlags,
+               uint32_t                                inInterfaceIndex,
+               const char *                    inType,   
+               const char *                    inDomain,
+               DNSServiceBrowseReply   inCallBack,
+               void *                                  inContext )
+{
+       DNSServiceErrorType             err;
+       DNSServiceRef                   obj;
+       mDNSBool                                ok;
+       domainname                              type;
+       domainname                              domain;
+       mDNSInterfaceID                 interfaceID;
+       
+       obj = NULL;
+       DNSServiceLock();
+       require_action( outRef, exit, err = kDNSServiceErr_BadReference );
+       require_action( inFlags == 0, exit, err = kDNSServiceErr_BadFlags );
+       require_action( inType, exit, err = kDNSServiceErr_BadParam );
+       require_action( inCallBack, exit, err = kDNSServiceErr_BadParam );
+       
+       // Convert the input strings and make sure they are valid.
+       
+       ok = MakeDomainNameFromDNSNameString( &type, inType ) != NULL;
+       require_action( ok, exit, err = kDNSServiceErr_BadParam );
+       
+       if( !inDomain || ( *inDomain == '\0' ) )
+       {
+               inDomain = "local.";
+       }
+       ok = MakeDomainNameFromDNSNameString( &domain, inDomain ) != NULL;
+       require_action( ok, exit, err = kDNSServiceErr_BadParam );
+       
+       // Allocate and initialize the object.
+       
+       obj = (DNSServiceRef) calloc( 1, sizeof( *obj ) );
+       require_action( obj, exit, err = kDNSServiceErr_NoMemory );
+
+       obj->releaseCallBack    = DNSServiceBrowseRelease_direct;
+       obj->context                    = inContext;
+       obj->u.browse.callback  = inCallBack;
+
+       obj->next                               = gDNSServiceRefList;
+       gDNSServiceRefList              = obj;
+               
+       // Start browsing.
+       
+       interfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex( gMDNSPtr, inInterfaceIndex );
+       
+       err = mDNS_StartBrowse( gMDNSPtr, &obj->u.browse.question, &type, &domain, interfaceID, 
+               DNSServiceBrowseCallBack_direct, obj );
+       require_noerr( err, exit );
+       obj->u.browse.questionActive = mDNStrue;
+       
+       // Success!
+       
+       *outRef = obj;
+       obj     = NULL;
+       
+exit:
+       if( obj )
+       {
+               DNSServiceRefDeallocate_direct( obj );
+       }
+       DNSServiceUnlock();
+       return( err );
+}
+
+//===========================================================================================================================
+//     DNSServiceBrowseRelease_direct
+//
+//     Warning: Assumes the mDNS platform lock is held.
+//===========================================================================================================================
+
+DEBUG_LOCAL void       DNSServiceBrowseRelease_direct( DNSServiceRef inRef )
+{
+       OSStatus                err;
+       
+       check( inRef );
+       
+       if( inRef->u.browse.questionActive )
+       {
+               err = mDNS_StopBrowse( gMDNSPtr, &inRef->u.browse.question );
+               check_noerr( err );
+       }
+       free( inRef );
+}
+
+//===========================================================================================================================
+//     DNSServiceBrowseCallBack_direct
+//
+//     Warning: Assumes the mDNS platform lock is held (held by mDNS before invoking this callback).
+//===========================================================================================================================
+
+DEBUG_LOCAL void
+       DNSServiceBrowseCallBack_direct( 
+               mDNS * const                                    inMDNS, 
+               DNSQuestion *                                   inQuestion, 
+               const ResourceRecord * const    inAnswer, 
+               mDNSBool                                                inAddRecord )
+{
+       DNSServiceRef           obj;
+       DNSServiceFlags         flags;
+       uint32_t                        interfaceIndex;
+       mDNSBool                        ok;
+       domainlabel                     name;
+       domainname                      type;
+       domainname                      domain;
+       char                            nameString[ MAX_DOMAIN_LABEL + 1 ];
+       char                            typeString[ MAX_ESCAPED_DOMAIN_NAME ];
+       char                            domainString[ MAX_ESCAPED_DOMAIN_NAME ];
+       
+       DEBUG_UNUSED( inMDNS );
+       check( inQuestion );
+       obj = (DNSServiceRef) inQuestion->QuestionContext;
+       check( obj );
+
+       flags = inAddRecord ? kDNSServiceFlagsAdd : kDNSServiceFlagsNone;
+       interfaceIndex = mDNSPlatformInterfaceIndexfromInterfaceID( &gMDNS, inAnswer->InterfaceID );
+       
+       ok = DeconstructServiceName( &inAnswer->rdata->u.name, &name, &type, &domain );
+       check( ok );
+       
+       ConvertDomainLabelToCString_unescaped( &name, nameString );
+       ConvertDomainNameToCString( &type, typeString );
+       ConvertDomainNameToCString( &domain, domainString );
+       
+       obj->u.browse.callback( obj, flags, interfaceIndex, kDNSServiceErr_NoError, nameString, typeString, domainString, 
+               obj->context );
+}
+
+#if 0
+#pragma mark -
+#endif
+
+//===========================================================================================================================
+//     DNSServiceResolve_direct
+//===========================================================================================================================
+
+DNSServiceErrorType
+       DNSServiceResolve_direct( 
+               DNSServiceRef *                 outRef,
+               DNSServiceFlags                 inFlags,
+               uint32_t                                inInterfaceIndex,
+               const char *                    inName,     
+               const char *                    inType,  
+               const char *                    inDomain,   
+               DNSServiceResolveReply  inCallBack,
+               void *                                  inContext )
+{
+       DNSServiceErrorType             err;
+       DNSServiceRef                   obj;
+       mDNSBool                                ok;
+       domainlabel                             name;
+       domainname                              type;
+       domainname                              domain;
+       domainname                              fqdn;
+       mDNSInterfaceID                 interfaceID;
+       DNSQuestion *                   q;
+       
+       obj = NULL;
+       DNSServiceLock();
+       dlog( kDebugLevelTrace, DEBUG_NAME "%s\n", __ROUTINE__ );
+       require_action( outRef, exit, err = kDNSServiceErr_BadReference );
+       require_action( inFlags == 0, exit, err = kDNSServiceErr_BadFlags );
+       require_action( inName, exit, err = kDNSServiceErr_BadParam );
+       require_action( inType, exit, err = kDNSServiceErr_BadParam );
+       if( !inDomain || ( *inDomain == '\0' ) ) inDomain = "local.";
+       require_action( inCallBack, exit, err = kDNSServiceErr_BadParam );
+       
+       // Convert all the input strings and make sure they are valid.
+       
+       ok = MakeDomainLabelFromLiteralString( &name, inName );
+       require_action( ok, exit, err = kDNSServiceErr_BadParam );
+       
+       ok = MakeDomainNameFromDNSNameString( &type, inType ) != NULL;
+       require_action( ok, exit, err = kDNSServiceErr_BadParam );
+       
+       ok = MakeDomainNameFromDNSNameString( &domain, inDomain ) != NULL;
+       require_action( ok, exit, err = kDNSServiceErr_BadParam );
+       
+       ok = ConstructServiceName( &fqdn, &name, &type, &domain ) != NULL;
+       require_action( ok, exit, err = kDNSServiceErr_BadParam );
+       
+       interfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex( gMDNSPtr, inInterfaceIndex );
+       
+       // Allocate and initialize the object.
+       
+       obj = (DNSServiceRef) calloc( 1, sizeof( *obj ) );
+       require_action( obj, exit, err = kDNSServiceErr_NoMemory );
+       
+       obj->releaseCallBack    = DNSServiceResolveRelease_direct;
+       obj->context                    = inContext;
+       obj->u.resolve.flags    = inFlags;
+       obj->u.resolve.callback = inCallBack;
+       
+       obj->next                       = gDNSServiceRefList;
+       gDNSServiceRefList      = obj;
+       
+       // Start the SRV query.
+       
+       q                                       = &obj->u.resolve.srvQuestion;
+       q->InterfaceID          = interfaceID;
+       AssignDomainName( q->qname, fqdn );
+       q->qtype                        = kDNSType_SRV;
+       q->qclass                       = kDNSClass_IN;
+       q->QuestionCallback = DNSServiceResolveCallBack_direct;
+       q->QuestionContext      = obj;
+       
+       err = mDNS_StartQuery( gMDNSPtr, q );
+       require_noerr( err, exit );
+       obj->u.resolve.srvQuestionActive = mDNStrue;
+       
+       // Start the TXT query.
+       
+       q                                       = &obj->u.resolve.txtQuestion;
+       q->InterfaceID          = interfaceID;
+       AssignDomainName( q->qname, fqdn );
+       q->qtype                        = kDNSType_TXT;
+       q->qclass                       = kDNSClass_IN;
+       q->QuestionCallback = DNSServiceResolveCallBack_direct;
+       q->QuestionContext      = obj;
+       
+       err = mDNS_StartQuery( gMDNSPtr, q );
+       require_noerr( err, exit );
+       obj->u.resolve.txtQuestionActive = mDNStrue;
+       
+       // Success!
+       
+       *outRef = obj;
+       obj     = NULL;
+       
+exit:
+       if( obj )
+       {
+               DNSServiceRefDeallocate_direct( obj );
+       }
+       DNSServiceUnlock();
+       return( err );
+}
+
+//===========================================================================================================================
+//     DNSServiceResolveRelease_direct
+//===========================================================================================================================
+
+DEBUG_LOCAL void       DNSServiceResolveRelease_direct( DNSServiceRef inRef )
+{
+       OSStatus                err;
+       
+       check( inRef );
+               
+       if( inRef->u.resolve.srvQuestionActive )
+       {
+               inRef->u.resolve.srvQuestionActive = mDNSfalse;
+               err = mDNS_StopQuery( gMDNSPtr, &inRef->u.resolve.srvQuestion );
+               check_noerr( err );
+       }
+       if( inRef->u.resolve.txtQuestionActive )
+       {
+               inRef->u.resolve.txtQuestionActive = mDNSfalse;
+               err = mDNS_StopQuery( gMDNSPtr, &inRef->u.resolve.txtQuestion );
+               check_noerr( err );
+       }       
+       free( inRef );
+}
+
+//===========================================================================================================================
+//     DNSServiceResolveCallBack_direct
+//===========================================================================================================================
+
+DEBUG_LOCAL void
+       DNSServiceResolveCallBack_direct(
+               mDNS * const                                    inMDNS, 
+               DNSQuestion *                                   inQuestion, 
+               const ResourceRecord * const    inAnswer, 
+               mDNSBool                                                inAddRecord )
+{
+       DNSServiceRef                           obj;
+       const ResourceRecord **         answer;
+       uint32_t                                        ifi;
+       char                                            fullName[ MAX_ESCAPED_DOMAIN_NAME ];
+       char                                            hostName[ MAX_ESCAPED_DOMAIN_NAME ];
+       uint16_t                                        port;
+       const char *                            txt;
+       uint16_t                                        txtSize;
+       
+       DEBUG_UNUSED( inMDNS );
+       
+       check( inQuestion );
+       obj = (DNSServiceRef) inQuestion->QuestionContext;
+       check( obj );
+       check( inAnswer );
+       
+       // Select the answer based on the type.
+       
+       if(      inAnswer->rrtype == kDNSType_SRV ) answer = &obj->u.resolve.srvAnswer;
+       else if( inAnswer->rrtype == kDNSType_TXT ) answer = &obj->u.resolve.txtAnswer;
+       else
+       {
+               dlog( kDebugLevelError, DEBUG_NAME "%s: unexpected rrtype (%d)\n", __ROUTINE__, inAnswer->rrtype );
+               goto exit;
+       }
+       
+       // If the record is being removed, invalidate the previous answer. Otherwise, update with the new answer.
+       
+       if( !inAddRecord )
+       {
+               if( *answer == inAnswer ) *answer = NULL;
+               goto exit;
+       }
+       *answer = inAnswer;
+       
+       // Only deliver the result if we have both answers.
+       
+       if( !obj->u.resolve.srvAnswer || !obj->u.resolve.txtAnswer )
+       {
+               goto exit;
+       }
+       
+       // Convert the results to the appropriate format and call the callback.
+       
+       ifi             = mDNSPlatformInterfaceIndexfromInterfaceID( &gMDNS, obj->u.resolve.srvAnswer->InterfaceID );
+       ConvertDomainNameToCString( &obj->u.resolve.srvAnswer->name, fullName );
+    ConvertDomainNameToCString( &obj->u.resolve.srvAnswer->rdata->u.srv.target, hostName );
+    port       = obj->u.resolve.srvAnswer->rdata->u.srv.port.NotAnInteger;
+    txt                = (const char *) obj->u.resolve.txtAnswer->rdata->u.txt.c;
+    txtSize    = obj->u.resolve.txtAnswer->rdlength;
+    
+       obj->u.resolve.callback( obj, 0, ifi, kDNSServiceErr_NoError, fullName, hostName, port, txtSize, txt, obj->context );
+       
+exit:
+       return;
+}
+
+#if 0
+#pragma mark -
+#pragma mark == Special Purpose ==
+#endif
+
+//===========================================================================================================================
+//     DNSServiceCreateConnection_direct
+//===========================================================================================================================
+
+DNSServiceErrorType    DNSServiceCreateConnection_direct( DNSServiceRef *outRef )
+{
+       OSStatus                        err;
+       DNSServiceRef           obj;
+       
+       DNSServiceLock();
+       require_action( outRef, exit, err = kDNSServiceErr_BadReference );
+               
+       // Allocate and initialize the object.
+       
+       obj = (DNSServiceRef) calloc( 1, sizeof( *obj ) );
+       require_action( obj, exit, err = kNoMemoryErr );
+
+       obj->releaseCallBack    = DNSServiceCreateConnectionRelease_direct;
+
+       obj->next                               = gDNSServiceRefList;
+       gDNSServiceRefList              = obj;
+       
+       // Success!
+       
+       *outRef = obj;
+       err     = kNoErr;
+       
+exit:
+       DNSServiceUnlock();
+       return( err );
+}
+
+//===========================================================================================================================
+//     DNSServiceCreateConnectionRelease_direct
+//
+//     Warning: Assumes the mDNS platform lock is held.
+//===========================================================================================================================
+
+DEBUG_LOCAL void       DNSServiceCreateConnectionRelease_direct( DNSServiceRef inRef )
+{
+       check( inRef );
+               
+       while( inRef->u.connection.records )
+       {
+               DNSRecordRef            record;
+               mStatus                         err;
+               mDNSBool                        freeRR;
+               
+               record = inRef->u.connection.records;
+               inRef->u.connection.records = record->u.connection.next;
+               
+               // If somebody will be looking at this object next, move the current ptr to the next object.
+               
+               if( record == gDNSCurrentRecord )
+               {
+                       dlog( kDebugLevelInfo, DEBUG_NAME "deleting gDNSCurrentRecord (%#p)\n", record );
+                       gDNSCurrentRecord = record->u.connection.next;
+               }
+               
+               freeRR = ( record->u.connection.rr.resrec.RecordType != kDNSRecordTypeShared );
+               err = mDNS_Deregister( gMDNSPtr, &record->u.connection.rr );
+               check_noerr( err );
+               if( freeRR || ( err != mStatus_NoError ) )
+               {
+                       free( record );
+               }
+       }
+       free( inRef );
+}
+
+//===========================================================================================================================
+//     DNSServiceConnectionRecordRemove_direct
+//
+//     Warning: Assumes the mDNS platform lock is held.
+//===========================================================================================================================
+
+DEBUG_LOCAL DNSRecordRef       DNSServiceConnectionRecordRemove_direct( DNSServiceRef inRef, DNSRecordRef inRecordRef )
+{
+       DNSRecordRef *          p;
+       
+       for( p = &inRef->u.connection.records; *p; p = &( *p )->u.connection.next )
+       {
+               if( *p == inRecordRef )
+               {
+                       break;
+               }
+       }
+       inRecordRef = *p;
+       if( inRecordRef )
+       {
+               *p = inRecordRef->u.connection.next;
+               
+               // If somebody will be looking at this object next, move the current ptr to the next object.
+               
+               if( inRecordRef == gDNSCurrentRecord )
+               {
+                       gDNSCurrentRecord = inRecordRef->u.connection.next;
+               }
+       }
+       return( inRecordRef );
+}
+
+//===========================================================================================================================
+//     DNSServiceRegisterRecord_direct
+//===========================================================================================================================
+
+DNSServiceErrorType
+       DNSServiceRegisterRecord_direct(
+               DNSServiceRef                                   inRef,
+               DNSRecordRef *                                  outRecordRef,
+               DNSServiceFlags                                 inFlags,
+               uint32_t                                                inInterfaceIndex,
+               const char *                                    inName,   
+               uint16_t                                                inRRType,
+               uint16_t                                                inRRClass,
+               uint16_t                                                inRDataSize,
+               const void *                                    inRData,
+               uint32_t                                                inTTL,
+               DNSServiceRegisterRecordReply   inCallBack,
+               void *                                                  inContext )
+{
+       DNSServiceErrorType             err;
+       size_t                                  size;
+       DNSRecordRef                    obj;
+       AuthRecord *                    rr;
+       mDNSBool                                ok;
+               
+       obj = NULL;
+       DNSServiceLock();
+       require_action( inRef, exit, err = kDNSServiceErr_BadReference );
+       require_action( outRecordRef, exit, err = kDNSServiceErr_BadParam );
+       require_action( ( inFlags == kDNSServiceFlagsShared ) || 
+                                       ( inFlags == kDNSServiceFlagsUnique ), 
+                                       exit, err = kDNSServiceErr_BadFlags );
+       require_action( inRData && ( inRDataSize > 0 ), exit, err = kDNSServiceErr_BadParam );
+       require_action( inCallBack, exit, err = kDNSServiceErr_BadParam );
+       
+       // Allocate and initialize the record. Allocate oversized record space at the end of the record.
+       
+       size = ( inRDataSize > sizeof( RDataBody ) ) ? inRDataSize : sizeof( RDataBody );
+       obj = (DNSRecordRef) calloc( 1, ( kDNSRecordConnectionFixedSize - sizeof( RDataBody ) ) + size );
+       require_action( obj, exit, err = kDNSServiceErr_NoMemory );
+       
+       obj->u.connection.owner                 = inRef;
+       obj->u.connection.callback              = inCallBack;
+       obj->u.connection.context               = inContext;
+       
+       obj->u.connection.next                  = inRef->u.connection.records;
+       inRef->u.connection.records     = obj;
+       
+       rr                                                              = &obj->u.connection.rr;
+       rr->resrec.RecordType                   = (mDNSu8)( ( inFlags == kDNSServiceFlagsShared ) ? kDNSRecordTypeShared : kDNSRecordTypeUnique );
+       rr->resrec.InterfaceID                  = mDNSPlatformInterfaceIDfromInterfaceIndex( gMDNSPtr, inInterfaceIndex );
+       
+       ok = MakeDomainNameFromDNSNameString( &rr->resrec.name, inName ) != NULL;
+       require_action( ok, exit, err = kDNSServiceErr_BadParam );
+       
+       rr->resrec.rrtype                               = inRRType;
+       rr->resrec.rrclass                              = inRRClass;
+       rr->resrec.rroriginalttl                = inTTL;
+       rr->resrec.rdlength                     = inRDataSize;
+       rr->resrec.rdata                                = &rr->rdatastorage;
+       rr->resrec.rdata->MaxRDLength   = inRDataSize;
+       memcpy( rr->resrec.rdata->u.data, inRData, inRDataSize );
+       rr->RecordContext                               = obj;
+       rr->RecordCallback                              = DNSServiceRegisterRecordCallBack_direct;
+       
+       // Register the record with mDNS.
+       
+       err = mDNS_Register( gMDNSPtr, rr );
+       require_noerr( err, exit );
+       
+       // Success!
+       
+       *outRecordRef   = obj;
+       obj                     = NULL;
+       
+exit:
+       if( obj )
+       {
+               DNSServiceConnectionRecordRemove_direct( inRef, obj );
+               free( obj );
+       }
+       DNSServiceUnlock();
+       return( err );
+}
+
+//===========================================================================================================================
+//     DNSServiceRegisterRecord_direct
+//
+//     Warning: Assumes the mDNS platform lock is held (held by mDNS before invoking this callback).
+//===========================================================================================================================
+
+DEBUG_LOCAL void       DNSServiceRegisterRecordCallBack_direct( mDNS * const inMDNS, AuthRecord * const inRR, mStatus inResult )
+{
+       DNSRecordRef            obj;
+       
+       DEBUG_UNUSED( inMDNS );
+       
+       check( inRR );
+       obj = (DNSRecordRef) inRR->RecordContext;
+       check( obj );
+       
+       if( inResult == mStatus_MemFree )
+       {
+               DNSServiceConnectionRecordRemove_direct( obj->u.connection.owner, obj );
+               free( inRR );
+       }
+       else
+       {
+               obj->u.connection.callback( obj->u.connection.owner, obj, 0, inResult, obj->u.connection.context );
+       }
+}
+
+//===========================================================================================================================
+//     DNSServiceQueryRecord_direct
+//===========================================================================================================================
+
+DNSServiceErrorType
+       DNSServiceQueryRecord_direct(
+               DNSServiceRef *                         outRef,
+               DNSServiceFlags                         inFlags,
+               uint32_t                                        inInterfaceIndex,
+               const char *                            inName,     
+               uint16_t                                        inRRType,
+               uint16_t                                        inRRClass,
+               DNSServiceQueryRecordReply      inCallBack,
+               void *                                          inContext )
+{
+       DNSServiceErrorType             err;
+       DNSServiceRef                   obj;
+       DNSQuestion *                   q;
+       mDNSBool                                ok;
+       
+       obj = NULL;
+       DNSServiceLock();
+       require_action( outRef, exit, err = kDNSServiceErr_BadParam );
+       require_action( inFlags == 0, exit, err = kDNSServiceErr_BadFlags );
+       require_action( inName, exit, err = kDNSServiceErr_BadParam );
+       require_action( inCallBack, exit, err = kDNSServiceErr_BadParam );
+       
+       // Allocate and initialize the object.
+       
+       obj = (DNSServiceRef) calloc( 1, sizeof( *obj ) );
+       require_action( obj, exit, err = kDNSServiceErr_NoMemory );
+       
+       obj->releaseCallBack    = DNSServiceQueryRecordRelease_direct;
+       obj->context                    = inContext;
+       obj->u.query.callback   = inCallBack;
+       
+       q                                               = &obj->u.query.question;
+       q->InterfaceID                  = mDNSPlatformInterfaceIDfromInterfaceIndex( gMDNSPtr, inInterfaceIndex );
+       ok = MakeDomainNameFromDNSNameString( &q->qname, inName ) != NULL;
+       require_action( ok, exit, err = kDNSServiceErr_BadParam );
+       q->qtype                                = inRRType;
+       q->qclass                               = inRRClass;
+       q->QuestionCallback     = DNSServiceQueryRecordCallBack_direct;
+       q->QuestionContext              = obj;
+
+       obj->next                               = gDNSServiceRefList;
+       gDNSServiceRefList              = obj;
+       
+       // Start the query with mDNS.
+       
+       err = mDNS_StartQuery( gMDNSPtr, q );
+       require_noerr( err, exit );
+       obj->u.query.questionActive = mDNStrue;
+       
+       // Success!
+       
+       *outRef = obj;
+       obj     = NULL;
+       
+exit:
+       if( obj )
+       {       
+               DNSServiceRefDeallocate_direct( obj );
+       }
+       DNSServiceUnlock();
+       return( err );
+}
+
+//===========================================================================================================================
+//     DNSServiceQueryRecordRelease_direct
+//
+//     Warning: Assumes the mDNS platform lock is held.
+//===========================================================================================================================
+
+DEBUG_LOCAL void       DNSServiceQueryRecordRelease_direct( DNSServiceRef inRef )
+{
+       OSStatus                err;
+       
+       check( inRef );
+       
+       if( inRef->u.query.questionActive )
+       {
+               err = mDNS_StopQuery( gMDNSPtr, &inRef->u.query.question );
+               check_noerr( err );
+       }
+       free( inRef );
+}
+
+//===========================================================================================================================
+//     DNSServiceQueryRecordCallBack_direct
+//
+//     Warning: Assumes the mDNS platform lock is held (held by mDNS before invoking this callback).
+//===========================================================================================================================
+
+DEBUG_LOCAL void
+       DNSServiceQueryRecordCallBack_direct(
+               mDNS * const                                    inMDNS, 
+               DNSQuestion *                                   inQuestion, 
+               const ResourceRecord * const    inAnswer, 
+               mDNSBool                                                inAddRecord )
+{
+       DNSServiceRef           obj;
+       DNSServiceFlags         flags;
+       uint32_t                        interfaceIndex;
+       char                            name[ MAX_ESCAPED_DOMAIN_NAME ];
+       
+       DEBUG_UNUSED( inMDNS );
+       
+       check( inQuestion );
+       obj = (DNSServiceRef) inQuestion->QuestionContext;
+       check( obj );
+       check( inAnswer );
+               
+       flags = inAddRecord ? kDNSServiceFlagsAdd : kDNSServiceFlagsNone;
+       interfaceIndex = mDNSPlatformInterfaceIndexfromInterfaceID( &gMDNS, inAnswer->InterfaceID );
+       ConvertDomainNameToCString( &inAnswer->name, name );
+       obj->u.query.callback( obj, flags, interfaceIndex, kDNSServiceErr_NoError, name, inAnswer->rrtype, inAnswer->rrclass, 
+               inAnswer->rdlength, &inAnswer->rdata->u, inAddRecord ? inAnswer->rroriginalttl : 0, obj->context );
+}
+
+//===========================================================================================================================
+//     DNSServiceReconfirmRecord_direct
+//===========================================================================================================================
+
+void
+       DNSServiceReconfirmRecord_direct(
+               DNSServiceFlags inFlags,
+               uint32_t                inInterfaceIndex,
+               const char *    inName,   
+               uint16_t                inRRType,
+               uint16_t                inRRClass,
+               uint16_t                inRDataSize,
+               const void *    inRData )
+{
+       DNSServiceErrorType             err;
+       size_t                                  size;
+       AuthRecord *                    rr;
+       mDNSBool                                ok;
+               
+       rr = NULL;
+       DNSServiceLock();
+       require_action( inFlags == 0, exit, err = kDNSServiceErr_BadFlags );
+       require_action( inName, exit, err = kDNSServiceErr_BadParam );
+       require_action( inRData && ( inRDataSize > 0 ), exit, err = kDNSServiceErr_BadParam );
+               
+       size = ( inRDataSize > sizeof( RDataBody ) ) ? inRDataSize : sizeof( RDataBody );
+       rr = (AuthRecord *) calloc( 1, ( sizeof( *rr ) - sizeof( RDataBody ) ) + size );
+       require_action( rr, exit, err = kDNSServiceErr_NoMemory );
+       
+       rr->resrec.RecordType                   = (mDNSu8)( ( inFlags == kDNSServiceFlagsShared ) ? kDNSRecordTypeShared : kDNSRecordTypeUnique );
+       rr->resrec.InterfaceID                  = mDNSPlatformInterfaceIDfromInterfaceIndex( gMDNSPtr, inInterfaceIndex );
+       
+       ok = MakeDomainNameFromDNSNameString( &rr->resrec.name, inName ) != NULL;
+       require_action( ok, exit, err = kDNSServiceErr_BadParam );
+       
+       rr->resrec.rrtype                               = inRRType;
+       rr->resrec.rrclass                              = inRRClass;
+       rr->resrec.rdlength                     = inRDataSize;
+       rr->resrec.rdata                                = &rr->rdatastorage;
+       rr->resrec.rdata->MaxRDLength   = inRDataSize;
+       memcpy( rr->resrec.rdata->u.data, inRData, inRDataSize );
+
+       err = mDNS_ReconfirmByValue( gMDNSPtr, &rr->resrec );
+       check( ( err == mStatus_BadReferenceErr ) || ( err == mStatus_NoError ) );
+
+exit:
+       if( rr )
+       {
+               free( rr );
+       }
+       DNSServiceUnlock();
+}
+
+#ifdef __cplusplus
+       }
+#endif
+
+#endif // DNS_SD_DIRECT_ENABLED
diff --git a/mDNSWindows/DNSSDDirect.h b/mDNSWindows/DNSSDDirect.h
new file mode 100644 (file)
index 0000000..be7acb0
--- /dev/null
@@ -0,0 +1,285 @@
+/*
+ * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+
+$Log: DNSSDDirect.h,v $
+Revision 1.1  2004/01/30 02:46:15  bradley
+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.
+
+*/
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @header         DNSSDDirect.h
+       
+       @abstract       Direct (compiled-in) implementation of DNS-SD APIs.
+       
+       @discussion     
+       
+       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.
+*/
+
+#ifndef __DNS_SD_DIRECT__
+#define __DNS_SD_DIRECT__
+
+#include       "CommonServices.h"
+
+#include       "DNSSD.h"
+
+#ifdef __cplusplus
+       extern "C" {
+#endif
+
+#if 0
+#pragma mark == General ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        kDNSServiceCacheEntryCountDefault
+
+       @abstract       Default number of mDNS cache entries.
+*/
+
+#define        kDNSServiceCacheEntryCountDefault               512
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       DNSServiceInitialize_direct
+
+       @abstract       Initializes the DNSService API. No DNSService API's should be called before this call returns successfully.
+*/
+
+DNSServiceErrorType    DNSServiceInitialize_direct( DNSServiceInitializeFlags inFlags, int inCacheEntryCount );
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       DNSServiceFinalize_direct
+
+       @abstract       Finalizes the DNSService API. No DNSService API's should be called after this call is made.
+*/
+
+void   DNSServiceFinalize_direct( void );
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       DNSServiceRefDeallocate_direct
+
+       @abstract       Direct version of DNSServiceRefDeallocate.
+*/
+
+void   DNSServiceRefDeallocate_direct( DNSServiceRef inRef );
+
+#if 0
+#pragma mark == Domain Enumeration ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       DNSServiceEnumerateDomains_client
+
+       @abstract       Direct version of DNSServiceEnumerateDomains.
+*/
+
+DNSServiceErrorType
+       DNSServiceEnumerateDomains_direct(
+               DNSServiceRef *                                 outRef,
+               const DNSServiceFlags                   inFlags,
+               const uint32_t                                  inInterfaceIndex,
+               const DNSServiceDomainEnumReply inCallBack,
+               void *                                                  inContext );
+
+#if 0
+#pragma mark == Service Registration ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       DNSServiceRegister_direct
+
+       @abstract       Direct version of DNSServiceRegister.
+*/
+
+DNSServiceErrorType
+       DNSServiceRegister_direct(
+               DNSServiceRef *                 outRef,
+               DNSServiceFlags                 inFlags,
+               uint32_t                                inInterfaceIndex,
+               const char *                    inName,
+               const char *                    inType,
+               const char *                    inDomain,
+               const char *                    inHost,
+               uint16_t                                inPort,
+               uint16_t                                inTXTSize,
+               const void *                    inTXT,
+               DNSServiceRegisterReply inCallBack,
+               void *                                  inContext );
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       DNSServiceAddRecord_direct
+
+       @abstract       Direct version of DNSServiceAddRecord.
+*/
+
+DNSServiceErrorType
+       DNSServiceAddRecord_direct(
+               DNSServiceRef   inRef,
+               DNSRecordRef *  outRecordRef,
+               DNSServiceFlags inFlags,
+               uint16_t                inRRType,
+               uint16_t                inRDataSize,
+               const void *    inRData,
+               uint32_t                inTTL );
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       DNSServiceUpdateRecord_direct
+
+       @abstract       Direct version of DNSServiceUpdateRecord.
+*/
+
+DNSServiceErrorType
+       DNSServiceUpdateRecord_direct(
+    DNSServiceRef      inRef,
+    DNSRecordRef       inRecordRef,
+    DNSServiceFlags    inFlags,
+    uint16_t           inRDataSize,
+    const void *       inRData,
+    uint32_t           inTTL );
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       DNSServiceRemoveRecord_direct
+
+       @abstract       Direct version of DNSServiceRemoveRecord.
+*/
+
+DNSServiceErrorType DNSServiceRemoveRecord_direct( DNSServiceRef inRef, DNSRecordRef inRecordRef, DNSServiceFlags inFlags );
+
+#if 0
+#pragma mark == Service Discovery ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       DNSServiceBrowse_direct
+
+       @abstract       Direct version of DNSServiceBrowse.
+*/
+
+DNSServiceErrorType
+       DNSServiceBrowse_direct(
+               DNSServiceRef *                 outRef,
+               DNSServiceFlags                 inFlags,
+               uint32_t                                inInterfaceIndex,
+               const char *                    inType,   
+               const char *                    inDomain,
+               DNSServiceBrowseReply   inCallBack,
+               void *                                  inContext );
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       DNSServiceResolve_direct
+
+       @abstract       Direct version of DNSServiceResolve.
+*/
+
+DNSServiceErrorType
+       DNSServiceResolve_direct( 
+               DNSServiceRef *                 inRef,
+               DNSServiceFlags                 inFlags,
+               uint32_t                                inInterfaceIndex,
+               const char *                    inName,     
+               const char *                    inType,  
+               const char *                    inDomain,   
+               DNSServiceResolveReply  inCallBack,
+               void *                                  inContext );
+
+#if 0
+#pragma mark == Special Purpose ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       DNSServiceCreateConnection_direct
+
+       @abstract       Direct version of DNSServiceCreateConnection.
+*/
+
+DNSServiceErrorType    DNSServiceCreateConnection_direct( DNSServiceRef *outRef );
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       DNSServiceRegisterRecord_direct
+
+       @abstract       Direct version of DNSServiceRegisterRecord.
+*/
+
+DNSServiceErrorType
+       DNSServiceRegisterRecord_direct(
+               DNSServiceRef                                   inRef,
+               DNSRecordRef *                                  outRecordRef,
+               DNSServiceFlags                                 inFlags,
+               uint32_t                                                inInterfaceIndex,
+               const char *                                    inName,   
+               uint16_t                                                inRRType,
+               uint16_t                                                inRRClass,
+               uint16_t                                                inRDataSize,
+               const void *                                    inRData,
+               uint32_t                                                inTTL,
+               DNSServiceRegisterRecordReply   inCallBack,
+               void *                                                  inContext );
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       DNSServiceQueryRecord_direct
+
+       @abstract       Direct version of DNSServiceQueryRecord.
+*/
+
+DNSServiceErrorType
+       DNSServiceQueryRecord_direct(
+               DNSServiceRef *                         outRef,
+               DNSServiceFlags                         inFlags,
+               uint32_t                                        inInterfaceIndex,
+               const char *                            inName,     
+               uint16_t                                        inRRType,
+               uint16_t                                        inRRClass,
+               DNSServiceQueryRecordReply      inCallBack,
+               void *                                          inContext );
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       DNSServiceReconfirmRecord_direct
+
+       @abstract       Direct version of DNSServiceReconfirmRecord.
+*/
+
+void
+       DNSServiceReconfirmRecord_direct(
+               DNSServiceFlags inFlags,
+               uint32_t                inInterfaceIndex,
+               const char *    inName,   
+               uint16_t                inRRType,
+               uint16_t                inRRClass,
+               uint16_t                inRDataSize,
+               const void *    inRData );
+
+#ifdef __cplusplus
+       }
+#endif
+
+#endif // __DNS_SD_DIRECT__
index 77e3dcb13e72718abbaa21d31bd0c54b310f21e1..e8d5e2e76c0c749e9950abd42dab5f704fc4136a 100644 (file)
@@ -1,8 +1,10 @@
 /*
- * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
     Change History (most recent first):
 
 $Log: DNSServiceDiscovery.c,v $
+Revision 1.7  2004/05/08 12:24:48  bradley
+Removed trailing character from zero value to fix compile error.
+
+Revision 1.6  2004/05/06 18:42:58  ksekar
+General dns_sd.h API cleanup, including the following radars:
+<rdar://problem/3592068>: Remove flags with zero value
+<rdar://problem/3479569>: Passing in NULL causes a crash.
+
+Revision 1.5  2004/01/30 02:56:34  bradley
+Updated to support full Unicode display. Added support for all services on www.dns-sd.org.
+
+Revision 1.4  2003/11/14 20:59:10  cheshire
+Clients can't use AssignDomainName macro because mDNSPlatformMemCopy is defined in mDNSPlatformFunctions.h.
+Best solution is just to combine mDNSClientAPI.h and mDNSPlatformFunctions.h into a single file.
+
+Revision 1.3  2003/10/04 04:47:08  bradley
+Changed DNSServiceRegistrationCreate to treat the port in network byte order for end-to-end consistency.
+
 Revision 1.2  2003/08/20 07:06:34  bradley
 Update to APSL 2.0. Updated change history to match other mDNSResponder files.
 
@@ -55,7 +75,6 @@ Platform-neutral DNSServices-based emulation layer for the Mac OS X DNSServiceDi
 #endif
 
 #include       "mDNSClientAPI.h"
-#include       "mDNSPlatformFunctions.h"
 #include       "DNSServices.h"
 
 #include       "DNSServiceDiscovery.h"
@@ -179,6 +198,7 @@ dns_service_discovery_ref
        dns_service_discovery_ref               obj;
        void *                                                  txt;
        size_t                                                  txtSize;
+       DNSOpaque16                                             port;
        DNSRegistrationRef                              registration;
        
        result  = NULL;
@@ -203,7 +223,9 @@ dns_service_discovery_ref
                require_noerr( err, exit );
        }
        
-       err = DNSRegistrationCreate( kDNSRegistrationFlagPreFormattedTextRecord, inName, inType, inDomain, inPort, txt, 
+       port.v8[ 0 ] = (DNSUInt8)( inPort >> 8 );
+       port.v8[ 1 ] = (DNSUInt8)( inPort & 0xFF );
+       err = DNSRegistrationCreate( kDNSRegistrationFlagPreFormattedTextRecord, inName, inType, inDomain, port.v16, txt, 
                                                                 (DNSCount) txtSize, NULL, NULL, DNSServiceRegistrationPrivateCallBack, obj, &registration );
        require_noerr( err, exit ); 
        obj->ref = registration;
@@ -426,7 +448,7 @@ DNS_LOCAL void
                        if( callback )
                        {
                                callback( DNSServiceDomainEnumerationReplyAddDomain, inEvent->data.addDomain.domain, 
-                                                 DNSServiceDiscoverReplyFlagsFinished, obj->context );
+                                                 0, obj->context );
                        }
                        break;
                
@@ -436,7 +458,7 @@ DNS_LOCAL void
                        if( callback )
                        {
                                callback( DNSServiceDomainEnumerationReplyAddDomainDefault, inEvent->data.addDefaultDomain.domain, 
-                                                 DNSServiceDiscoverReplyFlagsFinished, obj->context );
+                                                 0, obj->context );
                        }
                        break;
                
@@ -446,7 +468,7 @@ DNS_LOCAL void
                        if( callback )
                        {
                                callback( DNSServiceDomainEnumerationReplyRemoveDomain, inEvent->data.removeDomain.domain, 
-                                                 DNSServiceDiscoverReplyFlagsFinished, obj->context );
+                                                 0, obj->context );
                        }
                        break;
                
@@ -547,7 +569,7 @@ DNS_LOCAL void
                                                  inEvent->data.addService.name, 
                                                  inEvent->data.addService.type, 
                                                  inEvent->data.addService.domain, 
-                                                 DNSServiceDiscoverReplyFlagsFinished
+                                                 0
                                                  obj->context );
                        }
                        break;
@@ -564,7 +586,7 @@ DNS_LOCAL void
                                                  inEvent->data.removeService.name, 
                                                  inEvent->data.removeService.type, 
                                                  inEvent->data.removeService.domain, 
-                                                 DNSServiceDiscoverReplyFlagsFinished
+                                                 0
                                                  obj->context );
                        }
                        break;
@@ -667,7 +689,7 @@ DNS_LOCAL void
                        if( callback )
                        {
                                callback( (struct sockaddr *) &interfaceAddr, (struct sockaddr *) &addr, inEvent->data.resolved.textRecord, 
-                                                 DNSServiceDiscoverReplyFlagsFinished, obj->context );
+                                                 0, obj->context );
                        }
                        break;
                                
index 618bbb3d3e37459b43ea8f48afda5ef60bfaa2b9..eae6d472e6983580e5a371f48393e73717bf07fb 100644 (file)
@@ -1,8 +1,10 @@
 /*
- * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
     Change History (most recent first):
 
 $Log: DNSServiceDiscovery.h,v $
+Revision 1.4  2004/05/06 18:42:58  ksekar
+General dns_sd.h API cleanup, including the following radars:
+<rdar://problem/3592068>: Remove flags with zero value
+<rdar://problem/3479569>: Passing in NULL causes a crash.
+
+Revision 1.3  2004/01/30 02:56:34  bradley
+Updated to support full Unicode display. Added support for all services on www.dns-sd.org.
+
 Revision 1.2  2003/08/20 07:06:34  bradley
 Update to APSL 2.0. Updated change history to match other mDNSResponder files.
 
@@ -177,7 +187,6 @@ typedef enum
 
 typedef enum
 {
-    DNSServiceDiscoverReplyFlagsFinished,
     DNSServiceDiscoverReplyFlagsMoreComing,
 } DNSServiceDiscoveryReplyFlags;
 
index ca84436895996fc920521ca60ea7b3e77ecac04e..79a3258d100010c687cd869eae18687a3a740980 100755 (executable)
@@ -1,8 +1,10 @@
 /*
- * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
     Change History (most recent first):
     
 $Log: DNSServices.c,v $
+Revision 1.26  2004/06/05 00:04:27  cheshire
+<rdar://problem/3668639>: wide-area domains should be returned in reg. domain enumeration
+
+Revision 1.25  2004/04/08 09:31:17  bradley
+Renamed local variable to avoid hiding a system global in some libraries.
+
+Revision 1.24  2004/01/30 02:56:34  bradley
+Updated to support full Unicode display. Added support for all services on www.dns-sd.org.
+
+Revision 1.23  2004/01/24 23:57:29  cheshire
+Change to use mDNSOpaque16fromIntVal() instead of shifting and masking
+
+Revision 1.22  2003/12/17 21:12:15  bradley
+<rdar://problem/3491823>: Use the default .local domain when registering with an empty domain.
+
+Revision 1.21  2003/11/20 22:29:56  cheshire
+Don't need to use MAX_ESCAPED_DOMAIN_LABEL for the name part -- that's not escaped
+
+Revision 1.20  2003/11/14 21:27:09  cheshire
+<rdar://problem/3484766>: Security: Crashing bug in mDNSResponder
+Fix code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1005) instead of 256-byte buffers.
+
+Revision 1.19  2003/11/14 20:59:10  cheshire
+Clients can't use AssignDomainName macro because mDNSPlatformMemCopy is defined in mDNSPlatformFunctions.h.
+Best solution is just to combine mDNSClientAPI.h and mDNSPlatformFunctions.h into a single file.
+
+Revision 1.18  2003/11/14 19:18:34  cheshire
+Move AssignDomainName macro to mDNSClientAPI.h to that client layers can use it too
+
+Revision 1.17  2003/10/31 12:16:03  bradley
+Added support for providing the resolved host name to the callback.
+
+Revision 1.16  2003/10/16 09:16:39  bradley
+Unified address copying to fix a problem with IPv6 resolves not being passed up as IPv6.
+
 Revision 1.15  2003/08/20 06:44:24  bradley
 Updated to latest internal version of the Rendezvous for Windows code: Added support for interface
 specific registrations; Added support for no-such-service registrations; Added support for host
@@ -102,7 +139,6 @@ DNS Services for Windows
 #endif
 
 #include       "mDNSClientAPI.h"
-#include       "mDNSPlatformFunctions.h"
 
 #include       "DNSServices.h"
 
@@ -289,8 +325,6 @@ struct      DNSHostRegistration
        #define require_action_string( assertion, label, action, cstring )      do { if( !(assertion) ) { {action;}; goto label; } } while(0)
 #endif
 
-#define AssignDomainName(DST, SRC) mDNSPlatformMemCopy((SRC).c, (DST).c, DomainNameLength(&(SRC)))
-
 #if 0
 #pragma mark == Prototypes ==
 #endif
@@ -367,7 +401,7 @@ mDNSlocal void      DNSHostRegistrationPrivateCallBack( mDNS * const inMDNS, AuthReco
 
 mDNSlocal DNSStatus    DNSMemAlloc( size_t inSize, void *outMem );
 mDNSlocal void         DNSMemFree( void *inMem );
-mDNSlocal void         MDNSAddrToDNSAddress( const mDNSAddr *inAddr, DNSNetworkAddress *outAddr );
+mDNSlocal void         MDNSAddrToDNSAddress( const mDNSAddr *inAddr, mDNSIPPort inPort, DNSNetworkAddress *outAddr );
 
 // Platform Accessors
 
@@ -736,11 +770,11 @@ DNSStatus DNSBrowserStartDomainSearch( DNSBrowserRef inRef, DNSBrowserFlags inFl
        
        // Start the browse operations.
        
-       err = mDNS_GetDomains( gMDNSPtr, &inRef->domainQuestion, type, mDNSInterface_Any, DNSBrowserPrivateCallBack, inRef );
+       err = mDNS_GetDomains( gMDNSPtr, &inRef->domainQuestion, type, NULL, mDNSInterface_Any, DNSBrowserPrivateCallBack, inRef );
        require_noerr( err, exit );
        isDomainBrowsing = mDNStrue;
        
-       err = mDNS_GetDomains( gMDNSPtr, &inRef->defaultDomainQuestion, defaultType, mDNSInterface_Any, DNSBrowserPrivateCallBack, inRef );
+       err = mDNS_GetDomains( gMDNSPtr, &inRef->defaultDomainQuestion, defaultType, NULL, mDNSInterface_Any, DNSBrowserPrivateCallBack, inRef );
        require_noerr( err, exit );
        
        inRef->domainSearchFlags        = inFlags;
@@ -815,7 +849,7 @@ DNSStatus
        require_action( !inRef->isServiceBrowsing, exit, err = kDNSBadStateErr );
        require_action( inType, exit, err = kDNSBadParamErr );
        
-       // Default to the local domain when null is passed in.
+       // Default to the local domain when a NULL, empty, or "." domain is passed in.
        
        if( !inDomain || ( inDomain[ 0 ] == '\0' ) || ( inDomain[ 0 ] == '.' ) )
        {
@@ -893,9 +927,9 @@ mDNSlocal void
        domainlabel                     name;
        domainname                      type;
        domainname                      domain;
-       char                            nameString[ 256 ];
-       char                            typeString[ 256 ];
-       char                            domainString[ 256 ];
+       char                            nameString  [ MAX_DOMAIN_LABEL + 1 ];   // Name part is not escaped
+       char                            typeString  [ MAX_ESCAPED_DOMAIN_NAME ];
+       char                            domainString[ MAX_ESCAPED_DOMAIN_NAME ];
        DNSBrowserEvent         event;
        mStatus                         err;
        
@@ -953,7 +987,7 @@ mDNSlocal void
                        if( err == mStatus_NoError )
                        {
                                serviceDataPtr->interfaceName = info.name;
-                               MDNSAddrToDNSAddress( &info.ip, &serviceDataPtr->interfaceIP );
+                               MDNSAddrToDNSAddress( &info.ip, zeroIPPort, &serviceDataPtr->interfaceIP );
                        }
                        else
                        {
@@ -975,7 +1009,6 @@ mDNSlocal void
                
                if( ( browserFlags & kDNSBrowserFlagAutoResolve ) && inAddRecord )
                {
-                       DNSStatus                               err;
                        DNSResolverFlags                flags;
                        
                        flags = kDNSResolverFlagOnlyIfUnique | kDNSResolverFlagAutoReleaseByName;
@@ -1032,7 +1065,7 @@ mDNSlocal void
                        if( err == mStatus_NoError )
                        {
                                domainDataPtr->interfaceName = info.name;
-                               MDNSAddrToDNSAddress( &info.ip, &domainDataPtr->interfaceIP );
+                               MDNSAddrToDNSAddress( &info.ip, zeroIPPort, &domainDataPtr->interfaceIP );
                        }
                        else
                        {
@@ -1079,15 +1112,6 @@ mDNSlocal void
        switch( inEvent->type )
        {
                case kDNSResolverEventTypeResolved:
-                       verbosedebugf( DEBUG_NAME "private resolver callback: resolved (ref=0x%08X)", inRef );
-                       verbosedebugf( DEBUG_NAME "    name:   \"%s\"",         inEvent->data.resolved.name );
-                       verbosedebugf( DEBUG_NAME "    type:   \"%s\"",         inEvent->data.resolved.type );
-                       verbosedebugf( DEBUG_NAME "    domain: \"%s\"",         inEvent->data.resolved.domain );
-                       verbosedebugf( DEBUG_NAME "    if:     %.4a",           &inEvent->data.resolved.interfaceIP.u.ipv4.addr.v32 );
-                       verbosedebugf( DEBUG_NAME "    ip:     %.4a:%u",        &inEvent->data.resolved.address.u.ipv4.addr.v32, 
-                                                                                                                               ( inEvent->data.resolved.address.u.ipv4.port.v8[ 0 ] << 8 ) |
-                                                                                                                                 inEvent->data.resolved.address.u.ipv4.port.v8[ 1 ] );
-                       verbosedebugf( DEBUG_NAME "    text:   \"%s\"",         inEvent->data.resolved.textRecord );
                        
                        // Re-package the resolver event as a browser event and call the callback.
                        
@@ -1376,6 +1400,7 @@ mDNSlocal void    DNSResolverPrivateCallBack( mDNS * const inMDNS, ServiceInfoQuery
        char *                                  txtString;
        mStatus                                 err;
        mDNSBool                                release;
+       char                                    hostName[ MAX_ESCAPED_DOMAIN_NAME ];
        
        txtString = NULL;
        
@@ -1407,7 +1432,7 @@ mDNSlocal void    DNSResolverPrivateCallBack( mDNS * const inMDNS, ServiceInfoQuery
                if( err == mStatus_NoError )
                {
                        event.data.resolved.interfaceName = info.name;
-                       MDNSAddrToDNSAddress( &info.ip, &event.data.resolved.interfaceIP );
+                       MDNSAddrToDNSAddress( &info.ip, zeroIPPort, &event.data.resolved.interfaceIP );
                }
                else
                {
@@ -1415,13 +1440,13 @@ mDNSlocal void  DNSResolverPrivateCallBack( mDNS * const inMDNS, ServiceInfoQuery
                }
        }
        event.data.resolved.interfaceID                                         = inQuery->info->InterfaceID;
-       event.data.resolved.address.addressType                         = kDNSNetworkAddressTypeIPv4;
-       event.data.resolved.address.u.ipv4.addr.v32             = inQuery->info->ip.ip.v4.NotAnInteger;
-       event.data.resolved.address.u.ipv4.port.v16                     = inQuery->info->port.NotAnInteger;
+       MDNSAddrToDNSAddress( &inQuery->info->ip, inQuery->info->port, &event.data.resolved.address );
        event.data.resolved.textRecord                                          = txtString ? txtString : "";
        event.data.resolved.flags                                                       = 0;
        event.data.resolved.textRecordRaw                                       = (const void *) inQuery->info->TXTinfo;
        event.data.resolved.textRecordRawSize                           = (DNSCount) inQuery->info->TXTlen;
+       ConvertDomainNameToCString( &inQuery->qAv4.qname, hostName );
+       event.data.resolved.hostName                                            = hostName;
        release                                                                                         = (mDNSBool)( ( objectPtr->flags & kDNSResolverFlagOneShot ) != 0 );
        objectPtr->callback( objectPtr->callbackContext, objectPtr, kDNSNoErr, &event );
        
@@ -1556,7 +1581,6 @@ DNSStatus
        domainlabel                             name;
        domainname                              type;
        domainname                              domain;
-       mDNSIPPort                              port;
        mDNSu8                                  textRecord[ 256 ];
        const mDNSu8 *                  textRecordPtr;
        domainname *                    host;
@@ -1576,9 +1600,9 @@ DNSStatus
        require_action( !inInterfaceName || 
                                        ( strlen( inInterfaceName ) < sizeof( objectPtr->interfaceName ) ), exit, err = kDNSBadParamErr );
        
-       // Default to the local domain when null is passed in.
+       // Default to the local domain when a NULL, empty, or "." domain is passed in.
        
-       if( !inDomain )
+       if( !inDomain || ( inDomain[ 0 ] == '\0' ) || ( inDomain[ 0 ] == '.' ) )
        {
                inDomain = kDNSLocalDomain;
        }
@@ -1650,8 +1674,6 @@ DNSStatus
        }
        MakeDomainNameFromDNSNameString( &type, inType );
        MakeDomainNameFromDNSNameString( &domain, inDomain );
-       port.b[ 0 ] = ( mDNSu8 )( inPort >> 8 );
-       port.b[ 1 ] = ( mDNSu8 )( inPort >> 0 );
        
        // Set up the host name (if not using the default).
        
@@ -1665,7 +1687,7 @@ DNSStatus
                
        // Register the service with mDNS.
        
-       err = mDNS_RegisterService( gMDNSPtr, &objectPtr->set, &name, &type, &domain, host, port, textRecordPtr, 
+       err = mDNS_RegisterService( gMDNSPtr, &objectPtr->set, &name, &type, &domain, host, mDNSOpaque16fromIntVal(inPort), textRecordPtr, 
                                                                (mDNSu16) inTextRecordSize, NULL, 0, interfaceID, 
                                                                DNSRegistrationPrivateCallBack, objectPtr );
        require_noerr( err, exit );
@@ -1720,9 +1742,9 @@ DNSStatus
        require_action( !inInterfaceName || 
                                        ( strlen( inInterfaceName ) < sizeof( objectPtr->interfaceName ) ), exit, err = kDNSBadParamErr );
        
-       // Default to the local domain when null is passed in.
+       // Default to the local domain when a NULL, empty, or "." domain is passed in.
        
-       if( !inDomain )
+       if( !inDomain || ( inDomain[ 0 ] == '\0' ) || ( inDomain[ 0 ] == '.' ) )
        {
                inDomain = kDNSLocalDomain;
        }
@@ -1947,14 +1969,14 @@ mDNSlocal void  DNSRegistrationPrivateCallBack( mDNS * const inMDNS, ServiceRecor
                case mStatus_NameConflict:
                {
                        DNSStatus               err;
-                       mDNSBool                remove;
+                       mDNSBool                removeIt;
                        
                        debugf( DEBUG_NAME "registration callback: \"%##s\" name conflict", inSet->RR_SRV.resrec.name.c );
                        
                        // Name conflict. If the auto-rename option is enabled, uniquely rename the service and re-register it. Otherwise, 
                        // remove the object so they cannot try to use it in the callback and notify the client of the name conflict.
                        
-                       remove = mDNStrue;
+                       removeIt = mDNStrue;
                        if( object->flags & kDNSRegistrationFlagAutoRenameOnConflict )
                        {
                                err = mDNS_RenameAndReregisterService( inMDNS, inSet, mDNSNULL );
@@ -1962,10 +1984,10 @@ mDNSlocal void  DNSRegistrationPrivateCallBack( mDNS * const inMDNS, ServiceRecor
                                if( err == mStatus_NoError )
                                {
                                        debugf( DEBUG_NAME "registration callback: auto-renamed to \"%##s\"", inSet->RR_SRV.resrec.name.c );
-                                       remove = mDNSfalse;
+                                       removeIt = mDNSfalse;
                                }
                        }
-                       if( remove )
+                       if( removeIt )
                        {
                                object = DNSRegistrationRemoveObject( object );
                                require( object, exit );
@@ -2324,9 +2346,9 @@ DNSStatus
        require_action( !inInterfaceName || 
                                        ( strlen( inInterfaceName ) < sizeof( object->interfaceName ) ), exit, err = kDNSBadParamErr );
        
-       // Default to the local domain when null is passed in.
+       // Default to the local domain when a NULL, empty, or "." domain is passed in.
        
-       if( !inDomain )
+       if( !inDomain || ( inDomain[ 0 ] == '\0' ) || ( inDomain[ 0 ] == '.' ) )
        {
                inDomain = kDNSLocalDomain;
        }
@@ -2945,7 +2967,7 @@ DNSStatus DNSTextRecordEscape( const void *inTextRecord, size_t inTextSize, char
                        }
                        *dst++ = '\001';        // \001 record separator. May be overwritten later if this is the last record.
                }
-               check( ( dst - dstStorage ) <= inTextSize );
+               check( (size_t)( dst - dstStorage ) <= inTextSize );
                if( src != end )
                {
                        // Malformed TXT record. Assume an old-style TXT record and use the TXT record as a whole.
@@ -3130,13 +3152,14 @@ exit:
 //     MDNSAddrToDNSAddress
 //===========================================================================================================================
 
-mDNSlocal void MDNSAddrToDNSAddress( const mDNSAddr *inAddr, DNSNetworkAddress *outAddr )
+mDNSlocal void MDNSAddrToDNSAddress( const mDNSAddr *inAddr, mDNSIPPort inPort, DNSNetworkAddress *outAddr )
 {
        switch( inAddr->type )
        {
                case mDNSAddrType_IPv4:
                        outAddr->addressType            = kDNSNetworkAddressTypeIPv4;
                        outAddr->u.ipv4.addr.v32        = inAddr->ip.v4.NotAnInteger;
+                       outAddr->u.ipv4.port.v16        = inPort.NotAnInteger;
                        break;
                
                case mDNSAddrType_IPv6:
@@ -3145,6 +3168,7 @@ mDNSlocal void    MDNSAddrToDNSAddress( const mDNSAddr *inAddr, DNSNetworkAddress *
                        outAddr->u.ipv6.addr.v32[ 1 ]   = inAddr->ip.v6.l[ 1 ];
                        outAddr->u.ipv6.addr.v32[ 2 ]   = inAddr->ip.v6.l[ 2 ];
                        outAddr->u.ipv6.addr.v32[ 3 ]   = inAddr->ip.v6.l[ 3 ];
+                       outAddr->u.ipv6.port.v16                = inPort.NotAnInteger;
                        break;
                
                default:
index fbbb2bb0072c51d4cd87d7d0d5996557568fbdfc..bbf48b1c849053863a3bb7c591244744a467fb24 100755 (executable)
@@ -1,8 +1,10 @@
 /*
- * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
     Change History (most recent first):
     
 $Log: DNSServices.h,v $
+Revision 1.10  2004/01/30 02:56:34  bradley
+Updated to support full Unicode display. Added support for all services on www.dns-sd.org.
+
+Revision 1.9  2003/10/31 12:16:03  bradley
+Added support for providing the resolved host name to the callback.
+
 Revision 1.8  2003/08/20 06:44:24  bradley
 Updated to latest internal version of the Rendezvous for Windows code: Added support for interface
 specific registrations; Added support for no-such-service registrations; Added support for host
@@ -648,6 +656,9 @@ enum
 
        @field          textRecordRawSize
                                        Number of bytes in raw TXT record. May be needed if a custom TXT record format is used.
+
+       @field          hostName
+                                       Host name of the resolved service.
 */
 
 typedef struct DNSResolverEventResolveData             DNSResolverEventResolveData;
@@ -664,6 +675,7 @@ struct      DNSResolverEventResolveData
        DNSResolverFlags                flags;
        const void *                    textRecordRaw;
        DNSCount                                textRecordRawSize;
+       const char *                    hostName;
 };
 
 //---------------------------------------------------------------------------------------------------------------------------
@@ -1310,7 +1322,7 @@ DNSStatus
 //---------------------------------------------------------------------------------------------------------------------------
 /*!    @function       DNSNoSuchServiceRegistrationCreate
 
-       @abstract       Creates a registration object and publish the registration to assert non-existence of a particular service.
+       @abstract       Creates a registration object and publish the registration to assert non-existance of a particular service.
 
        @param          inFlags
                                        Flags to control the registration process.
diff --git a/mDNSWindows/DebugServices.c b/mDNSWindows/DebugServices.c
new file mode 100644 (file)
index 0000000..7742b59
--- /dev/null
@@ -0,0 +1,3101 @@
+/*
+ * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+    
+$Log: DebugServices.c,v $
+Revision 1.4  2004/04/15 08:59:08  bradley
+Removed deprecated debug and log levels and replaced them with modern equivalents.
+
+Revision 1.3  2004/04/08 09:29:55  bradley
+Manually do host->network byte order conversion to avoid needing libraries for htons/htonl. Changed
+hex dumps to better separate hex and ASCII. Added support for %.8a syntax in DebugSNPrintF for Fibre
+Channel addresses (00:11:22:33:44:55:66:77). Fixed a few places where HeaderDoc was incorrect.
+
+Revision 1.2  2004/03/07 05:59:34  bradley
+Sync'd with internal version: Added expect macros, error codes, and CoreServices exclusion.
+
+Revision 1.1  2004/01/30 02:27:30  bradley
+Debugging support for various platforms.
+
+
+       To Do:
+       
+       - Use StackWalk on Windows to optionally print stack frames.
+*/
+
+#if 0
+#pragma mark == Includes ==
+#endif
+
+//===========================================================================================================================
+//     Includes
+//===========================================================================================================================
+
+#if( !KERNEL )
+       #include        <ctype.h>
+       #include        <stdio.h>
+       #include        <string.h>
+#endif
+
+#include       "CommonServices.h"
+
+#include       "DebugServices.h"
+
+#if( DEBUG )
+
+#if( TARGET_OS_VXWORKS )
+       #include        "intLib.h"
+#endif
+
+#if( TARGET_OS_WIN32 )
+       #include        <time.h>
+       
+       #if( !TARGET_OS_WINDOWS_CE )
+               #include        <fcntl.h>
+               #include        <io.h>
+       #endif
+#endif
+
+#if( DEBUG_IDEBUG_ENABLED && TARGET_API_MAC_OSX_KERNEL )
+       #include        <IOKit/IOLib.h>
+#endif
+
+// If MDNS_DEBUGMSGS is defined (even if defined 0), it is aware of mDNS and it is probably safe to include mDNSClientAPI.h.
+
+#if( defined( MDNS_DEBUGMSGS ) )
+       #include        "mDNSClientAPI.h"
+#endif
+
+#if 0
+#pragma mark == Macros ==
+#endif
+
+//===========================================================================================================================
+//     Macros
+//===========================================================================================================================
+
+#define DebugIsPrint( C )              ( ( ( C ) >= 0x20 ) && ( ( C ) <= 0x7E ) )
+
+#if 0
+#pragma mark == Prototypes ==
+#endif
+
+//===========================================================================================================================
+//     Prototypes
+//===========================================================================================================================
+
+static OSStatus        DebugPrint( DebugLevel inLevel, char *inData, size_t inSize );
+
+// fprintf
+
+#if( DEBUG_FPRINTF_ENABLED )
+       static OSStatus DebugFPrintFInit( DebugOutputTypeFlags inFlags, const char *inFilename );
+       static void             DebugFPrintFPrint( char *inData, size_t inSize );
+#endif
+
+// iDebug (Mac OS X user and kernel)
+
+#if( DEBUG_IDEBUG_ENABLED )
+       static OSStatus DebugiDebugInit( void );
+       static void             DebugiDebugPrint( char *inData, size_t inSize );
+#endif
+
+// kprintf (Mac OS X Kernel)
+
+#if( DEBUG_KPRINTF_ENABLED )
+       static void     DebugKPrintFPrint( char *inData, size_t inSize );
+#endif
+
+// Mac OS X IOLog (Mac OS X Kernel)
+
+#if( DEBUG_MAC_OS_X_IOLOG_ENABLED )
+       static void     DebugMacOSXIOLogPrint( char *inData, size_t inSize );
+#endif
+
+// Mac OS X Log
+
+#if( TARGET_OS_MAC )
+       static OSStatus DebugMacOSXLogInit( void );
+       static void             DebugMacOSXLogPrint( char *inData, size_t inSize );
+#endif
+
+// Windows Debugger
+
+#if( TARGET_OS_WIN32 )
+       static void     DebugWindowsDebuggerPrint( char *inData, size_t inSize );
+#endif
+
+// Windows Event Log
+
+#if( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
+       static OSStatus DebugWindowsEventLogInit( const char *inName, HMODULE inModule );
+       static void     DebugWindowsEventLogPrint( DebugLevel inLevel, char *inData, size_t inSize );
+#endif
+
+// DebugLib support
+
+#if( DEBUG_CORE_SERVICE_ASSERTS_ENABLED )
+       static pascal void      
+               DebugAssertOutputHandler( 
+                       OSType                          inComponentSignature, 
+                       UInt32                          inOptions, 
+                       const char *            inAssertionString, 
+                       const char *            inExceptionString, 
+                       const char *            inErrorString, 
+                       const char *            inFileName, 
+                       long                            inLineNumber, 
+                       void *                          inValue, 
+                       ConstStr255Param        inOutputMsg );
+#endif
+
+// Utilities
+
+static char *  DebugNumVersionToString( uint32_t inVersion, char *inString );
+
+#if( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
+       static void     DebugWinEnableConsole( void );
+#endif
+
+#if( TARGET_OS_WIN32 )
+       static TCHAR *
+               DebugWinCharToTCharString( 
+                       const char *    inCharString, 
+                       size_t                  inCharCount, 
+                       TCHAR *                 outTCharString, 
+                       size_t                  inTCharCountMax, 
+                       size_t *                outTCharCount );
+#endif
+
+#if 0
+#pragma mark == Globals ==
+#endif
+
+//===========================================================================================================================
+//     Private Globals
+//===========================================================================================================================
+
+#if( TARGET_OS_VXWORKS )
+       // TCP States for inetstatShow.
+
+       extern char **  pTcpstates;             // defined in tcpLib.c
+
+       const char *            kDebugTCPStates[] =
+       {
+               "(0)  TCPS_CLOSED", 
+               "(1)  TCPS_LISTEN", 
+               "(2)  TCPS_SYN_SENT", 
+               "(3)  TCPS_SYN_RECEIVED", 
+               "(4)  TCPS_ESTABLISHED", 
+               "(5)  TCPS_CLOSE_WAIT", 
+               "(6)  TCPS_FIN_WAIT_1", 
+               "(7)  TCPS_CLOSING", 
+               "(8)  TCPS_LAST_ACK", 
+               "(9)  TCPS_FIN_WAIT_2", 
+               "(10) TCPS_TIME_WAIT",
+       };
+#endif
+
+// General
+
+static bool                                                                    gDebugInitialized                               = false;
+static DebugOutputType                                         gDebugOutputType                                = kDebugOutputTypeNone;
+static DebugLevel                                                      gDebugPrintLevelMin                             = kDebugLevelInfo;
+static DebugLevel                                                      gDebugPrintLevelMax                             = kDebugLevelMax;
+static DebugLevel                                                      gDebugBreakLevel                                = kDebugLevelAssert;
+#if( DEBUG_CORE_SERVICE_ASSERTS_ENABLED )
+       static DebugAssertOutputHandlerUPP              gDebugAssertOutputHandlerUPP    = NULL;
+#endif
+
+// Custom
+
+static DebugOutputFunctionPtr                          gDebugCustomOutputFunction              = NULL;
+static void *                                                          gDebugCustomOutputContext               = NULL;
+
+// fprintf
+
+#if( DEBUG_FPRINTF_ENABLED )
+       static FILE *                                                   gDebugFPrintFFile                               = NULL;
+#endif
+
+// MacOSXLog
+
+#if( TARGET_OS_MAC )
+       typedef int     ( *DebugMacOSXLogFunctionPtr )( const char *inFormat, ... );
+       
+       static DebugMacOSXLogFunctionPtr                gDebugMacOSXLogFunction                 = NULL;
+#endif
+
+// WindowsEventLog
+
+
+#if( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
+       static HANDLE                                                   gDebugWindowsEventLogEventSource = NULL;
+#endif
+
+#if 0
+#pragma mark -
+#pragma mark == General ==
+#endif
+
+//===========================================================================================================================
+//     DebugInitialize
+//===========================================================================================================================
+
+DEBUG_EXPORT OSStatus  DebugInitialize( DebugOutputType inType, ... )
+{
+       OSStatus                        err;
+       DebugOutputType         type;
+       va_list                         args;
+       
+       va_start( args, inType );
+
+#if( TARGET_OS_VXWORKS )
+       // Set up the TCP state strings if they are not already set up by VxWorks (normally not set up for some reason).
+       
+       if( !pTcpstates )
+       {
+               pTcpstates = (char **) kDebugTCPStates;
+       }
+#endif
+       
+       // Set up DebugLib stuff (if building with Debugging.h).
+       
+#if( DEBUG_CORE_SERVICE_ASSERTS_ENABLED )
+       if( !gDebugAssertOutputHandlerUPP )
+       {
+               gDebugAssertOutputHandlerUPP = NewDebugAssertOutputHandlerUPP( DebugAssertOutputHandler );
+               check( gDebugAssertOutputHandlerUPP );
+               if( gDebugAssertOutputHandlerUPP )
+               {
+                       InstallDebugAssertOutputHandler( gDebugAssertOutputHandlerUPP );
+               }
+       }
+#endif
+       
+       // Pre-process meta-output kind to pick an appropriate output kind for the platform.
+       
+       type = inType;
+       if( type == kDebugOutputTypeMetaConsole )
+       {
+               #if( TARGET_OS_MAC )
+                       type = kDebugOutputTypeMacOSXLog;
+               #elif( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
+                       #if( DEBUG_FPRINTF_ENABLED )
+                               type = kDebugOutputTypeFPrintF;
+                       #else
+                               type = kDebugOutputTypeWindowsDebugger;
+                       #endif
+               #elif( TARGET_API_MAC_OSX_KERNEL )
+                       #if( DEBUG_MAC_OS_X_IOLOG_ENABLED )
+                               type = kDebugOutputTypeMacOSXIOLog;
+                       #elif( DEBUG_IDEBUG_ENABLED )
+                               type = kDebugOutputTypeiDebug;
+                       #elif( DEBUG_KPRINTF_ENABLED )
+                               type = kDebugOutputTypeKPrintF;
+                       #endif
+               #elif( TARGET_OS_VXWORKS )
+                       #if( DEBUG_FPRINTF_ENABLED )
+                               type = kDebugOutputTypeFPrintF;
+                       #else
+                               #error target is VxWorks, but fprintf output is disabled
+                       #endif
+               #else
+                       #if( DEBUG_FPRINTF_ENABLED )
+                               type = kDebugOutputTypeFPrintF;
+                       #endif
+               #endif
+       }
+       
+       // Process output kind.
+       
+       gDebugOutputType = type;
+       switch( type )
+       {
+               case kDebugOutputTypeNone:
+                       err = kNoErr;
+                       break;
+
+               case kDebugOutputTypeCustom:
+                       gDebugCustomOutputFunction = va_arg( args, DebugOutputFunctionPtr );
+                       gDebugCustomOutputContext  = va_arg( args, void * );
+                       err = kNoErr;
+                       break;
+
+#if( DEBUG_FPRINTF_ENABLED )
+               case kDebugOutputTypeFPrintF:
+                       if( inType == kDebugOutputTypeMetaConsole )
+                       {
+                               err = DebugFPrintFInit( kDebugOutputTypeFlagsStdErr, NULL );
+                       }
+                       else
+                       {
+                               DebugOutputTypeFlags            flags;
+                               const char *                            filename;
+                               
+                               flags = (DebugOutputTypeFlags) va_arg( args, unsigned int );
+                               if( ( flags & kDebugOutputTypeFlagsTypeMask ) == kDebugOutputTypeFlagsFile )
+                               {
+                                       filename = va_arg( args, const char * );
+                               }
+                               else
+                               {
+                                       filename = NULL;
+                               }
+                               err = DebugFPrintFInit( flags, filename );
+                       }
+                       break;
+#endif
+
+#if( DEBUG_IDEBUG_ENABLED )
+               case kDebugOutputTypeiDebug:
+                       err = DebugiDebugInit();
+                       break;
+#endif
+
+#if( DEBUG_KPRINTF_ENABLED )
+               case kDebugOutputTypeKPrintF:
+                       err = kNoErr;
+                       break;
+#endif
+
+#if( DEBUG_MAC_OS_X_IOLOG_ENABLED )
+               case kDebugOutputTypeMacOSXIOLog:
+                       err = kNoErr;
+                       break;
+#endif
+
+#if( TARGET_OS_MAC )
+               case kDebugOutputTypeMacOSXLog:
+                       err = DebugMacOSXLogInit();
+                       break;
+#endif
+
+#if( TARGET_OS_WIN32 )
+               case kDebugOutputTypeWindowsDebugger:
+                       err = kNoErr;
+                       break;
+#endif
+
+#if( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
+               case kDebugOutputTypeWindowsEventLog:
+               {
+                       const char *            name;
+                       HMODULE                         module;
+                       
+                       name   = va_arg( args, const char * );
+                       module = va_arg( args, HMODULE );
+                       err = DebugWindowsEventLogInit( name, module );
+               }
+               break;
+#endif
+
+               default:
+                       err = kParamErr;
+                       goto exit;
+       }
+       gDebugInitialized = true;
+       
+exit:
+       va_end( args );
+       return( err );
+}
+
+//===========================================================================================================================
+//     DebugFinalize
+//===========================================================================================================================
+
+DEBUG_EXPORT void              DebugFinalize( void )
+{
+#if( DEBUG_CORE_SERVICE_ASSERTS_ENABLED )
+       check( gDebugAssertOutputHandlerUPP );
+       if( gDebugAssertOutputHandlerUPP )
+       {
+               InstallDebugAssertOutputHandler( NULL );
+               DisposeDebugAssertOutputHandlerUPP( gDebugAssertOutputHandlerUPP );
+               gDebugAssertOutputHandlerUPP = NULL;
+       }
+#endif
+}
+
+//===========================================================================================================================
+//     DebugGetProperty
+//===========================================================================================================================
+
+DEBUG_EXPORT OSStatus  DebugGetProperty( DebugPropertyTag inTag, ... )
+{
+       OSStatus                        err;
+       va_list                         args;
+       DebugLevel *            level;
+       
+       va_start( args, inTag );
+       switch( inTag )
+       {
+               case kDebugPropertyTagPrintLevelMin:
+                       level  = va_arg( args, DebugLevel * );
+                       *level = gDebugPrintLevelMin;
+                       err = kNoErr;
+                       break;
+               
+               case kDebugPropertyTagPrintLevelMax:
+                       level  = va_arg( args, DebugLevel * );
+                       *level = gDebugPrintLevelMax;
+                       err = kNoErr;
+                       break;
+               
+               case kDebugPropertyTagBreakLevel:
+                       level  = va_arg( args, DebugLevel * );
+                       *level = gDebugBreakLevel;
+                       err = kNoErr;
+                       break;          
+               
+               default:
+                       err = kUnsupportedErr;
+                       break;
+       }
+       va_end( args );
+       return( err );
+}
+
+//===========================================================================================================================
+//     DebugSetProperty
+//===========================================================================================================================
+
+DEBUG_EXPORT OSStatus  DebugSetProperty( DebugPropertyTag inTag, ... )
+{
+       OSStatus                err;
+       va_list                 args;
+       DebugLevel              level;
+       
+       va_start( args, inTag );
+       switch( inTag )
+       {
+               case kDebugPropertyTagPrintLevelMin:
+                       level  = va_arg( args, DebugLevel );
+                       gDebugPrintLevelMin = level;
+                       err = kNoErr;
+                       break;
+               
+               case kDebugPropertyTagPrintLevelMax:
+                       level  = va_arg( args, DebugLevel );
+                       gDebugPrintLevelMax = level;
+                       err = kNoErr;
+                       break;
+               
+               case kDebugPropertyTagBreakLevel:
+                       level  = va_arg( args, DebugLevel );
+                       gDebugBreakLevel = level;
+                       err = kNoErr;
+                       break;          
+               
+               default:
+                       err = kUnsupportedErr;
+                       break;
+       }
+       va_end( args );
+       return( err );
+}
+
+#if 0
+#pragma mark -
+#pragma mark == Output ==
+#endif
+
+//===========================================================================================================================
+//     DebugPrintF
+//===========================================================================================================================
+
+DEBUG_EXPORT size_t    DebugPrintF( DebugLevel inLevel, const char *inFormat, ... )
+{      
+       va_list         args;
+       size_t          n;
+       
+       // Skip if the level is not in the enabled range..
+       
+       if( ( inLevel < gDebugPrintLevelMin ) || ( inLevel > gDebugPrintLevelMax ) )
+       {
+               n = 0;
+               goto exit;
+       }
+       
+       va_start( args, inFormat );
+       n = DebugPrintFVAList( inLevel, inFormat, args );
+       va_end( args );
+
+exit:
+       return( n );
+}
+
+//===========================================================================================================================
+//     DebugPrintFVAList
+//===========================================================================================================================
+
+DEBUG_EXPORT size_t    DebugPrintFVAList( DebugLevel inLevel, const char *inFormat, va_list inArgs )
+{
+       size_t          n;
+       char            buffer[ 512 ];
+       
+       // Skip if the level is not in the enabled range..
+       
+       if( ( inLevel < gDebugPrintLevelMin ) || ( inLevel > gDebugPrintLevelMax ) )
+       {
+               n = 0;
+               goto exit;
+       }
+       
+       n = DebugSNPrintFVAList( buffer, sizeof( buffer ), inFormat, inArgs );
+       DebugPrint( inLevel, buffer, (size_t) n );
+
+exit:
+       return( n );
+}
+
+//===========================================================================================================================
+//     DebugPrint
+//===========================================================================================================================
+
+static OSStatus        DebugPrint( DebugLevel inLevel, char *inData, size_t inSize )
+{
+       OSStatus                err;
+       
+       // Skip if the level is not in the enabled range..
+       
+       if( ( inLevel < gDebugPrintLevelMin ) || ( inLevel > gDebugPrintLevelMax ) )
+       {
+               err = kRangeErr;
+               goto exit;
+       }
+       
+       // Printing is not safe at interrupt time so check for this and warn with an interrupt safe mechanism (if available).
+       
+       if( DebugTaskLevel() & kDebugInterruptLevelMask )
+       {
+               #if( TARGET_OS_VXWORKS )
+                       logMsg( "\ncannot print at interrupt time\n\n", 1, 2, 3, 4, 5, 6 );
+               #endif
+               
+               err = kExecutionStateErr;
+               goto exit;
+       }
+       
+       // Initialize the debugging library if it hasn't already been initialized (allows for zero-config usage).
+       
+       if( !gDebugInitialized )
+       {
+               debug_initialize( kDebugOutputTypeMetaConsole );
+       }
+       
+       // Print based on the current output type.
+       
+       switch( gDebugOutputType )
+       {
+               case kDebugOutputTypeNone:
+                       break;
+               
+               case kDebugOutputTypeCustom:
+                       if( gDebugCustomOutputFunction )
+                       {
+                               gDebugCustomOutputFunction( inData, inSize, gDebugCustomOutputContext );
+                       }
+                       break;
+
+#if( DEBUG_FPRINTF_ENABLED )
+               case kDebugOutputTypeFPrintF:
+                       DebugFPrintFPrint( inData, inSize );
+                       break;
+#endif
+
+#if( DEBUG_IDEBUG_ENABLED )
+               case kDebugOutputTypeiDebug:
+                       DebugiDebugPrint( inData, inSize );
+                       break;
+#endif
+
+#if( DEBUG_KPRINTF_ENABLED )
+               case kDebugOutputTypeKPrintF:
+                       DebugKPrintFPrint( inData, inSize );
+                       break;
+#endif
+
+#if( DEBUG_MAC_OS_X_IOLOG_ENABLED )
+               case kDebugOutputTypeMacOSXIOLog:
+                       DebugMacOSXIOLogPrint( inData, inSize );
+                       break;
+#endif
+
+#if( TARGET_OS_MAC )
+               case kDebugOutputTypeMacOSXLog:
+                       DebugMacOSXLogPrint( inData, inSize );
+                       break;
+#endif
+
+#if( TARGET_OS_WIN32 )
+               case kDebugOutputTypeWindowsDebugger:
+                       DebugWindowsDebuggerPrint( inData, inSize );
+                       break;
+#endif
+
+#if( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
+               case kDebugOutputTypeWindowsEventLog:
+                       DebugWindowsEventLogPrint( inLevel, inData, inSize );
+                       break;
+#endif
+
+               default:
+                       break;
+       }
+       err = kNoErr;
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     DebugPrintAssert
+//
+//     Warning: This routine relies on several of the strings being string constants that will exist forever because the
+//           underlying logMsg API that does the printing is asynchronous so it cannot use temporary/stack-based 
+//           pointer variables (e.g. local strings). The debug macros that invoke this function only use constant 
+//           constant strings, but if this function is invoked directly from other places, it must use constant strings.
+//===========================================================================================================================
+
+DEBUG_EXPORT void
+       DebugPrintAssert( 
+               int_least32_t   inErrorCode, 
+               const char *    inAssertString, 
+               const char *    inMessage, 
+               const char *    inFilename, 
+               int_least32_t   inLineNumber, 
+               const char *    inFunction )
+{
+       // Skip if the level is not in the enabled range..
+       
+       if( ( kDebugLevelAssert < gDebugPrintLevelMin ) || ( kDebugLevelAssert > gDebugPrintLevelMax ) )
+       {
+               return;
+       }
+       
+       if( inErrorCode != 0 )
+       {
+               DebugPrintF( 
+                       kDebugLevelAssert, 
+                       "\n"
+                       "[ASSERT] error:  %ld (%m)\n"
+                       "[ASSERT] where:  \"%s\", line %ld, \"%s\"\n"
+                       "\n", 
+                       inErrorCode, inErrorCode, 
+                       inFilename ? inFilename : "", 
+                       inLineNumber, 
+                       inFunction ? inFunction : "" );
+       }
+       else
+       {
+               DebugPrintF( 
+                       kDebugLevelAssert, 
+                       "\n"
+                       "[ASSERT] assert: \"%s\" %s\n"
+                       "[ASSERT] where:  \"%s\", line %ld, \"%s\"\n"
+                       "\n", 
+                       inAssertString ? inAssertString : "", 
+                       inMessage ? inMessage : "", 
+                       inFilename ? inFilename : "", 
+                       inLineNumber, 
+                       inFunction ? inFunction : "" );
+       }
+       
+       // Break into the debugger if enabled.
+       
+       #if( TARGET_OS_WIN32 )
+               if( gDebugBreakLevel <= kDebugLevelAssert )
+               {
+                       if( IsDebuggerPresent() )
+                       {
+                               DebugBreak();
+                       }
+               }
+       #endif
+}
+
+#if 0
+#pragma mark -
+#endif
+
+#if( DEBUG_FPRINTF_ENABLED )
+//===========================================================================================================================
+//     DebugFPrintFInit
+//===========================================================================================================================
+
+static OSStatus        DebugFPrintFInit( DebugOutputTypeFlags inFlags, const char *inFilename )
+{
+       OSStatus                                        err;
+       DebugOutputTypeFlags            typeFlags;
+       
+       typeFlags = inFlags & kDebugOutputTypeFlagsTypeMask;
+       if( typeFlags == kDebugOutputTypeFlagsStdOut )
+       {
+               #if( TARGET_OS_WIN32 )
+                       DebugWinEnableConsole();
+               #endif
+
+               gDebugFPrintFFile = stdout;
+       }
+       else if( typeFlags == kDebugOutputTypeFlagsStdErr )
+       {
+               #if( TARGET_OS_WIN32 )
+                       DebugWinEnableConsole();
+               #endif
+               
+               gDebugFPrintFFile = stdout;
+       }
+       else if( typeFlags == kDebugOutputTypeFlagsFile )
+       {
+               require_action_quiet( inFilename && ( *inFilename != '\0' ), exit, err = kOpenErr );
+               
+               gDebugFPrintFFile = fopen( inFilename, "a" );
+               require_action_quiet( gDebugFPrintFFile, exit, err = kOpenErr );
+       }
+       else
+       {
+               err = kParamErr;
+               goto exit;
+       }
+       err = kNoErr;
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     DebugFPrintFPrint
+//===========================================================================================================================
+
+static void    DebugFPrintFPrint( char *inData, size_t inSize )
+{
+       char *          p;
+       char *          q;
+       
+       // Convert \r to \n. fprintf will interpret \n and convert to whatever is appropriate for the platform.
+       
+       p = inData;
+       q = p + inSize;
+       while( p < q )
+       {
+               if( *p == '\r' )
+               {
+                       *p = '\n';
+               }
+               ++p;
+       }
+       
+       // Write the data and flush.
+       
+       if( gDebugFPrintFFile )
+       {
+               fprintf( gDebugFPrintFFile, "%.*s", (int) inSize, inData );
+               fflush( gDebugFPrintFFile );
+       }
+}
+#endif // DEBUG_FPRINTF_ENABLED
+
+#if( DEBUG_IDEBUG_ENABLED )
+//===========================================================================================================================
+//     DebugiDebugInit
+//===========================================================================================================================
+
+static OSStatus        DebugiDebugInit( void )
+{
+       OSStatus                err;
+       
+       #if( TARGET_API_MAC_OSX_KERNEL )
+               
+               extern uint32_t *               _giDebugReserved1;
+               
+               // Emulate the iDebugSetOutputType macro in iDebugServices.h.
+               // Note: This is not thread safe, but neither is iDebugServices.h nor iDebugKext.
+               
+               if( !_giDebugReserved1 )
+               {
+                       _giDebugReserved1 = (uint32_t *) IOMalloc( sizeof( uint32_t ) );
+                       require_action_quiet( _giDebugReserved1, exit, err = kNoMemoryErr );
+               }
+               *_giDebugReserved1 = 0x00010000U;
+               err = kNoErr;
+exit:
+       #else
+               
+               __private_extern__ void iDebugSetOutputTypeInternal( uint32_t inType );
+               
+               iDebugSetOutputTypeInternal( 0x00010000U );
+               err = kNoErr;
+               
+       #endif
+       
+       return( err );
+}
+
+//===========================================================================================================================
+//     DebugiDebugPrint
+//===========================================================================================================================
+
+static void    DebugiDebugPrint( char *inData, size_t inSize )
+{
+       #if( TARGET_API_MAC_OSX_KERNEL )
+               
+               // Locally declared here so we do not need to include iDebugKext.h.
+               // Note: IOKit uses a global namespace for all code and only a partial link occurs at build time. When the 
+               // KEXT is loaded, the runtime linker will link in this extern'd symbol (assuming iDebug is present).
+               // _giDebugLogInternal is actually part of IOKit proper so this should link even if iDebug is not present.
+               
+               typedef void ( *iDebugLogFunctionPtr )( uint32_t inLevel, uint32_t inTag, const char *inFormat, ... );
+               
+               extern iDebugLogFunctionPtr             _giDebugLogInternal;
+               
+               if( _giDebugLogInternal )
+               {
+                       _giDebugLogInternal( 0, 0, "%.*s", (int) inSize, inData );
+               }
+               
+       #else
+       
+               __private_extern__ void iDebugLogInternal( uint32_t inLevel, uint32_t inTag, const char *inFormat, ... );
+               
+               iDebugLogInternal( 0, 0, "%.*s", (int) inSize, inData );
+       
+       #endif
+}
+#endif
+
+#if( DEBUG_KPRINTF_ENABLED )
+//===========================================================================================================================
+//     DebugKPrintFPrint
+//===========================================================================================================================
+
+static void    DebugKPrintFPrint( char *inData, size_t inSize )
+{
+       extern void     kprintf( const char *inFormat, ... );
+       
+       kprintf( "%.*s", (int) inSize, inData );
+}
+#endif
+
+#if( DEBUG_MAC_OS_X_IOLOG_ENABLED )
+//===========================================================================================================================
+//     DebugMacOSXIOLogPrint
+//===========================================================================================================================
+
+static void    DebugMacOSXIOLogPrint( char *inData, size_t inSize )
+{
+       extern void     IOLog( const char *inFormat, ... );
+       
+       IOLog( "%.*s", (int) inSize, inData );
+}
+#endif
+
+#if( TARGET_OS_MAC )
+//===========================================================================================================================
+//     DebugMacOSXLogInit
+//===========================================================================================================================
+
+static OSStatus        DebugMacOSXLogInit( void )
+{
+       OSStatus                err;
+       CFStringRef             path;
+       CFURLRef                url;
+       CFBundleRef             bundle;
+       CFStringRef             functionName;
+       void *                  functionPtr;
+       
+       bundle = NULL;
+       
+       // Create a bundle reference for System.framework.
+       
+       path = CFSTR( "/System/Library/Frameworks/System.framework" );
+       url = CFURLCreateWithFileSystemPath( NULL, path, kCFURLPOSIXPathStyle, true );
+       require_action_quiet( url, exit, err = memFullErr );
+       
+       bundle = CFBundleCreate( NULL, url );
+       CFRelease( url );
+       require_action_quiet( bundle, exit, err = memFullErr );
+       
+       // Get a ptr to the system's "printf" function from System.framework.
+       
+       functionName = CFSTR( "printf" );
+       functionPtr = CFBundleGetFunctionPointerForName( bundle, functionName );
+       require_action_quiet( functionPtr, exit, err = memFullErr );    
+       
+       // Success! Note: The bundle cannot be released because it would invalidate the function ptr.
+       
+       gDebugMacOSXLogFunction = (DebugMacOSXLogFunctionPtr) functionPtr;
+       bundle = NULL;
+       err = noErr;
+       
+exit:
+       if( bundle )
+       {
+               CFRelease( bundle );
+       }
+       return( err );
+}
+
+//===========================================================================================================================
+//     DebugMacOSXLogPrint
+//===========================================================================================================================
+
+static void    DebugMacOSXLogPrint( char *inData, size_t inSize )
+{      
+       if( gDebugMacOSXLogFunction )
+       {
+               gDebugMacOSXLogFunction( "%.*s", (int) inSize, inData );
+       }
+}
+#endif
+
+#if( TARGET_OS_WIN32 )
+//===========================================================================================================================
+//     DebugWindowsDebuggerPrint
+//===========================================================================================================================
+
+void   DebugWindowsDebuggerPrint( char *inData, size_t inSize )
+{
+       TCHAR                           buffer[ 512 ];
+       const char *            src;
+       const char *            end;
+       TCHAR *                         dst;
+       char                            c;
+       
+       // Copy locally and null terminate the string. This also converts from char to TCHAR in case we are 
+       // building with UNICODE enabled since the input is always char. Also convert \r to \n in the process.
+
+       src = inData;
+       if( inSize >= sizeof_array( buffer ) )
+       {
+               inSize = sizeof_array( buffer ) - 1;
+       }
+       end = src + inSize;
+       dst = buffer;   
+       while( src < end )
+       {
+               c = *src++;
+               if( c == '\r' )
+               {
+                       c = '\n';
+               }
+               *dst++ = (TCHAR) c;
+       }
+       *dst = 0;
+       
+       // Print out the string to the debugger.
+       
+       OutputDebugString( buffer );
+}
+#endif
+
+#if( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
+//===========================================================================================================================
+//     DebugWindowsEventLogInit
+//===========================================================================================================================
+
+static OSStatus        DebugWindowsEventLogInit( const char *inName, HMODULE inModule )
+{
+       OSStatus                        err;
+       HKEY                            key;
+       TCHAR                           name[ 128 ];
+       const char *            src;
+       TCHAR                           path[ MAX_PATH ];
+       size_t                          size;
+       DWORD                           typesSupported;
+       DWORD                           n;
+       
+       key = NULL;
+
+       // Use a default name if needed then convert the name to TCHARs so it works on ANSI or Unicode builds.
+
+       if( !inName || ( *inName == '\0' ) )
+       {
+               inName = "DefaultApp";
+       }
+       DebugWinCharToTCharString( inName, kSizeCString, name, sizeof( name ), NULL );
+       
+       // Build the path string using the fixed registry path and app name.
+       
+       src = "SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\";
+       DebugWinCharToTCharString( src, kSizeCString, path, sizeof_array( path ), &size );
+       DebugWinCharToTCharString( inName, kSizeCString, path + size, sizeof_array( path ) - size, NULL );
+       
+       // Add/Open the source name as a sub-key under the Application key in the EventLog registry key.
+       
+       err = RegCreateKeyEx( HKEY_LOCAL_MACHINE, path, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &key, NULL );
+       require_noerr_quiet( err, exit );
+       
+       // Set the path in the EventMessageFile subkey. Add 1 to the TCHAR count to include the null terminator.
+       
+       n = GetModuleFileName( inModule, path, sizeof_array( path ) );
+       err = translate_errno( n > 0, (OSStatus) GetLastError(), kParamErr );
+       require_noerr_quiet( err, exit );
+       n += 1;
+       n *= sizeof( TCHAR );
+       
+       err = RegSetValueEx( key, TEXT( "EventMessageFile" ), 0, REG_EXPAND_SZ, (const LPBYTE) path, n );
+       require_noerr_quiet( err, exit );
+       
+       // Set the supported event types in the TypesSupported subkey.
+       
+       typesSupported = EVENTLOG_SUCCESS | EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE |
+                                        EVENTLOG_AUDIT_SUCCESS | EVENTLOG_AUDIT_FAILURE;
+       err = RegSetValueEx( key, TEXT( "TypesSupported" ), 0, REG_DWORD, (const LPBYTE) &typesSupported, sizeof( DWORD ) );
+       require_noerr_quiet( err, exit );
+       
+       // Set up the event source.
+       
+       gDebugWindowsEventLogEventSource = RegisterEventSource( NULL, name );
+       err = translate_errno( gDebugWindowsEventLogEventSource, (OSStatus) GetLastError(), kParamErr );
+       require_noerr_quiet( err, exit );
+       
+exit:
+       if( key )
+       {
+               RegCloseKey( key );
+       }
+       return( err );
+}
+
+//===========================================================================================================================
+//     DebugWindowsEventLogPrint
+//===========================================================================================================================
+
+static void    DebugWindowsEventLogPrint( DebugLevel inLevel, char *inData, size_t inSize )
+{
+       WORD                            type;
+       TCHAR                           buffer[ 512 ];
+       const char *            src;
+       const char *            end;
+       TCHAR *                         dst;
+       char                            c;
+       const TCHAR *           array[ 1 ];
+       
+       // Map the debug level to a Windows EventLog type.
+       
+       if( inLevel <= kDebugLevelNotice )
+       {
+               type = EVENTLOG_INFORMATION_TYPE;
+       }
+       else if( inLevel <= kDebugLevelWarning )
+       {
+               type = EVENTLOG_WARNING_TYPE;
+       }
+       else
+       {
+               type = EVENTLOG_ERROR_TYPE;
+       }
+       
+       // Copy locally and null terminate the string. This also converts from char to TCHAR in case we are 
+       // building with UNICODE enabled since the input is always char. Also convert \r to \n in the process.
+       
+       src = inData;
+       if( inSize >= sizeof_array( buffer ) )
+       {
+               inSize = sizeof_array( buffer ) - 1;
+       }
+       end = src + inSize;
+       dst = buffer;   
+       while( src < end )
+       {
+               c = *src++;
+               if( c == '\r' )
+               {
+                       c = '\n';
+               }
+               *dst++ = (TCHAR) c;
+       }
+       *dst = 0;
+       
+       // Add the the string to the event log.
+       
+       array[ 0 ] = buffer;
+       if( gDebugWindowsEventLogEventSource )
+       {
+               ReportEvent( gDebugWindowsEventLogEventSource, type, 0, 0x20000001L, NULL, 1, 0, array, NULL );
+       }
+}
+#endif // TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE
+
+#if( DEBUG_CORE_SERVICE_ASSERTS_ENABLED )
+//===========================================================================================================================
+//     DebugAssertOutputHandler
+//===========================================================================================================================
+
+static pascal void     
+       DebugAssertOutputHandler( 
+               OSType                          inComponentSignature, 
+               UInt32                          inOptions, 
+               const char *            inAssertString, 
+               const char *            inExceptionString, 
+               const char *            inErrorString, 
+               const char *            inFileName, 
+               long                            inLineNumber, 
+               void *                          inValue, 
+               ConstStr255Param        inOutputMsg )
+{
+       DEBUG_UNUSED( inComponentSignature );
+       DEBUG_UNUSED( inOptions );
+       DEBUG_UNUSED( inExceptionString );
+       DEBUG_UNUSED( inValue );
+       DEBUG_UNUSED( inOutputMsg );
+       
+       DebugPrintAssert( 0, inAssertString, inErrorString, inFileName, (int_least32_t) inLineNumber, "" );
+}
+#endif
+
+#if 0
+#pragma mark -
+#pragma mark == Utilities ==
+#endif
+
+//===========================================================================================================================
+//     DebugSNPrintF
+//
+//     Stolen from mDNS.c's mDNS_snprintf/mDNS_vsnprintf with the following changes:
+//
+//     Changed names to avoid name collisions with the mDNS versions.
+//     Changed types to standard C types since mDNSClientAPI.h may not be available.
+//     Conditionalized mDNS stuff so it can be used with or with mDNSClientAPI.h.
+//     Added 64-bit support for %d (%lld), %i (%lli), %u (%llu), %o (%llo), %x (%llx), and %b (%llb).
+//     Added %@   - Cocoa/CoreFoundation object. Param is the object. Strings are used directly. Others use CFCopyDescription.
+//     Added %.8a - FIbre Channel address. Arg=ptr to address.
+//     Added %##a - IPv4 (if AF_INET defined) or IPv6 (if AF_INET6 defined) sockaddr. Arg=ptr to sockaddr.
+//     Added %b   - Binary representation of integer (e.g. 01101011). Modifiers and arg=the same as %d, %x, etc.
+//     Added %C   - Mac-style FourCharCode (e.g. 'APPL'). Arg=32-bit value to print as a Mac-style FourCharCode.
+//     Added %H   - Hex Dump (e.g. "\x6b\xa7" -> "6B A7"). 1st arg=ptr, 2nd arg=size, 3rd arg=max size.
+//     Added %#H  - Hex Dump & ASCII (e.g. "\x41\x62" -> "6B A7 'Ab'"). 1st arg=ptr, 2nd arg=size, 3rd arg=max size.
+//     Added %m   - Error Message (e.g. 0 -> "kNoErr"). Modifiers and error code args are the same as %d, %x, etc.
+//     Added %S   - UTF-16 string. Host order if no BOM. Precision is UTF-16 char count. BOM counts in any precision. Arg=ptr.
+//     Added %#S  - Big Endian UTF-16 string (unless BOM overrides). Otherwise the same as %S.
+//     Added %##S - Little Endian UTF-16 string (unless BOM overrides). Otherwise the same as %S.
+//     Added %U   - Universally Unique Identifier (UUID) (e.g. 6ba7b810-9dad-11d1-80b4-00c04fd430c8). Arg=ptr to 16-byte UUID.
+//===========================================================================================================================
+
+DEBUG_EXPORT size_t DebugSNPrintF(char *sbuffer, size_t buflen, const char *fmt, ...)
+       {
+       size_t length;
+       
+       va_list ptr;
+       va_start(ptr,fmt);
+       length = DebugSNPrintFVAList(sbuffer, buflen, fmt, ptr);
+       va_end(ptr);
+       
+       return(length);
+       }
+
+//===========================================================================================================================
+//     DebugSNPrintFVAList     - va_list version of DebugSNPrintF. See DebugSNPrintF for more info.
+//===========================================================================================================================
+
+DEBUG_EXPORT size_t DebugSNPrintFVAList(char *sbuffer, size_t buflen, const char *fmt, va_list arg)
+       {
+       static const struct DebugSNPrintF_format
+               {
+               unsigned      leftJustify : 1;
+               unsigned      forceSign : 1;
+               unsigned      zeroPad : 1;
+               unsigned      havePrecision : 1;
+               unsigned      hSize : 1;
+               char          lSize;
+               char          altForm;
+               char          sign;             // +, - or space
+               unsigned int  fieldWidth;
+               unsigned int  precision;
+               } DebugSNPrintF_format_default = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+
+       size_t nwritten = 0;
+       int c;
+       if (buflen == 0) return(0);
+       buflen--;               // Pre-reserve one space in the buffer for the terminating nul
+       if (buflen == 0) goto exit;
+       
+       for (c = *fmt; c != 0; c = *++fmt)
+               {
+               if (c != '%')
+                       {
+                       *sbuffer++ = (char)c;
+                       if (++nwritten >= buflen) goto exit;
+                       }
+               else
+                       {
+                       size_t i=0, j;
+                       // The mDNS Vsprintf Argument Conversion Buffer is used as a temporary holding area for
+                       // generating decimal numbers, hexdecimal numbers, IP addresses, domain name strings, etc.
+                       // The size needs to be enough for a 256-byte domain name plus some error text.
+                       #define mDNS_VACB_Size 300
+                       char mDNS_VACB[mDNS_VACB_Size];
+                       #define mDNS_VACB_Lim (&mDNS_VACB[mDNS_VACB_Size])
+                       #define mDNS_VACB_Remain(s) ((size_t)(mDNS_VACB_Lim - s))
+                       char *s = mDNS_VACB_Lim;
+                       const char *digits = "0123456789ABCDEF";
+                       struct DebugSNPrintF_format F = DebugSNPrintF_format_default;
+       
+                       for(;;) //  decode flags
+                               {
+                               c = *++fmt;
+                               if      (c == '-') F.leftJustify = 1;
+                               else if (c == '+') F.forceSign = 1;
+                               else if (c == ' ') F.sign = ' ';
+                               else if (c == '#') F.altForm++;
+                               else if (c == '0') F.zeroPad = 1;
+                               else break;
+                               }
+       
+                       if (c == '*')   //  decode field width
+                               {
+                               int f = va_arg(arg, int);
+                               if (f < 0) { f = -f; F.leftJustify = 1; }
+                               F.fieldWidth = (unsigned int)f;
+                               c = *++fmt;
+                               }
+                       else
+                               {
+                               for (; c >= '0' && c <= '9'; c = *++fmt)
+                                       F.fieldWidth = (10 * F.fieldWidth) + (c - '0');
+                               }
+       
+                       if (c == '.')   //  decode precision
+                               {
+                               if ((c = *++fmt) == '*')
+                                       { F.precision = va_arg(arg, unsigned int); c = *++fmt; }
+                               else for (; c >= '0' && c <= '9'; c = *++fmt)
+                                               F.precision = (10 * F.precision) + (c - '0');
+                               F.havePrecision = 1;
+                               }
+       
+                       if (F.leftJustify) F.zeroPad = 0;
+       
+                       conv:
+                       switch (c)      //  perform appropriate conversion
+                               {
+                               #if TYPE_LONGLONG_NATIVE
+                                       unsigned_long_long_compat n;
+                                       unsigned_long_long_compat base;
+                               #else
+                                       unsigned long n;
+                                       unsigned long base;
+                               #endif
+                               case 'h' :      F.hSize = 1; c = *++fmt; goto conv;
+                               case 'l' :      // fall through
+                               case 'L' :      F.lSize++; c = *++fmt; goto conv;
+                               case 'd' :
+                               case 'i' :      base = 10;
+                                                       goto canBeSigned;
+                               case 'u' :      base = 10;
+                                                       goto notSigned;
+                               case 'o' :      base = 8;
+                                                       goto notSigned;
+                               case 'b' :      base = 2;
+                                                       goto notSigned;
+                               case 'p' :      n = va_arg(arg, uintptr_t);
+                                                       F.havePrecision = 1;
+                                                       F.precision = (sizeof(uintptr_t) == 4) ? 8 : 16;
+                                                       F.sign = 0;
+                                                       base = 16;
+                                                       c = 'x';
+                                                       goto number;
+                               case 'x' :      digits = "0123456789abcdef";
+                               case 'X' :      base = 16;
+                                                       goto notSigned;
+                               canBeSigned:
+                                                       #if TYPE_LONGLONG_NATIVE
+                                                               if (F.lSize == 1) n = (unsigned_long_long_compat)va_arg(arg, long);
+                                                               else if (F.lSize == 2) n = (unsigned_long_long_compat)va_arg(arg, long_long_compat);
+                                                               else n = (unsigned_long_long_compat)va_arg(arg, int);
+                                                       #else
+                                                               if (F.lSize == 1) n = (unsigned long)va_arg(arg, long);
+                                                               else if (F.lSize == 2) goto exit;
+                                                               else n = (unsigned long)va_arg(arg, int);
+                                                       #endif
+                                                       if (F.hSize) n = (short) n;
+                                                       #if TYPE_LONGLONG_NATIVE
+                                                               if ((long_long_compat) n < 0) { n = (unsigned_long_long_compat)-(long_long_compat)n; F.sign = '-'; }
+                                                       #else
+                                                               if ((long) n < 0) { n = (unsigned long)-(long)n; F.sign = '-'; }
+                                                       #endif
+                                                       else if (F.forceSign) F.sign = '+';
+                                                       goto number;
+                               
+                               notSigned:      if (F.lSize == 1) n = va_arg(arg, unsigned long);
+                                                       else if (F.lSize == 2)
+                                                               {
+                                                               #if TYPE_LONGLONG_NATIVE
+                                                                       n = va_arg(arg, unsigned_long_long_compat);
+                                                               #else
+                                                                       goto exit;
+                                                               #endif
+                                                               }
+                                                       else n = va_arg(arg, unsigned int);
+                                                       if (F.hSize) n = (unsigned short) n;
+                                                       F.sign = 0;
+                                                       goto number;
+                               
+                               number:         if (!F.havePrecision)
+                                                               {
+                                                               if (F.zeroPad)
+                                                                       {
+                                                                       F.precision = F.fieldWidth;
+                                                                       if (F.altForm) F.precision -= 2;
+                                                                       if (F.sign) --F.precision;
+                                                                       }
+                                                               if (F.precision < 1) F.precision = 1;
+                                                               }
+                                                       if (F.precision > mDNS_VACB_Size - 1)
+                                                               F.precision = mDNS_VACB_Size - 1;
+                                                       for (i = 0; n; n /= base, i++) *--s = (char)(digits[n % base]);
+                                                       for (; i < F.precision; i++) *--s = '0';
+                                                       if (F.altForm) { *--s = (char)c; *--s = '0'; i += 2; }
+                                                       if (F.sign) { *--s = F.sign; i++; }
+                                                       break;
+       
+                               case 'a' :      {
+                                                       unsigned char *a = va_arg(arg, unsigned char *);
+                                                       char pre[4] = "";
+                                                       char post[32] = "";
+                                                       if (!a) { static char emsg[] = "<<NULL>>"; s = emsg; i = sizeof(emsg)-1; }
+                                                       else
+                                                               {
+                                                               s = mDNS_VACB;  // Adjust s to point to the start of the buffer, not the end
+                                                               if (F.altForm == 1)
+                                                                       {
+                                                                       #if(defined(MDNS_DEBUGMSGS))
+                                                                               mDNSAddr *ip = (mDNSAddr*)a;
+                                                                               switch (ip->type)
+                                                                                       {
+                                                                                       case mDNSAddrType_IPv4: F.precision =  4; a = (unsigned char *)&ip->ip.v4; break;
+                                                                                       case mDNSAddrType_IPv6: F.precision = 16; a = (unsigned char *)&ip->ip.v6; break;
+                                                                                       default:                F.precision =  0; break;
+                                                                                       }
+                                                                       #else
+                                                                               F.precision = 0;        // mDNSClientAPI.h not included so no mDNSAddr support
+                                                                       #endif
+                                                                       }
+                                                               else if (F.altForm == 2)
+                                                                       {
+                                                                       #ifdef AF_INET
+                                                                               const struct sockaddr *sa;
+                                                                               unsigned char *port;
+                                                                               sa = (const struct sockaddr*)a;
+                                                                               switch (sa->sa_family)
+                                                                                       {
+                                                                                       case AF_INET:  F.precision =  4; a = (unsigned char*)&((const struct sockaddr_in *)a)->sin_addr;
+                                                                                                      port = (unsigned char*)&((const struct sockaddr_in *)sa)->sin_port;
+                                                                                                      DebugSNPrintF(post, sizeof(post), ":%d", (port[0] << 8) | port[1]); break;
+                                                                                       #ifdef AF_INET6
+                                                                                       case AF_INET6: F.precision = 16; a = (unsigned char*)&((const struct sockaddr_in6 *)a)->sin6_addr; 
+                                                                                                      pre[0] = '['; pre[1] = '\0';
+                                                                                                      port = (unsigned char*)&((const struct sockaddr_in6 *)sa)->sin6_port;
+                                                                                                      DebugSNPrintF(post, sizeof(post), "%%%d]:%d", 
+                                                                                                               (int)((const struct sockaddr_in6 *)sa)->sin6_scope_id,
+                                                                                                               (port[0] << 8) | port[1]); break;
+                                                                                       #endif
+                                                                                       default:       F.precision =  0; break;
+                                                                                       }
+                                                                       #else
+                                                                               F.precision = 0;        // socket interfaces not included so no sockaddr support
+                                                                       #endif
+                                                                       }
+                                                               switch (F.precision)
+                                                                       {
+                                                                       case  4: i = DebugSNPrintF(mDNS_VACB, sizeof(mDNS_VACB), "%d.%d.%d.%d%s",
+                                                                                                               a[0], a[1], a[2], a[3], post); break;
+                                                                       case  6: i = DebugSNPrintF(mDNS_VACB, sizeof(mDNS_VACB), "%02X:%02X:%02X:%02X:%02X:%02X",
+                                                                                                               a[0], a[1], a[2], a[3], a[4], a[5]); break;
+                                                                       case  8: i = DebugSNPrintF(mDNS_VACB, sizeof(mDNS_VACB), "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X",
+                                                                                                               a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7]); break;
+                                                                       case 16: i = DebugSNPrintF(mDNS_VACB, sizeof(mDNS_VACB), 
+                                                                                                               "%s%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X%s",
+                                                                                                               pre, a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], 
+                                                                                                               a[9], a[10], a[11], a[12], a[13], a[14], a[15], post); break;           
+                                                                       default: i = DebugSNPrintF(mDNS_VACB, sizeof(mDNS_VACB), "%s", "<< ERROR: Must specify address size "
+                                                                                                               "(i.e. %.4a=IPv4, %.6a=Ethernet, %.8a=Fibre Channel %.16a=IPv6) >>"); break;
+                                                                       }
+                                                               }
+                                                       }
+                                                       break;
+
+                               case 'U' :      {
+                                                       unsigned char *a = va_arg(arg, unsigned char *);
+                                                       if (!a) { static char emsg[] = "<<NULL>>"; s = emsg; i = sizeof(emsg)-1; }
+                                                       else
+                                                               {
+                                                               s = mDNS_VACB;  // Adjust s to point to the start of the buffer, not the end
+                                                               i = DebugSNPrintF(mDNS_VACB, sizeof(mDNS_VACB), "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+                                                                               *((uint32_t*) &a[0]), *((uint16_t*) &a[4]), *((uint16_t*) &a[6]), 
+                                                                               a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15]); break;
+                                                               }
+                                                       }
+                                                       break;
+
+                               case 'c' :      *--s = (char)va_arg(arg, int); i = 1; break;
+       
+                               case 'C' :      if (F.lSize) n = va_arg(arg, unsigned long);
+                                                       else n = va_arg(arg, unsigned int);
+                                                       if (F.hSize) n = (unsigned short) n;
+                                                       c = (int)( n        & 0xFF); *--s = (char)(DebugIsPrint(c) ? c : '^');
+                                                       c = (int)((n >>  8) & 0xFF); *--s = (char)(DebugIsPrint(c) ? c : '^');
+                                                       c = (int)((n >> 16) & 0xFF); *--s = (char)(DebugIsPrint(c) ? c : '^');
+                                                       c = (int)((n >> 24) & 0xFF); *--s = (char)(DebugIsPrint(c) ? c : '^');
+                                                       i = 4;
+                                                       break;
+       
+                               case 's' :      s = va_arg(arg, char *);
+                                                       if (!s) { static char emsg[] = "<<NULL>>"; s = emsg; i = sizeof(emsg)-1; }
+                                                       else switch (F.altForm)
+                                                               {
+                                                               case 0: i=0;
+                                                                               if (F.havePrecision)                            // C string
+                                                                                       {
+                                                                                       while((i < F.precision) && s[i]) i++;
+                                                                                       // Make sure we don't truncate in the middle of a UTF-8 character.
+                                                                                       // If the last character is part of a multi-byte UTF-8 character, back up to the start of it.
+                                                                                       j=0;
+                                                                                       while((i > 0) && ((c = s[i-1]) & 0x80)) { j++; i--; if((c & 0xC0) != 0x80) break; }
+                                                                                       // If the actual count of UTF-8 characters matches the encoded UTF-8 count, add it back.
+                                                                                       if((j > 1) && (j <= 6))
+                                                                                               {
+                                                                                               int test = (0xFF << (8-j)) & 0xFF;
+                                                                                               int mask = test | (1 << ((8-j)-1));
+                                                                                               if((c & mask) == test) i += j;
+                                                                                               }
+                                                                                       }
+                                                                               else
+                                                                                       while(s[i]) i++;
+                                                                               break;                                                          
+                                                               case 1: i = (unsigned char) *s++; break;        // Pascal string
+                                                               case 2: {                                                                       // DNS label-sequence name
+                                                                               unsigned char *a = (unsigned char *)s;
+                                                                               s = mDNS_VACB;  // Adjust s to point to the start of the buffer, not the end
+                                                                               if (*a == 0) *s++ = '.';        // Special case for root DNS name
+                                                                               while (*a)
+                                                                                       {
+                                                                                       if (*a > 63) { s += DebugSNPrintF(s, mDNS_VACB_Remain(s), "<<INVALID LABEL LENGTH %u>>", *a); break; }
+                                                                                       if (s + *a >= &mDNS_VACB[254]) { s += DebugSNPrintF(s, mDNS_VACB_Remain(s), "<<NAME TOO LONG>>"); break; }
+                                                                                       s += DebugSNPrintF(s, mDNS_VACB_Remain(s), "%#s.", a);
+                                                                                       a += 1 + *a;
+                                                                                       }
+                                                                               i = (size_t)(s - mDNS_VACB);
+                                                                               s = mDNS_VACB;  // Reset s back to the start of the buffer
+                                                                               break;
+                                                                               }
+                                                               }
+                                                       if (F.havePrecision && i > F.precision)         // Make sure we don't truncate in the middle of a UTF-8 character
+                                                               { i = F.precision; while (i>0 && (s[i] & 0xC0) == 0x80) i--; }
+                                                       break;
+                               
+                               case 'S':       {       // UTF-16 string
+                                                       unsigned char *a = va_arg(arg, unsigned char *);
+                                                       uint16_t      *u = (uint16_t*)a;
+                                                       if (!u) { static char emsg[] = "<<NULL>>"; s = emsg; i = sizeof(emsg)-1; }
+                                                       if ((!F.havePrecision || F.precision))
+                                                               {
+                                                               if      ((a[0] == 0xFE) && (a[1] == 0xFF)) { F.altForm = 1; u += 1; a += 2; F.precision--; }    // Big Endian
+                                                               else if ((a[0] == 0xFF) && (a[1] == 0xFE)) { F.altForm = 2; u += 1; a += 2; F.precision--; }    // Little Endian
+                                                               }
+                                                       s = mDNS_VACB;  // Adjust s to point to the start of the buffer, not the end
+                                                       switch (F.altForm)
+                                                               {
+                                                               case 0: while ((!F.havePrecision || (i < F.precision)) && u[i] && mDNS_VACB_Remain(s))  // Host Endian
+                                                                                       { c = u[i]; *s++ = (char)(DebugIsPrint(c) ? c : '^'); i++; }
+                                                                               break;
+                                                               case 1: while ((!F.havePrecision || (i < F.precision)) && u[i] && mDNS_VACB_Remain(s))  // Big Endian
+                                                                                       { c = ((a[0] << 8) | a[1]) & 0xFF; *s++ = (char)(DebugIsPrint(c) ? c : '^'); i++; a += 2; }
+                                                                               break;
+                                                               case 2: while ((!F.havePrecision || (i < F.precision)) && u[i] && mDNS_VACB_Remain(s))  // Little Endian
+                                                                                       { c = ((a[1] << 8) | a[0]) & 0xFF; *s++ = (char)(DebugIsPrint(c) ? c : '^'); i++; a += 2; }
+                                                                               break;
+                                                               }
+                                                       }
+                                                       s = mDNS_VACB;  // Reset s back to the start of the buffer
+                                                       break;
+                       
+                       #if TARGET_OS_MAC
+                               case '@':       {       // Cocoa/CoreFoundation object
+                                                       CFTypeRef cfObj;
+                                                       CFStringRef cfStr;
+                                                       cfObj = (CFTypeRef) va_arg(arg, void *);
+                                                       cfStr = (CFGetTypeID(cfObj) == CFStringGetTypeID()) ? (CFStringRef)CFRetain(cfObj) : CFCopyDescription(cfObj);
+                                                       s = mDNS_VACB;  // Adjust s to point to the start of the buffer, not the end
+                                                       if (cfStr)
+                                                               {
+                                                               CFRange range;
+                                                               CFIndex m;
+                                                               range = CFRangeMake(0, CFStringGetLength(cfStr));
+                                                               m = 0;
+                                                               CFStringGetBytes(cfStr, range, kCFStringEncodingUTF8, '^', false, (UInt8*)mDNS_VACB, (CFIndex)sizeof(mDNS_VACB), &m);
+                                                               CFRelease(cfStr);
+                                                               i = (size_t) m;
+                                                               }
+                                                       else
+                                                               {
+                                                               i = DebugSNPrintF(mDNS_VACB, sizeof(mDNS_VACB), "%s", "ERROR: <invalid CF object>" );
+                                                               }
+                                                       }
+                                                       if (F.havePrecision && i > F.precision)         // Make sure we don't truncate in the middle of a UTF-8 character
+                                                               { i = F.precision; while (i>0 && (s[i] & 0xC0) == 0x80) i--; }
+                                                       break;
+                       #endif
+
+                               case 'm' :      {       // Error Message
+                                                       long err;
+                                                       if (F.lSize) err = va_arg(arg, long);
+                                                       else err = va_arg(arg, int);
+                                                       if (F.hSize) err = (short)err;
+                                                       DebugGetErrorString(err, mDNS_VACB, sizeof(mDNS_VACB));
+                                                       s = mDNS_VACB;  // Adjust s to point to the start of the buffer, not the end
+                                                       for(i=0;s[i];i++) {}
+                                                       }
+                                                       break;
+
+                               case 'H' :      {       // Hex Dump
+                                                       void *a = va_arg(arg, void *);
+                                                       size_t size = (size_t)va_arg(arg, int);
+                                                       size_t max = (size_t)va_arg(arg, int);
+                                                       DebugFlags flags = 
+                                                               kDebugFlagsNoAddress | kDebugFlagsNoOffset | kDebugFlagsNoNewLine |
+                                                               kDebugFlags8BitSeparator | kDebugFlagsNo32BitSeparator |
+                                                               kDebugFlagsNo16ByteHexPad | kDebugFlagsNoByteCount;
+                                                       if (F.altForm == 0) flags |= kDebugFlagsNoASCII;
+                                                       size = (max < size) ? max : size;
+                                                       s = mDNS_VACB;  // Adjust s to point to the start of the buffer, not the end
+                                                       i = DebugHexDump(kDebugLevelMax, 0, NULL, 0, 0, NULL, 0, a, a, size, flags, mDNS_VACB, sizeof(mDNS_VACB));
+                                                       }
+                                                       break;
+                               
+                               case 'v' :      {       // Version
+                                                       uint32_t version;
+                                                       version = va_arg(arg, unsigned int);
+                                                       DebugNumVersionToString(version, mDNS_VACB);
+                                                       s = mDNS_VACB;  // Adjust s to point to the start of the buffer, not the end
+                                                       for(i=0;s[i];i++) {}
+                                                       }
+                                                       break;
+
+                               case 'n' :      s = va_arg(arg, char *);
+                                                       if      (F.hSize) * (short *) s = (short)nwritten;
+                                                       else if (F.lSize) * (long  *) s = (long)nwritten;
+                                                       else              * (int   *) s = (int)nwritten;
+                                                       continue;
+       
+                               default:        s = mDNS_VACB;
+                                                       i = DebugSNPrintF(mDNS_VACB, sizeof(mDNS_VACB), "<<UNKNOWN FORMAT CONVERSION CODE %%%c>>", c);
+
+                               case '%' :      *sbuffer++ = (char)c;
+                                                       if (++nwritten >= buflen) goto exit;
+                                                       break;
+                               }
+       
+                       if (i < F.fieldWidth && !F.leftJustify)                 // Pad on the left
+                               do      {
+                                       *sbuffer++ = ' ';
+                                       if (++nwritten >= buflen) goto exit;
+                                       } while (i < --F.fieldWidth);
+       
+                       if (i > buflen - nwritten)      // Make sure we don't truncate in the middle of a UTF-8 character
+                               { i = buflen - nwritten; while (i>0 && (s[i] & 0xC0) == 0x80) i--; }
+                       for (j=0; j<i; j++) *sbuffer++ = *s++;                  // Write the converted result
+                       nwritten += i;
+                       if (nwritten >= buflen) goto exit;
+       
+                       for (; i < F.fieldWidth; i++)                                   // Pad on the right
+                               {
+                               *sbuffer++ = ' ';
+                               if (++nwritten >= buflen) goto exit;
+                               }
+                       }
+               }
+       exit:
+       *sbuffer++ = 0;
+       return(nwritten);
+       }
+
+//===========================================================================================================================
+//     DebugGetErrorString
+//===========================================================================================================================
+
+DEBUG_EXPORT const char *      DebugGetErrorString( int_least32_t inErrorCode, char *inBuffer, size_t inBufferSize )
+{
+       const char *            s;
+       char *                          dst;
+       char *                          end;
+#if( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
+       char                            buffer[ 256 ];
+#endif
+       
+       switch( inErrorCode )
+       {
+               #define CaseErrorString( X, STR )                                       case X: s = STR; break
+               #define CaseErrorStringify( X )                                         case X: s = # X; break
+               #define CaseErrorStringifyHardCode( VALUE, X )          case VALUE: s = # X; break
+               
+               // General Errors
+               
+               CaseErrorString( 0,  "no error" );
+               CaseErrorString( 1,  "in-progress/waiting" );
+               CaseErrorString( -1, "catch-all unknown error" );
+                               
+               // ACP Errors
+               
+               CaseErrorStringifyHardCode( -2,  kACPBadRequestErr );
+               CaseErrorStringifyHardCode( -3,  kACPNoMemoryErr );
+               CaseErrorStringifyHardCode( -4,  kACPBadParamErr );
+               CaseErrorStringifyHardCode( -5,  kACPNotFoundErr );
+               CaseErrorStringifyHardCode( -6,  kACPBadChecksumErr );
+               CaseErrorStringifyHardCode( -7,  kACPCommandNotHandledErr );
+               CaseErrorStringifyHardCode( -8,  kACPNetworkErr );
+               CaseErrorStringifyHardCode( -9,  kACPDuplicateCommandHandlerErr );
+               CaseErrorStringifyHardCode( -10, kACPUnknownPropertyErr );
+               CaseErrorStringifyHardCode( -11, kACPImmutablePropertyErr );
+               CaseErrorStringifyHardCode( -12, kACPBadPropertyValueErr );
+               CaseErrorStringifyHardCode( -13, kACPNoResourcesErr );
+               CaseErrorStringifyHardCode( -14, kACPBadOptionErr );
+               CaseErrorStringifyHardCode( -15, kACPBadSizeErr );
+               CaseErrorStringifyHardCode( -16, kACPBadPasswordErr );
+               CaseErrorStringifyHardCode( -17, kACPNotInitializedErr );
+               CaseErrorStringifyHardCode( -18, kACPNonReadablePropertyErr );
+               CaseErrorStringifyHardCode( -19, kACPBadVersionErr );
+               CaseErrorStringifyHardCode( -20, kACPBadSignatureErr );
+               CaseErrorStringifyHardCode( -21, kACPBadIndexErr );
+               CaseErrorStringifyHardCode( -22, kACPUnsupportedErr );
+               CaseErrorStringifyHardCode( -23, kACPInUseErr );
+               CaseErrorStringifyHardCode( -24, kACPParamCountErr );
+               CaseErrorStringifyHardCode( -25, kACPIDErr );
+               CaseErrorStringifyHardCode( -26, kACPFormatErr );
+               CaseErrorStringifyHardCode( -27, kACPUnknownUserErr );
+               CaseErrorStringifyHardCode( -28, kACPAccessDeniedErr );
+               CaseErrorStringifyHardCode( -29, kACPIncorrectFWErr );
+               
+               // Common Services Errors
+               
+               CaseErrorStringify( kUnknownErr );
+               CaseErrorStringify( kOptionErr );
+               CaseErrorStringify( kSelectorErr );
+               CaseErrorStringify( kExecutionStateErr );
+               CaseErrorStringify( kPathErr );
+               CaseErrorStringify( kParamErr );
+               CaseErrorStringify( kParamCountErr );
+               CaseErrorStringify( kCommandErr );
+               CaseErrorStringify( kIDErr );
+               CaseErrorStringify( kStateErr );
+               CaseErrorStringify( kRangeErr );
+               CaseErrorStringify( kRequestErr );
+               CaseErrorStringify( kResponseErr );
+               CaseErrorStringify( kChecksumErr );
+               CaseErrorStringify( kNotHandledErr );
+               CaseErrorStringify( kVersionErr );
+               CaseErrorStringify( kSignatureErr );
+               CaseErrorStringify( kFormatErr );
+               CaseErrorStringify( kNotInitializedErr );
+               CaseErrorStringify( kAlreadyInitializedErr );
+               CaseErrorStringify( kNotInUseErr );
+               CaseErrorStringify( kInUseErr );
+               CaseErrorStringify( kTimeoutErr );
+               CaseErrorStringify( kCanceledErr );
+               CaseErrorStringify( kAlreadyCanceledErr );
+               CaseErrorStringify( kCannotCancelErr );
+               CaseErrorStringify( kDeletedErr );
+               CaseErrorStringify( kNotFoundErr );
+               CaseErrorStringify( kNoMemoryErr );
+               CaseErrorStringify( kNoResourcesErr );
+               CaseErrorStringify( kDuplicateErr );
+               CaseErrorStringify( kImmutableErr );
+               CaseErrorStringify( kUnsupportedDataErr );
+               CaseErrorStringify( kIntegrityErr );
+               CaseErrorStringify( kIncompatibleErr );
+               CaseErrorStringify( kUnsupportedErr );
+               CaseErrorStringify( kUnexpectedErr );
+               CaseErrorStringify( kValueErr );
+               CaseErrorStringify( kNotReadableErr );
+               CaseErrorStringify( kNotWritableErr );
+               CaseErrorStringify( kBadReferenceErr );
+               CaseErrorStringify( kFlagErr );
+               CaseErrorStringify( kMalformedErr );
+               CaseErrorStringify( kSizeErr );
+               CaseErrorStringify( kNameErr );
+               CaseErrorStringify( kNotReadyErr );
+               CaseErrorStringify( kReadErr );
+               CaseErrorStringify( kWriteErr );
+               CaseErrorStringify( kMismatchErr );
+               CaseErrorStringify( kDateErr );
+               CaseErrorStringify( kUnderrunErr );
+               CaseErrorStringify( kOverrunErr );
+               CaseErrorStringify( kEndingErr );
+               CaseErrorStringify( kConnectionErr );
+               CaseErrorStringify( kAuthenticationErr );
+               CaseErrorStringify( kOpenErr );
+               CaseErrorStringify( kTypeErr );
+               CaseErrorStringify( kSkipErr );
+               CaseErrorStringify( kNoAckErr );
+               CaseErrorStringify( kCollisionErr );
+               CaseErrorStringify( kBackoffErr );
+               CaseErrorStringify( kNoAddressAckErr );
+               CaseErrorStringify( kBusyErr );
+               CaseErrorStringify( kNoSpaceErr );
+               
+               // mDNS/DNS-SD Errors
+               
+               CaseErrorStringifyHardCode( -65537, mStatus_UnknownErr );
+               CaseErrorStringifyHardCode( -65538, mStatus_NoSuchNameErr );
+               CaseErrorStringifyHardCode( -65539, mStatus_NoMemoryErr );
+               CaseErrorStringifyHardCode( -65540, mStatus_BadParamErr );
+               CaseErrorStringifyHardCode( -65541, mStatus_BadReferenceErr );
+               CaseErrorStringifyHardCode( -65542, mStatus_BadStateErr );
+               CaseErrorStringifyHardCode( -65543, mStatus_BadFlagsErr );
+               CaseErrorStringifyHardCode( -65544, mStatus_UnsupportedErr );
+               CaseErrorStringifyHardCode( -65545, mStatus_NotInitializedErr );
+               CaseErrorStringifyHardCode( -65546, mStatus_NoCache );
+               CaseErrorStringifyHardCode( -65547, mStatus_AlreadyRegistered );
+               CaseErrorStringifyHardCode( -65548, mStatus_NameConflict );
+               CaseErrorStringifyHardCode( -65549, mStatus_Invalid );
+               CaseErrorStringifyHardCode( -65550, mStatus_GrowCache );
+               CaseErrorStringifyHardCode( -65551, mStatus_BadInterfaceErr );
+               CaseErrorStringifyHardCode( -65552, mStatus_Incompatible );
+               CaseErrorStringifyHardCode( -65791, mStatus_ConfigChanged );
+               CaseErrorStringifyHardCode( -65792, mStatus_MemFree );
+               
+               // RSP Errors
+               
+               CaseErrorStringifyHardCode( -400000, kRSPUnknownErr );
+               CaseErrorStringifyHardCode( -400050, kRSPParamErr );
+               CaseErrorStringifyHardCode( -400108, kRSPNoMemoryErr );
+               CaseErrorStringifyHardCode( -405246, kRSPRangeErr );
+               CaseErrorStringifyHardCode( -409057, kRSPSizeErr );
+               CaseErrorStringifyHardCode( -400200, kRSPHardwareErr );
+               CaseErrorStringifyHardCode( -401712, kRSPTimeoutErr );  
+               CaseErrorStringifyHardCode( -402053, kRSPUnsupportedErr );
+               CaseErrorStringifyHardCode( -402419, kRSPIDErr );
+               CaseErrorStringifyHardCode( -403165, kRSPFlagErr );
+               CaseErrorString(                        -200000, "kRSPControllerStatusBase - 0x50" );           
+               CaseErrorString(                        -200080, "kRSPCommandSucceededErr - 0x50" );
+               CaseErrorString(                        -200001, "kRSPCommandFailedErr - 0x01" );
+               CaseErrorString(                        -200051, "kRSPChecksumErr - 0x33" );
+               CaseErrorString(                        -200132, "kRSPCommandTimeoutErr - 0x84" );
+               CaseErrorString(                        -200034, "kRSPPasswordRequiredErr - 0x22 OBSOLETE" );
+               CaseErrorString(                        -200128, "kRSPCanceledErr - 0x02 Async" );
+               
+               // XML Errors
+               
+               CaseErrorStringifyHardCode( -100043, kXMLNotFoundErr );
+               CaseErrorStringifyHardCode( -100050, kXMLParamErr );
+               CaseErrorStringifyHardCode( -100108, kXMLNoMemoryErr );
+               CaseErrorStringifyHardCode( -100206, kXMLFormatErr );
+               CaseErrorStringifyHardCode( -100586, kXMLNoRootElementErr );
+               CaseErrorStringifyHardCode( -101703, kXMLWrongDataTypeErr );
+               CaseErrorStringifyHardCode( -101726, kXMLKeyErr );
+               CaseErrorStringifyHardCode( -102053, kXMLUnsupportedErr );
+               CaseErrorStringifyHardCode( -102063, kXMLMissingElementErr );
+               CaseErrorStringifyHardCode( -103026, kXMLParseErr );
+               CaseErrorStringifyHardCode( -103159, kXMLBadDataErr );
+               CaseErrorStringifyHardCode( -103170, kXMLBadNameErr );
+               CaseErrorStringifyHardCode( -105246, kXMLRangeErr );
+               CaseErrorStringifyHardCode( -105251, kXMLUnknownElementErr );
+               CaseErrorStringifyHardCode( -108739, kXMLMalformedInputErr );
+               CaseErrorStringifyHardCode( -109057, kXMLBadSizeErr );
+               CaseErrorStringifyHardCode( -101730, kXMLMissingChildElementErr );
+               CaseErrorStringifyHardCode( -102107, kXMLMissingParentElementErr );
+               CaseErrorStringifyHardCode( -130587, kXMLNonRootElementErr );
+               CaseErrorStringifyHardCode( -102015, kXMLDateErr );
+
+       #if( __MACH__ )
+       
+               // Mach Errors
+
+               CaseErrorStringifyHardCode( 0x00002000, MACH_MSG_IPC_SPACE );
+               CaseErrorStringifyHardCode( 0x00001000, MACH_MSG_VM_SPACE );
+               CaseErrorStringifyHardCode( 0x00000800, MACH_MSG_IPC_KERNEL );
+               CaseErrorStringifyHardCode( 0x00000400, MACH_MSG_VM_KERNEL );
+               CaseErrorStringifyHardCode( 0x10000001, MACH_SEND_IN_PROGRESS );
+               CaseErrorStringifyHardCode( 0x10000002, MACH_SEND_INVALID_DATA );
+               CaseErrorStringifyHardCode( 0x10000003, MACH_SEND_INVALID_DEST );
+               CaseErrorStringifyHardCode( 0x10000004, MACH_SEND_TIMED_OUT );
+               CaseErrorStringifyHardCode( 0x10000007, MACH_SEND_INTERRUPTED );
+               CaseErrorStringifyHardCode( 0x10000008, MACH_SEND_MSG_TOO_SMALL );
+               CaseErrorStringifyHardCode( 0x10000009, MACH_SEND_INVALID_REPLY );
+               CaseErrorStringifyHardCode( 0x1000000A, MACH_SEND_INVALID_RIGHT );
+               CaseErrorStringifyHardCode( 0x1000000B, MACH_SEND_INVALID_NOTIFY );
+               CaseErrorStringifyHardCode( 0x1000000C, MACH_SEND_INVALID_MEMORY );
+               CaseErrorStringifyHardCode( 0x1000000D, MACH_SEND_NO_BUFFER );
+               CaseErrorStringifyHardCode( 0x1000000E, MACH_SEND_TOO_LARGE );
+               CaseErrorStringifyHardCode( 0x1000000F, MACH_SEND_INVALID_TYPE );
+               CaseErrorStringifyHardCode( 0x10000010, MACH_SEND_INVALID_HEADER );
+               CaseErrorStringifyHardCode( 0x10000011, MACH_SEND_INVALID_TRAILER );
+               CaseErrorStringifyHardCode( 0x10000015, MACH_SEND_INVALID_RT_OOL_SIZE );
+               CaseErrorStringifyHardCode( 0x10004001, MACH_RCV_IN_PROGRESS );
+               CaseErrorStringifyHardCode( 0x10004002, MACH_RCV_INVALID_NAME );
+               CaseErrorStringifyHardCode( 0x10004003, MACH_RCV_TIMED_OUT );
+               CaseErrorStringifyHardCode( 0x10004004, MACH_RCV_TOO_LARGE );
+               CaseErrorStringifyHardCode( 0x10004005, MACH_RCV_INTERRUPTED );
+               CaseErrorStringifyHardCode( 0x10004006, MACH_RCV_PORT_CHANGED );
+               CaseErrorStringifyHardCode( 0x10004007, MACH_RCV_INVALID_NOTIFY );
+               CaseErrorStringifyHardCode( 0x10004008, MACH_RCV_INVALID_DATA );
+               CaseErrorStringifyHardCode( 0x10004009, MACH_RCV_PORT_DIED );
+               CaseErrorStringifyHardCode( 0x1000400A, MACH_RCV_IN_SET );
+               CaseErrorStringifyHardCode( 0x1000400B, MACH_RCV_HEADER_ERROR );
+               CaseErrorStringifyHardCode( 0x1000400C, MACH_RCV_BODY_ERROR );
+               CaseErrorStringifyHardCode( 0x1000400D, MACH_RCV_INVALID_TYPE );
+               CaseErrorStringifyHardCode( 0x1000400E, MACH_RCV_SCATTER_SMALL );
+               CaseErrorStringifyHardCode( 0x1000400F, MACH_RCV_INVALID_TRAILER );
+               CaseErrorStringifyHardCode( 0x10004011, MACH_RCV_IN_PROGRESS_TIMED );
+
+               // Mach OSReturn Errors
+
+               CaseErrorStringifyHardCode( 0xDC000001, kOSReturnError );
+               CaseErrorStringifyHardCode( 0xDC004001, kOSMetaClassInternal );
+               CaseErrorStringifyHardCode( 0xDC004002, kOSMetaClassHasInstances );
+               CaseErrorStringifyHardCode( 0xDC004003, kOSMetaClassNoInit );
+               CaseErrorStringifyHardCode( 0xDC004004, kOSMetaClassNoTempData );
+               CaseErrorStringifyHardCode( 0xDC004005, kOSMetaClassNoDicts );
+               CaseErrorStringifyHardCode( 0xDC004006, kOSMetaClassNoKModSet );
+               CaseErrorStringifyHardCode( 0xDC004007, kOSMetaClassNoInsKModSet );
+               CaseErrorStringifyHardCode( 0xDC004008, kOSMetaClassNoSuper );
+               CaseErrorStringifyHardCode( 0xDC004009, kOSMetaClassInstNoSuper );
+               CaseErrorStringifyHardCode( 0xDC00400A, kOSMetaClassDuplicateClass );
+
+               // IOKit Errors
+
+               CaseErrorStringifyHardCode( 0xE00002BC, kIOReturnError );
+               CaseErrorStringifyHardCode( 0xE00002BD, kIOReturnNoMemory );
+               CaseErrorStringifyHardCode( 0xE00002BE, kIOReturnNoResources );
+               CaseErrorStringifyHardCode( 0xE00002BF, kIOReturnIPCError );
+               CaseErrorStringifyHardCode( 0xE00002C0, kIOReturnNoDevice );
+               CaseErrorStringifyHardCode( 0xE00002C1, kIOReturnNotPrivileged );
+               CaseErrorStringifyHardCode( 0xE00002C2, kIOReturnBadArgument );
+               CaseErrorStringifyHardCode( 0xE00002C3, kIOReturnLockedRead );
+               CaseErrorStringifyHardCode( 0xE00002C4, kIOReturnLockedWrite );
+               CaseErrorStringifyHardCode( 0xE00002C5, kIOReturnExclusiveAccess );
+               CaseErrorStringifyHardCode( 0xE00002C6, kIOReturnBadMessageID );
+               CaseErrorStringifyHardCode( 0xE00002C7, kIOReturnUnsupported );
+               CaseErrorStringifyHardCode( 0xE00002C8, kIOReturnVMError );
+               CaseErrorStringifyHardCode( 0xE00002C9, kIOReturnInternalError );
+               CaseErrorStringifyHardCode( 0xE00002CA, kIOReturnIOError );
+               CaseErrorStringifyHardCode( 0xE00002CC, kIOReturnCannotLock );
+               CaseErrorStringifyHardCode( 0xE00002CD, kIOReturnNotOpen );
+               CaseErrorStringifyHardCode( 0xE00002CE, kIOReturnNotReadable );
+               CaseErrorStringifyHardCode( 0xE00002CF, kIOReturnNotWritable );
+               CaseErrorStringifyHardCode( 0xE00002D0, kIOReturnNotAligned );
+               CaseErrorStringifyHardCode( 0xE00002D1, kIOReturnBadMedia );
+               CaseErrorStringifyHardCode( 0xE00002D2, kIOReturnStillOpen );
+               CaseErrorStringifyHardCode( 0xE00002D3, kIOReturnRLDError );
+               CaseErrorStringifyHardCode( 0xE00002D4, kIOReturnDMAError );
+               CaseErrorStringifyHardCode( 0xE00002D5, kIOReturnBusy );
+               CaseErrorStringifyHardCode( 0xE00002D6, kIOReturnTimeout );
+               CaseErrorStringifyHardCode( 0xE00002D7, kIOReturnOffline );
+               CaseErrorStringifyHardCode( 0xE00002D8, kIOReturnNotReady );
+               CaseErrorStringifyHardCode( 0xE00002D9, kIOReturnNotAttached );
+               CaseErrorStringifyHardCode( 0xE00002DA, kIOReturnNoChannels );
+               CaseErrorStringifyHardCode( 0xE00002DB, kIOReturnNoSpace );
+               CaseErrorStringifyHardCode( 0xE00002DD, kIOReturnPortExists );
+               CaseErrorStringifyHardCode( 0xE00002DE, kIOReturnCannotWire );
+               CaseErrorStringifyHardCode( 0xE00002DF, kIOReturnNoInterrupt );
+               CaseErrorStringifyHardCode( 0xE00002E0, kIOReturnNoFrames );
+               CaseErrorStringifyHardCode( 0xE00002E1, kIOReturnMessageTooLarge );
+               CaseErrorStringifyHardCode( 0xE00002E2, kIOReturnNotPermitted );
+               CaseErrorStringifyHardCode( 0xE00002E3, kIOReturnNoPower );
+               CaseErrorStringifyHardCode( 0xE00002E4, kIOReturnNoMedia );
+               CaseErrorStringifyHardCode( 0xE00002E5, kIOReturnUnformattedMedia );
+               CaseErrorStringifyHardCode( 0xE00002E6, kIOReturnUnsupportedMode );
+               CaseErrorStringifyHardCode( 0xE00002E7, kIOReturnUnderrun );
+               CaseErrorStringifyHardCode( 0xE00002E8, kIOReturnOverrun );
+               CaseErrorStringifyHardCode( 0xE00002E9, kIOReturnDeviceError     );
+               CaseErrorStringifyHardCode( 0xE00002EA, kIOReturnNoCompletion    );
+               CaseErrorStringifyHardCode( 0xE00002EB, kIOReturnAborted         );
+               CaseErrorStringifyHardCode( 0xE00002EC, kIOReturnNoBandwidth     );
+               CaseErrorStringifyHardCode( 0xE00002ED, kIOReturnNotResponding   );
+               CaseErrorStringifyHardCode( 0xE00002EE, kIOReturnIsoTooOld       );
+               CaseErrorStringifyHardCode( 0xE00002EF, kIOReturnIsoTooNew       );
+               CaseErrorStringifyHardCode( 0xE00002F0, kIOReturnNotFound );
+               CaseErrorStringifyHardCode( 0xE0000001, kIOReturnInvalid );
+
+               // IOKit FireWire Errors
+
+               CaseErrorStringifyHardCode( 0xE0008010, kIOFireWireResponseBase );
+               CaseErrorStringifyHardCode( 0xE0008020, kIOFireWireBusReset );
+               CaseErrorStringifyHardCode( 0xE0008001, kIOConfigNoEntry );
+               CaseErrorStringifyHardCode( 0xE0008002, kIOFireWirePending );
+               CaseErrorStringifyHardCode( 0xE0008003, kIOFireWireLastDCLToken );
+               CaseErrorStringifyHardCode( 0xE0008004, kIOFireWireConfigROMInvalid );
+               CaseErrorStringifyHardCode( 0xE0008005, kIOFireWireAlreadyRegistered );
+               CaseErrorStringifyHardCode( 0xE0008006, kIOFireWireMultipleTalkers );
+               CaseErrorStringifyHardCode( 0xE0008007, kIOFireWireChannelActive );
+               CaseErrorStringifyHardCode( 0xE0008008, kIOFireWireNoListenerOrTalker );
+               CaseErrorStringifyHardCode( 0xE0008009, kIOFireWireNoChannels );
+               CaseErrorStringifyHardCode( 0xE000800A, kIOFireWireChannelNotAvailable );
+               CaseErrorStringifyHardCode( 0xE000800B, kIOFireWireSeparateBus );
+               CaseErrorStringifyHardCode( 0xE000800C, kIOFireWireBadSelfIDs );
+               CaseErrorStringifyHardCode( 0xE000800D, kIOFireWireLowCableVoltage );
+               CaseErrorStringifyHardCode( 0xE000800E, kIOFireWireInsufficientPower );
+               CaseErrorStringifyHardCode( 0xE000800F, kIOFireWireOutOfTLabels );
+               CaseErrorStringifyHardCode( 0xE0008101, kIOFireWireBogusDCLProgram );
+               CaseErrorStringifyHardCode( 0xE0008102, kIOFireWireTalkingAndListening );
+               CaseErrorStringifyHardCode( 0xE0008103, kIOFireWireHardwareSlept );
+               CaseErrorStringifyHardCode( 0xE00087D0, kIOFWMessageServiceIsRequestingClose );
+               CaseErrorStringifyHardCode( 0xE00087D1, kIOFWMessagePowerStateChanged );
+               CaseErrorStringifyHardCode( 0xE00087D2, kIOFWMessageTopologyChanged );
+
+               // IOKit USB Errors
+                               
+               CaseErrorStringifyHardCode( 0xE0004061, kIOUSBUnknownPipeErr );
+               CaseErrorStringifyHardCode( 0xE0004060, kIOUSBTooManyPipesErr );
+               CaseErrorStringifyHardCode( 0xE000405F, kIOUSBNoAsyncPortErr );
+               CaseErrorStringifyHardCode( 0xE000405E, kIOUSBNotEnoughPipesErr );
+               CaseErrorStringifyHardCode( 0xE000405D, kIOUSBNotEnoughPowerErr );
+               CaseErrorStringifyHardCode( 0xE0004057, kIOUSBEndpointNotFound );
+               CaseErrorStringifyHardCode( 0xE0004056, kIOUSBConfigNotFound );
+               CaseErrorStringifyHardCode( 0xE0004051, kIOUSBTransactionTimeout );
+               CaseErrorStringifyHardCode( 0xE0004050, kIOUSBTransactionReturned );
+               CaseErrorStringifyHardCode( 0xE000404F, kIOUSBPipeStalled );
+               CaseErrorStringifyHardCode( 0xE000404E, kIOUSBInterfaceNotFound );
+               CaseErrorStringifyHardCode( 0xE000404D, kIOUSBLowLatencyBufferNotPreviouslyAllocated );
+               CaseErrorStringifyHardCode( 0xE000404C, kIOUSBLowLatencyFrameListNotPreviouslyAllocated );
+               CaseErrorStringifyHardCode( 0xE000404B, kIOUSBHighSpeedSplitError );
+               CaseErrorStringifyHardCode( 0xE0004010, kIOUSBLinkErr );
+               CaseErrorStringifyHardCode( 0xE000400F, kIOUSBNotSent2Err );
+               CaseErrorStringifyHardCode( 0xE000400E, kIOUSBNotSent1Err );
+               CaseErrorStringifyHardCode( 0xE000400D, kIOUSBBufferUnderrunErr );
+               CaseErrorStringifyHardCode( 0xE000400C, kIOUSBBufferOverrunErr );
+               CaseErrorStringifyHardCode( 0xE000400B, kIOUSBReserved2Err );
+               CaseErrorStringifyHardCode( 0xE000400A, kIOUSBReserved1Err );
+               CaseErrorStringifyHardCode( 0xE0004007, kIOUSBWrongPIDErr );
+               CaseErrorStringifyHardCode( 0xE0004006, kIOUSBPIDCheckErr );
+               CaseErrorStringifyHardCode( 0xE0004003, kIOUSBDataToggleErr );
+               CaseErrorStringifyHardCode( 0xE0004002, kIOUSBBitstufErr );
+               CaseErrorStringifyHardCode( 0xE0004001, kIOUSBCRCErr );
+       
+       #endif  // __MACH__
+
+               // Other Errors
+               
+               default:
+                       s = NULL;
+                       #if( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
+                               if( inBuffer && ( inBufferSize > 0 ) )
+                               {
+                                       DWORD           n;
+                                       
+                                       n = FormatMessageA( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, (DWORD) inErrorCode, 
+                                               MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ), buffer, sizeof( buffer ), NULL );
+                                       if( n > 0 )
+                                       {
+                                               // Remove any trailing CR's or LF's since some messages have them.
+                                               
+                                               while( ( n > 0 ) && isspace( ( (unsigned char *) buffer )[ n - 1 ] ) )
+                                               {
+                                                       buffer[ --n ] = '\0';
+                                               }
+                                               s = buffer;
+                                       }
+                               }
+                       #endif
+                       
+                       if( !s )
+                       {
+                               #if( !TARGET_API_MAC_OSX_KERNEL && !TARGET_OS_WINDOWS_CE )
+                                       s = strerror( inErrorCode );
+                               #endif
+                               if( !s )
+                               {
+                                       s = "<unknown error code>";
+                               }
+                       }
+                       break;
+       }
+       
+       // Copy the string to the output buffer. If no buffer is supplied or it is empty, return an empty string.
+       
+       if( inBuffer && ( inBufferSize > 0 ) )
+       {
+               dst = inBuffer;
+               end = dst + ( inBufferSize - 1 );
+               while( ( ( end - dst ) > 0 ) && ( *s != '\0' ) )
+               {
+                       *dst++ = *s++;
+               }
+               *dst = '\0';
+               s = inBuffer;
+       }
+       return( s );
+}
+
+//===========================================================================================================================
+//     DebugHexDump
+//===========================================================================================================================
+
+DEBUG_EXPORT size_t
+       DebugHexDump( 
+               DebugLevel              inLevel, 
+               int                             inIndent, 
+               const char *    inLabel, 
+               size_t                  inLabelSize, 
+               int                             inLabelMinWidth, 
+               const char *    inType, 
+               size_t                  inTypeSize, 
+               const void *    inDataStart, 
+               const void *    inData, 
+               size_t                  inDataSize, 
+               DebugFlags              inFlags, 
+               char *                  outBuffer, 
+               size_t                  inBufferSize )
+{
+       static const char               kHexChars[] = "0123456789ABCDEF";
+       const uint8_t *                 start;
+       const uint8_t *                 src;
+       char *                                  dst;
+       char *                                  end;
+       size_t                                  n;
+       int                                             offset;
+       int                                             width;
+       const char *                    newline;
+       char                                    separator[ 8 ];
+       char *                                  s;
+       
+       DEBUG_UNUSED( inType );
+       DEBUG_UNUSED( inTypeSize );
+       
+       // Set up the function-wide variables.
+       
+       if( inLabelSize == kSizeCString )
+       {
+               inLabelSize = strlen( inLabel );
+       }
+       start   = (const uint8_t *) inData;
+       src     = start;
+       dst             = outBuffer;
+       end             = dst + inBufferSize;
+       offset  = (int)( (intptr_t) inData - (intptr_t) inDataStart );
+       width   = ( (int) inLabelSize > inLabelMinWidth ) ? (int) inLabelSize : inLabelMinWidth;
+       newline = ( inFlags & kDebugFlagsNoNewLine ) ? "" : "\n";
+               
+       // Set up the separator string. This is used to insert spaces on subsequent "lines" when not using newlines.
+       
+       s = separator;
+       if( inFlags & kDebugFlagsNoNewLine )
+       {
+               if( inFlags & kDebugFlags8BitSeparator )
+               {
+                       *s++ = ' ';
+               }
+               if( inFlags & kDebugFlags16BitSeparator )
+               {
+                       *s++ = ' ';
+               }
+               if( !( inFlags & kDebugFlagsNo32BitSeparator ) )
+               {
+                       *s++ = ' ';
+               }
+               check( ( (size_t)( s - separator ) ) < sizeof( separator ) );
+       }
+       *s = '\0';
+       
+       for( ;; )
+       {
+               char            prefixString[ 32 ];
+               char            hexString[ 64 ];
+               char            asciiString[ 32 ];
+               char            byteCountString[ 32 ];
+               int                     c;
+               size_t          chunkSize;
+               size_t          i;
+               
+               // If this is a label-only item (i.e. no data), print the label (accounting for prefix string spacing) and exit.
+               
+               if( inDataSize == 0 )
+               {
+                       if( inLabel && ( inLabelSize > 0 ) )
+                       {
+                               width = 0;
+                               if( !( inFlags & kDebugFlagsNoAddress ) )
+                               {
+                                       width += 8;                     // "00000000"
+                                       if( !( inFlags & kDebugFlagsNoOffset ) )
+                                       {
+                                               width += 1;             // "+"
+                                       }
+                               }
+                               if( inFlags & kDebugFlags32BitOffset )
+                               {
+                                       width += 8;                     // "00000000"
+                               }
+                               else if( !( inFlags & kDebugFlagsNoOffset ) )
+                               {
+                                       width += 4;                     // "0000"
+                               }
+                               
+                               if( outBuffer )
+                               {
+                                       dst += DebugSNPrintF( dst, (size_t)( end - dst ), "%*s" "%-*.*s" "%.*s" "%s", 
+                                               width, "", 
+                                               ( width > 0 ) ? ": " : "", 
+                                               width, (int) inLabelSize, inLabel, 
+                                               newline );
+                               }
+                               else
+                               {
+                                       dst += DebugPrintF( inLevel, "%*s" "%-*.*s" "%.*s" "%s", 
+                                               width, "", 
+                                               ( width > 0 ) ? ": " : "", 
+                                               width, (int) inLabelSize, inLabel, 
+                                               newline );
+                               }
+                       }
+                       break;
+               }
+               
+               // Build the prefix string. It will be in one of the following formats:
+               //
+               // 1) "00000000+0000[0000]"     (address and offset)
+               // 2) "00000000"                        (address only)
+               // 3) "0000[0000]"                      (offset only)
+               // 4) ""                                        (no address or offset)
+               //
+               // Note: If we're printing multiple "lines", but not printing newlines, a space is used to separate.
+               
+               s = prefixString;
+               if( !( inFlags & kDebugFlagsNoAddress ) )
+               {
+                       *s++ = kHexChars[ ( ( (uintptr_t) src ) >> 28 ) & 0xF ];
+                       *s++ = kHexChars[ ( ( (uintptr_t) src ) >> 24 ) & 0xF ];
+                       *s++ = kHexChars[ ( ( (uintptr_t) src ) >> 20 ) & 0xF ];
+                       *s++ = kHexChars[ ( ( (uintptr_t) src ) >> 16 ) & 0xF ];
+                       *s++ = kHexChars[ ( ( (uintptr_t) src ) >> 12 ) & 0xF ];
+                       *s++ = kHexChars[ ( ( (uintptr_t) src ) >>  8 ) & 0xF ];
+                       *s++ = kHexChars[ ( ( (uintptr_t) src ) >>  4 ) & 0xF ];
+                       *s++ = kHexChars[   ( (uintptr_t) src )         & 0xF ];
+                       
+                       if( !( inFlags & kDebugFlagsNoOffset ) )
+                       {
+                               *s++ = '+';
+                       }
+               }
+               if( !( inFlags & kDebugFlagsNoOffset ) )
+               {
+                       if( inFlags & kDebugFlags32BitOffset )
+                       {
+                               *s++ = kHexChars[ ( offset >> 28 ) & 0xF ];
+                               *s++ = kHexChars[ ( offset >> 24 ) & 0xF ];
+                               *s++ = kHexChars[ ( offset >> 20 ) & 0xF ];
+                               *s++ = kHexChars[ ( offset >> 16 ) & 0xF ];
+                       }
+                       *s++ = kHexChars[ ( offset >> 12 ) & 0xF ];
+                       *s++ = kHexChars[ ( offset >>  8 ) & 0xF ];
+                       *s++ = kHexChars[ ( offset >>  4 ) & 0xF ];
+                       *s++ = kHexChars[   offset         & 0xF ];
+               }
+               if( s != prefixString )
+               {
+                       *s++ = ':';
+                       *s++ = ' ';
+               }
+               check( ( (size_t)( s - prefixString ) ) < sizeof( prefixString ) );
+               *s = '\0';
+               
+               // Build a hex string with a optional spaces after every 1, 2, and/or 4 bytes to make it easier to read.
+               // Optionally pads the hex string with space to fill the full 16 byte range (so it lines up).
+               
+               s = hexString;
+               chunkSize = ( inDataSize < 16 ) ? inDataSize : 16;
+               n = ( inFlags & kDebugFlagsNo16ByteHexPad ) ? chunkSize : 16;
+               for( i = 0; i < n; ++i )
+               {
+                       if( ( inFlags & kDebugFlags8BitSeparator ) && ( i > 0 ) )
+                       {
+                               *s++ = ' ';
+                       }
+                       if( ( inFlags & kDebugFlags16BitSeparator ) && ( i > 0 ) && ( ( i % 2 ) == 0 ) )
+                       {
+                               *s++ = ' ';
+                       }
+                       if( !( inFlags & kDebugFlagsNo32BitSeparator ) && ( i > 0 ) && ( ( i % 4 ) == 0 ) )
+                       {
+                               *s++ = ' ';
+                       }
+                       if( i < chunkSize )
+                       {
+                               *s++ = kHexChars[ src[ i ] >> 4   ];
+                               *s++ = kHexChars[ src[ i ] &  0xF ];
+                       }
+                       else
+                       {
+                               *s++ = ' ';
+                               *s++ = ' ';
+                       }
+               }
+               check( ( (size_t)( s - hexString ) ) < sizeof( hexString ) );
+               *s = '\0';
+               
+               // Build a string with the ASCII version of the data (replaces non-printable characters with '^').
+               // Optionally pads the string with '`' to fill the full 16 byte range (so it lines up).
+               
+               s = asciiString;
+               if( !( inFlags & kDebugFlagsNoASCII ) )
+               {
+                       *s++ = ' ';
+                       *s++ = '|';
+                       for( i = 0; i < n; ++i )
+                       {
+                               if( i < chunkSize )
+                               {
+                                       c = src[ i ];
+                                       if( !DebugIsPrint( c ) )
+                                       {
+                                               c = '^';
+                                       }
+                               }
+                               else
+                               {
+                                       c = '`';
+                               }
+                               *s++ = (char) c;
+                       }
+                       *s++ = '|';
+                       check( ( (size_t)( s - asciiString ) ) < sizeof( asciiString ) );
+               }
+               *s = '\0';
+               
+               // Build a string indicating how bytes are in the hex dump. Only printed on the first line.
+               
+               s = byteCountString;
+               if( !( inFlags & kDebugFlagsNoByteCount ) )
+               {
+                       if( src == start )
+                       {
+                               s += DebugSNPrintF( s, sizeof( byteCountString ), " (%d bytes)", (int) inDataSize );
+                       }
+               }
+               check( ( (size_t)( s - byteCountString ) ) < sizeof( byteCountString ) );
+               *s = '\0';
+               
+               // Build the entire line from all the pieces we've previously built.
+                       
+               if( outBuffer )
+               {
+                       if( src == start )
+                       {
+                               dst += DebugSNPrintF( dst, (size_t)( end - dst ), 
+                                       "%*s"           // Indention
+                                       "%s"            // Separator (only if needed)
+                                       "%s"            // Prefix
+                                       "%-*.*s"        // Label
+                                       "%s"            // Separator
+                                       "%s"            // Hex
+                                       "%s"            // ASCII
+                                       "%s"            // Byte Count
+                                       "%s",           // Newline
+                                       inIndent, "", 
+                                       ( src != start ) ? separator : "", 
+                                       prefixString, 
+                                       width, (int) inLabelSize, inLabel ? inLabel : "", 
+                                       ( width > 0 ) ? " " : "", 
+                                       hexString, 
+                                       asciiString, 
+                                       byteCountString, 
+                                       newline );
+                       }
+                       else
+                       {
+                               dst += DebugSNPrintF( dst, (size_t)( end - dst ), 
+                                       "%*s"           // Indention
+                                       "%s"            // Separator (only if needed)
+                                       "%s"            // Prefix
+                                       "%*s"           // Label Spacing
+                                       "%s"            // Separator
+                                       "%s"            // Hex
+                                       "%s"            // ASCII
+                                       "%s"            // Byte Count
+                                       "%s",           // Newline
+                                       inIndent, "", 
+                                       ( src != start ) ? separator : "", 
+                                       prefixString, 
+                                       width, "", 
+                                       ( width > 0 ) ? " " : "", 
+                                       hexString, 
+                                       asciiString, 
+                                       byteCountString, 
+                                       newline );
+                       }
+               }
+               else
+               {
+                       if( src == start )
+                       {
+                               dst += DebugPrintF( inLevel, 
+                                       "%*s"           // Indention
+                                       "%s"            // Separator (only if needed)
+                                       "%s"            // Prefix
+                                       "%-*.*s"        // Label
+                                       "%s"            // Separator
+                                       "%s"            // Hex
+                                       "%s"            // ASCII
+                                       "%s"            // Byte Count
+                                       "%s",           // Newline
+                                       inIndent, "", 
+                                       ( src != start ) ? separator : "", 
+                                       prefixString, 
+                                       width, (int) inLabelSize, inLabel, 
+                                       ( width > 0 ) ? " " : "", 
+                                       hexString, 
+                                       asciiString, 
+                                       byteCountString, 
+                                       newline );
+                       }
+                       else
+                       {
+                               dst += DebugPrintF( inLevel, 
+                                       "%*s"           // Indention
+                                       "%s"            // Separator (only if needed)
+                                       "%s"            // Prefix
+                                       "%*s"           // Label Spacing
+                                       "%s"            // Separator
+                                       "%s"            // Hex
+                                       "%s"            // ASCII
+                                       "%s"            // Byte Count
+                                       "%s",           // Newline
+                                       inIndent, "", 
+                                       ( src != start ) ? separator : "", 
+                                       prefixString, 
+                                       width, "", 
+                                       ( width > 0 ) ? " " : "", 
+                                       hexString, 
+                                       asciiString, 
+                                       byteCountString, 
+                                       newline );
+                       }
+               }
+               
+               // Move to the next chunk. Exit if there is no more data.
+               
+               offset          += (int) chunkSize;
+               src             += chunkSize;
+               inDataSize      -= chunkSize;
+               if( inDataSize == 0 )
+               {
+                       break;
+               }
+       }
+       
+       // Note: The "dst - outBuffer" size calculation works even if "outBuffer" is NULL because it's all relative.
+       
+       return( (size_t)( dst - outBuffer ) );
+}
+
+//===========================================================================================================================
+//     DebugNumVersionToString
+//===========================================================================================================================
+
+static char *  DebugNumVersionToString( uint32_t inVersion, char *inString )
+{
+       char *          s;
+       uint8_t         majorRev;
+       uint8_t         minor;
+       uint8_t         bugFix;
+       uint8_t         stage;
+       uint8_t         revision;
+       
+       check( inString );
+       
+       majorRev        = (uint8_t)( ( inVersion >> 24 ) & 0xFF );
+       minor           = (uint8_t)( ( inVersion >> 20 ) & 0x0F );
+       bugFix          = (uint8_t)( ( inVersion >> 16 ) & 0x0F );
+       stage           = (uint8_t)( ( inVersion >>  8 ) & 0xFF );
+       revision        = (uint8_t)(   inVersion         & 0xFF );
+       
+       // Convert the major, minor, and bugfix numbers.
+       
+       s  = inString;
+       s += sprintf( s, "%u", majorRev );
+       s += sprintf( s, ".%u", minor );
+       if( bugFix != 0 )
+       {
+               s += sprintf( s, ".%u", bugFix );
+       }
+       
+       // Convert the version stage and non-release revision number.
+       
+       switch( stage )
+       {
+               case kVersionStageDevelopment:
+                       s += sprintf( s, "d%u", revision );
+                       break;
+               
+               case kVersionStageAlpha:
+                       s += sprintf( s, "a%u", revision );
+                       break;
+               
+               case kVersionStageBeta:
+                       s += sprintf( s, "b%u", revision );
+                       break;
+               
+               case kVersionStageFinal:
+                       
+                       // A non-release revision of zero is a special case indicating the software is GM (at the golden master 
+                       // stage) and therefore, the non-release revision should not be added to the string.
+                       
+                       if( revision != 0 )
+                       {
+                               s += sprintf( s, "f%u", revision );
+                       }
+                       break;
+               
+               default:
+                       dlog( kDebugLevelError, "invalid NumVersion stage (0x%02X)\n", stage );
+                       break;
+       }
+       return( inString );
+}
+
+//===========================================================================================================================
+//     DebugTaskLevel
+//===========================================================================================================================
+
+DEBUG_EXPORT uint32_t  DebugTaskLevel( void )
+{
+       uint32_t                level;
+       
+       level = 0;
+       
+#if( TARGET_OS_VXWORKS )
+       if( intContext() )
+       {
+               level |= ( ( 1 << kDebugInterruptLevelShift ) & kDebugInterruptLevelMask );
+       }
+#endif
+       
+       return( level );
+}
+
+#if( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
+//===========================================================================================================================
+//     DebugWinEnableConsole
+//===========================================================================================================================
+
+#pragma warning( disable:4311 )
+
+static void    DebugWinEnableConsole( void )
+{
+       static bool             sConsoleEnabled = false;
+       BOOL                    result;
+       int                             fileHandle;
+       FILE *                  file;
+       int                             err;
+       
+       if( sConsoleEnabled )
+       {
+               goto exit;
+       }
+       
+       // Create console window.
+       
+       result = AllocConsole();
+       require_quiet( result, exit );
+
+       // Redirect stdin to the console stdin.
+       
+       fileHandle = _open_osfhandle( (long) GetStdHandle( STD_INPUT_HANDLE ), _O_TEXT );
+       
+       #if( defined( __MWERKS__ ) )
+               file = __handle_reopen( (unsigned long) fileHandle, "r", stdin );
+               require_quiet( file, exit );
+       #else
+               file = _fdopen( fileHandle, "r" );
+               require_quiet( file, exit );
+       
+               *stdin = *file;
+       #endif
+       
+       err = setvbuf( stdin, NULL, _IONBF, 0 );
+       require_noerr_quiet( err, exit );
+       
+       // Redirect stdout to the console stdout.
+               
+       fileHandle = _open_osfhandle( (long) GetStdHandle( STD_OUTPUT_HANDLE ), _O_TEXT );
+       
+       #if( defined( __MWERKS__ ) )
+               file = __handle_reopen( (unsigned long) fileHandle, "w", stdout );
+               require_quiet( file, exit );
+       #else
+               file = _fdopen( fileHandle, "w" );
+               require_quiet( file, exit );
+               
+               *stdout = *file;
+       #endif
+       
+       err = setvbuf( stdout, NULL, _IONBF, 0 );
+       require_noerr_quiet( err, exit );
+       
+       // Redirect stderr to the console stdout.
+       
+       fileHandle = _open_osfhandle( (long) GetStdHandle( STD_OUTPUT_HANDLE ), _O_TEXT );
+       
+       #if( defined( __MWERKS__ ) )
+               file = __handle_reopen( (unsigned long) fileHandle, "w", stderr );
+               require_quiet( file, exit );
+       #else
+               file = _fdopen( fileHandle, "w" );
+               require_quiet( file, exit );
+       
+               *stderr = *file;
+       #endif
+       
+       err = setvbuf( stderr, NULL, _IONBF, 0 );
+       require_noerr_quiet( err, exit );
+       
+       sConsoleEnabled = true;
+       
+exit:
+       return;
+}
+
+#pragma warning( default:4311 )
+
+#endif // TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE
+
+#if( TARGET_OS_WIN32 )
+//===========================================================================================================================
+//     DebugWinCharToTCharString
+//===========================================================================================================================
+
+static TCHAR *
+       DebugWinCharToTCharString( 
+               const char *    inCharString, 
+               size_t                  inCharCount, 
+               TCHAR *                 outTCharString, 
+               size_t                  inTCharCountMax, 
+               size_t *                outTCharCount )
+{
+       const char *            src;
+       TCHAR *                         dst;
+       TCHAR *                         end;
+       
+       if( inCharCount == kSizeCString )
+       {
+               inCharCount = strlen( inCharString );
+       }
+       src = inCharString;
+       dst = outTCharString;
+       if( inTCharCountMax > 0 )
+       {
+               inTCharCountMax -= 1;
+               if( inTCharCountMax > inCharCount )
+               {
+                       inTCharCountMax = inCharCount;
+               }
+               
+               end = dst + inTCharCountMax;
+               while( dst < end )
+               {
+                       *dst++ = (TCHAR) *src++;
+               }
+               *dst = 0;
+       }
+       if( outTCharCount )
+       {
+               *outTCharCount = (size_t)( dst - outTCharString );
+       }
+       return( outTCharString );
+}
+#endif
+
+#if 0
+#pragma mark -
+#pragma mark == Debugging ==
+#endif
+
+//===========================================================================================================================
+//     DebugServicesTest
+//===========================================================================================================================
+
+DEBUG_EXPORT OSStatus  DebugServicesTest( void )
+{
+       OSStatus                err;
+       char                    s[ 512 ];
+       uint8_t *               p;
+       uint8_t                 data[] = 
+       {
+               0x11, 0x22, 0x33, 0x44, 
+               0x55, 0x66, 
+               0x77, 0x88, 0x99, 0xAA, 
+               0xBB, 0xCC, 0xDD, 
+               0xEE,
+               0xFF, 
+               0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 
+               0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, 0xA0, 
+               0x11, 0x21, 0x31, 0x41, 0x51, 0x61, 0x71, 0x81, 0x91, 0xA1 
+       };
+       
+       debug_initialize( kDebugOutputTypeMetaConsole );        
+       
+       // check's
+       
+       check( 0 && "SHOULD SEE: check" );
+       check( 1 && "SHOULD *NOT* SEE: check (valid)" );
+       check_string( 0, "SHOULD SEE: check_string" );
+       check_string( 1, "SHOULD *NOT* SEE: check_string (valid)" );
+       check_noerr( -123 );
+       check_noerr( 10038 );
+       check_noerr( 22 );
+       check_noerr( 0 );
+       check_noerr_string( -6712, "SHOULD SEE: check_noerr_string" );
+       check_noerr_string( 0, "SHOULD *NOT* SEE: check_noerr_string (valid)" );
+       check_translated_errno( 0 >= 0 && "SHOULD *NOT* SEE", -384, -999 );
+       check_translated_errno( -1 >= 0 && "SHOULD SEE", -384, -999 );
+       check_translated_errno( -1 >= 0 && "SHOULD SEE", 0, -999 );
+       check_ptr_overlap( "SHOULD *NOT* SEE" ? 10 : 0, 10, 22, 10 );
+       check_ptr_overlap( "SHOULD SEE" ? 10 : 0, 10,  5, 10 );
+       check_ptr_overlap( "SHOULD SEE" ? 10 : 0, 10, 12,  6 );
+       check_ptr_overlap( "SHOULD SEE" ? 12 : 0,  6, 10, 10 );
+       check_ptr_overlap( "SHOULD SEE" ? 12 : 0, 10, 10, 10 );
+       check_ptr_overlap( "SHOULD *NOT* SEE" ? 22 : 0, 10, 10, 10 );
+       check_ptr_overlap( "SHOULD *NOT* SEE" ? 10 : 0, 10, 20, 10 );
+       check_ptr_overlap( "SHOULD *NOT* SEE" ? 20 : 0, 10, 10, 10 );
+               
+       // require's
+       
+       require( 0 && "SHOULD SEE", require1 );
+       { err = kResponseErr; goto exit; }
+require1:
+       require( 1 && "SHOULD *NOT* SEE", require2 );
+       goto require2Good;
+require2:
+       { err = kResponseErr; goto exit; }
+require2Good:
+       require_string( 0 && "SHOULD SEE", require3, "SHOULD SEE: require_string" );
+       { err = kResponseErr; goto exit; }
+require3:
+       require_string( 1 && "SHOULD *NOT* SEE", require4, "SHOULD *NOT* SEE: require_string (valid)" );
+       goto require4Good;
+require4:
+       { err = kResponseErr; goto exit; }
+require4Good:
+       require_quiet( 0 && "SHOULD SEE", require5 );
+       { err = kResponseErr; goto exit; }
+require5:
+       require_quiet( 1 && "SHOULD *NOT* SEE", require6 );
+       goto require6Good;
+require6:
+       { err = kResponseErr; goto exit; }
+require6Good:
+       require_noerr( -1, require7 );
+       { err = kResponseErr; goto exit; }
+require7:
+       require_noerr( 0, require8 );
+       goto require8Good;
+require8:
+       { err = kResponseErr; goto exit; }
+require8Good:
+       require_noerr_string( -2, require9, "SHOULD SEE: require_noerr_string");
+       { err = kResponseErr; goto exit; }
+require9:
+       require_noerr_string( 0, require10, "SHOULD *NOT* SEE: require_noerr_string (valid)" );
+       goto require10Good;
+require10:
+       { err = kResponseErr; goto exit; }
+require10Good:
+       require_noerr_action_string( -3, require11, dlog( kDebugLevelMax, "action 1 (expected)\n" ), "require_noerr_action_string" );
+       { err = kResponseErr; goto exit; }
+require11:
+       require_noerr_action_string( 0, require12, dlog( kDebugLevelMax, "action 2\n" ), "require_noerr_action_string (valid)" );
+       goto require12Good;
+require12:
+       { err = kResponseErr; goto exit; }
+require12Good:
+       require_noerr_quiet( -4, require13 );
+       { err = kResponseErr; goto exit; }
+require13:
+       require_noerr_quiet( 0, require14 );
+       goto require14Good;
+require14:
+       { err = kResponseErr; goto exit; }
+require14Good:
+       require_noerr_action( -5, require15, dlog( kDebugLevelMax, "SHOULD SEE: action 3 (expected)\n" ) );
+       { err = kResponseErr; goto exit; }
+require15:
+       require_noerr_action( 0, require16, dlog( kDebugLevelMax, "SHOULD *NOT* SEE: action 4\n" ) );
+       goto require16Good;
+require16:
+       { err = kResponseErr; goto exit; }
+require16Good:
+       require_noerr_action_quiet( -4, require17, dlog( kDebugLevelMax, "SHOULD SEE: action 5 (expected)\n" ) );
+       { err = kResponseErr; goto exit; }
+require17:
+       require_noerr_action_quiet( 0, require18, dlog( kDebugLevelMax, "SHOULD *NOT* SEE: action 6\n" ) );
+       goto require18Good;
+require18:
+       { err = kResponseErr; goto exit; }
+require18Good:
+       require_action( 0 && "SHOULD SEE", require19, dlog( kDebugLevelMax, "SHOULD SEE: action 7 (expected)\n" ) );
+       { err = kResponseErr; goto exit; }
+require19:
+       require_action( 1 && "SHOULD *NOT* SEE", require20, dlog( kDebugLevelMax, "SHOULD *NOT* SEE: action 8\n" ) );
+       goto require20Good;
+require20:
+       { err = kResponseErr; goto exit; }
+require20Good:
+       require_action_quiet( 0, require21, dlog( kDebugLevelMax, "SHOULD SEE: action 9 (expected)\n" ) );
+       { err = kResponseErr; goto exit; }
+require21:
+       require_action_quiet( 1, require22, dlog( kDebugLevelMax, "SHOULD *NOT* SEE: action 10\n" ) );
+       goto require22Good;
+require22:
+       { err = kResponseErr; goto exit; }
+require22Good:
+       require_action_string( 0, require23, dlog( kDebugLevelMax, "SHOULD SEE: action 11 (expected)\n" ), "SHOULD SEE: require_action_string" );
+       { err = kResponseErr; goto exit; }
+require23:
+       require_action_string( 1, require24, dlog( kDebugLevelMax, "SHOULD *NOT* SEE: action 12\n" ), "SHOULD *NOT* SEE: require_action_string" );
+       goto require24Good;
+require24:
+       { err = kResponseErr; goto exit; }
+require24Good:
+
+#if( defined( __MWERKS__ )  )
+       #if( defined( __cplusplus ) && __option( exceptions ) )
+               #define COMPILER_HAS_EXCEPTIONS         1
+       #else
+               #define COMPILER_HAS_EXCEPTIONS         0
+       #endif
+#else
+       #if( defined( __cplusplus ) )
+               #define COMPILER_HAS_EXCEPTIONS         1
+       #else
+               #define COMPILER_HAS_EXCEPTIONS         0
+       #endif
+#endif
+
+#if( COMPILER_HAS_EXCEPTIONS )
+       try
+       {
+               require_throw( 1 && "SHOULD *NOT* SEE" );
+               require_throw( 0 && "SHOULD SEE" );
+       }
+       catch( ... )
+       {
+               goto require26Good;
+       }
+       { err = kResponseErr; goto exit; }
+require26Good:
+#endif
+
+       // translate_errno
+       
+       err = translate_errno( 1 != -1, -123, -567 );
+       require( ( err == 0 ) && "SHOULD *NOT* SEE", exit );
+       
+       err = translate_errno( -1 != -1, -123, -567 );
+       require( ( err == -123 ) && "SHOULD *NOT* SEE", exit );
+       
+       err = translate_errno( -1 != -1, 0, -567 );
+       require( ( err == -567 ) && "SHOULD *NOT* SEE", exit );
+
+       // debug_string
+       
+       debug_string( "debug_string" );
+       
+       // DebugSNPrintF
+       
+       DebugSNPrintF( s, sizeof( s ), "%d", 1234 );
+       require_action( strcmp( s, "1234" ) == 0, exit, err = -1 );
+       
+       DebugSNPrintF( s, sizeof( s ), "%X", 0x2345 );
+       require_action( strcmp( s, "2345" ) == 0, exit, err = -1 );
+       
+       DebugSNPrintF( s, sizeof( s ), "%#s", "\05test" );
+       require_action( strcmp( s, "test" ) == 0, exit, err = -1 );
+       
+       DebugSNPrintF( s, sizeof( s ), "%##s", "\03www\05apple\03com" );
+       require_action( strcmp( s, "www.apple.com." ) == 0, exit, err = -1 );
+       
+       DebugSNPrintF( s, sizeof( s ), "%ld", (long) INT32_C( 2147483647 ) );
+       require_action( strcmp( s, "2147483647" ) == 0, exit, err = -1 );
+       
+       DebugSNPrintF( s, sizeof( s ), "%lu", (unsigned long) UINT32_C( 4294967295 ) );
+       require_action( strcmp( s, "4294967295" ) == 0, exit, err = -1 );
+       
+       #if( TYPE_LONGLONG_NATIVE )
+               DebugSNPrintF( s, sizeof( s ), "%lld", (long_long_compat) INT64_C( 9223372036854775807 ) );
+               require_action( strcmp( s, "9223372036854775807" ) == 0, exit, err = -1 );
+               
+               DebugSNPrintF( s, sizeof( s ), "%lld", (long_long_compat) INT64_C( -9223372036854775807 ) );
+               require_action( strcmp( s, "-9223372036854775807" ) == 0, exit, err = -1 );
+               
+               DebugSNPrintF( s, sizeof( s ), "%llu", (unsigned_long_long_compat) UINT64_C( 18446744073709551615 ) );
+               require_action( strcmp( s, "18446744073709551615" ) == 0, exit, err = -1 );
+       #endif
+       
+       DebugSNPrintF( s, sizeof( s ), "%lb", (unsigned long) binary_32( 01111011, 01111011, 01111011, 01111011 ) );
+       require_action( strcmp( s, "1111011011110110111101101111011" ) == 0, exit, err = -1 );
+       
+       DebugSNPrintF( s, sizeof( s ), "%C", 0x41624364 );      // 'AbCd'
+       require_action( strcmp( s, "AbCd" ) == 0, exit, err = -1 );
+       
+       #if( defined( MDNS_DEBUGMSGS ) )
+       {
+               mDNSAddr                maddr;
+               
+               memset( &maddr, 0, sizeof( maddr ) );
+               maddr.type = mDNSAddrType_IPv4;
+               maddr.ip.v4.b[ 0 ] = 127;
+               maddr.ip.v4.b[ 1 ] = 0;
+               maddr.ip.v4.b[ 2 ] = 0;
+               maddr.ip.v4.b[ 3 ] = 1;
+               DebugSNPrintF( s, sizeof( s ), "%#a", &maddr );
+               require_action( strcmp( s, "127.0.0.1" ) == 0, exit, err = -1 );
+               
+               memset( &maddr, 0, sizeof( maddr ) );
+               maddr.type = mDNSAddrType_IPv6;
+               maddr.ip.v6.b[  0 ]     = 0xFE;
+               maddr.ip.v6.b[  1 ]     = 0x80;
+               maddr.ip.v6.b[ 15 ]     = 0x01;
+               DebugSNPrintF( s, sizeof( s ), "%#a", &maddr );
+               require_action( strcmp( s, "FE80:0000:0000:0000:0000:0000:0000:0001" ) == 0, exit, err = -1 );
+       }
+       #endif
+       
+       #if( AF_INET )
+       {
+               struct sockaddr_in              sa4;
+               
+               memset( &sa4, 0, sizeof( sa4 ) );
+               sa4.sin_family          = AF_INET;
+               p                                       = (uint8_t *) &sa4.sin_port;
+               p[ 0 ]                          = (uint8_t)( ( 80 >> 8 ) & 0xFF );
+               p[ 1 ]                          = (uint8_t)(   80        & 0xFF );
+               p                                       = (uint8_t *) &sa4.sin_addr.s_addr;
+               p[ 0 ]                          = (uint8_t)( ( INADDR_LOOPBACK >> 24 ) & 0xFF );
+               p[ 1 ]                          = (uint8_t)( ( INADDR_LOOPBACK >> 16 ) & 0xFF );
+               p[ 2 ]                          = (uint8_t)( ( INADDR_LOOPBACK >>  8 ) & 0xFF );
+               p[ 3 ]                          = (uint8_t)(   INADDR_LOOPBACK         & 0xFF );
+               DebugSNPrintF( s, sizeof( s ), "%##a", &sa4 );
+               require_action( strcmp( s, "127.0.0.1:80" ) == 0, exit, err = -1 );
+       }
+       #endif
+       
+       #if( AF_INET6 )
+       {
+               struct sockaddr_in6             sa6;
+               
+               memset( &sa6, 0, sizeof( sa6 ) );
+               sa6.sin6_family                         = AF_INET6;
+               p                                                       = (uint8_t *) &sa6.sin6_port;
+               p[ 0 ]                                          = (uint8_t)( ( 80 >> 8 ) & 0xFF );
+               p[ 1 ]                                          = (uint8_t)(   80        & 0xFF );
+               sa6.sin6_addr.s6_addr[  0 ]     = 0xFE;
+               sa6.sin6_addr.s6_addr[  1 ]     = 0x80;
+               sa6.sin6_addr.s6_addr[ 15 ]     = 0x01;
+               sa6.sin6_scope_id                       = 2;
+               DebugSNPrintF( s, sizeof( s ), "%##a", &sa6 );
+               require_action( strcmp( s, "[FE80:0000:0000:0000:0000:0000:0000:0001%2]:80" ) == 0, exit, err = -1 );
+       }
+       #endif
+       
+       // Unicode
+
+       DebugSNPrintF(s, sizeof(s), "%.*s", 4, "tes" );
+       require_action( strcmp( s, "tes" ) == 0, exit, err = kResponseErr );
+       
+       DebugSNPrintF(s, sizeof(s), "%.*s", 4, "test" );
+       require_action( strcmp( s, "test" ) == 0, exit, err = kResponseErr );
+       
+       DebugSNPrintF(s, sizeof(s), "%.*s", 4, "testing" );
+       require_action( strcmp( s, "test" ) == 0, exit, err = kResponseErr );
+       
+       DebugSNPrintF(s, sizeof(s), "%.*s", 4, "te\xC3\xA9" );
+       require_action( strcmp( s, "te\xC3\xA9" ) == 0, exit, err = kResponseErr );
+       
+       DebugSNPrintF(s, sizeof(s), "%.*s", 4, "te\xC3\xA9ing" );
+       require_action( strcmp( s, "te\xC3\xA9" ) == 0, exit, err = kResponseErr );
+       
+       DebugSNPrintF(s, sizeof(s), "%.*s", 4, "tes\xC3\xA9ing" );
+       require_action( strcmp( s, "tes" ) == 0, exit, err = kResponseErr );
+       
+       DebugSNPrintF(s, sizeof(s), "%.*s", 4, "t\xed\x9f\xbf" );
+       require_action( strcmp( s, "t\xed\x9f\xbf" ) == 0, exit, err = kResponseErr );
+       
+       DebugSNPrintF(s, sizeof(s), "%.*s", 4, "t\xed\x9f\xbfing" );
+       require_action( strcmp( s, "t\xed\x9f\xbf" ) == 0, exit, err = kResponseErr );
+       
+       DebugSNPrintF(s, sizeof(s), "%.*s", 4, "te\xed\x9f\xbf" );
+       require_action( strcmp( s, "te" ) == 0, exit, err = kResponseErr );
+       
+       DebugSNPrintF(s, sizeof(s), "%.*s", 4, "te\xed\x9f\xbfing" );
+       require_action( strcmp( s, "te" ) == 0, exit, err = kResponseErr );
+       
+       DebugSNPrintF(s, sizeof(s), "%.*s", 7, "te\xC3\xA9\xed\x9f\xbfing" );
+       require_action( strcmp( s, "te\xC3\xA9\xed\x9f\xbf" ) == 0, exit, err = kResponseErr );
+       
+       DebugSNPrintF(s, sizeof(s), "%.*s", 6, "te\xC3\xA9\xed\x9f\xbfing" );
+       require_action( strcmp( s, "te\xC3\xA9" ) == 0, exit, err = kResponseErr );
+       
+       DebugSNPrintF(s, sizeof(s), "%.*s", 5, "te\xC3\xA9\xed\x9f\xbfing" );
+       require_action( strcmp( s, "te\xC3\xA9" ) == 0, exit, err = kResponseErr );
+
+       #if( TARGET_RT_BIG_ENDIAN )
+               DebugSNPrintF( s, sizeof( s ), "%S", "\x00" "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" "\x00" );
+               require_action( strcmp( s, "abcd" ) == 0, exit, err = -1 );
+       #else
+               DebugSNPrintF( s, sizeof( s ), "%S", "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" "\x00" "\x00" );
+               require_action( strcmp( s, "abcd" ) == 0, exit, err = -1 );
+       #endif
+       
+       DebugSNPrintF( s, sizeof( s ), "%S", 
+               "\xFE\xFF" "\x00" "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" "\x00" ); // Big Endian BOM
+       require_action( strcmp( s, "abcd" ) == 0, exit, err = -1 );
+       
+       DebugSNPrintF( s, sizeof( s ), "%S", 
+               "\xFF\xFE" "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" "\x00" "\x00" ); // Little Endian BOM
+       require_action( strcmp( s, "abcd" ) == 0, exit, err = -1 );
+       
+       DebugSNPrintF( s, sizeof( s ), "%#S", "\x00" "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" "\x00" );      // Big Endian
+       require_action( strcmp( s, "abcd" ) == 0, exit, err = -1 );
+       
+       DebugSNPrintF( s, sizeof( s ), "%##S", "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" "\x00" "\x00" );     // Little Endian
+       require_action( strcmp( s, "abcd" ) == 0, exit, err = -1 );
+       
+       DebugSNPrintF( s, sizeof( s ), "%.*S", 
+               4, "\xFE\xFF" "\x00" "a" "\x00" "b" "\x00" "c" "\x00" "d" );    // Big Endian BOM
+       require_action( strcmp( s, "abc" ) == 0, exit, err = -1 );
+       
+       DebugSNPrintF( s, sizeof( s ), "%.*S", 
+               4, "\xFF\xFE" "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" );    // Little Endian BOM
+       require_action( strcmp( s, "abc" ) == 0, exit, err = -1 );
+       
+       #if( TARGET_RT_BIG_ENDIAN )
+               DebugSNPrintF( s, sizeof( s ), "%.*S", 3, "\x00" "a" "\x00" "b" "\x00" "c" "\x00" "d" );
+               require_action( strcmp( s, "abc" ) == 0, exit, err = -1 );
+       #else
+               DebugSNPrintF( s, sizeof( s ), "%.*S", 3, "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" );
+               require_action( strcmp( s, "abc" ) == 0, exit, err = -1 );
+       #endif
+       
+       DebugSNPrintF( s, sizeof( s ), "%#.*S", 3, "\x00" "a" "\x00" "b" "\x00" "c" "\x00" "d" );       // Big Endian
+       require_action( strcmp( s, "abc" ) == 0, exit, err = -1 );
+       
+       DebugSNPrintF( s, sizeof( s ), "%##.*S", 3, "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" );      // Little Endian
+       require_action( strcmp( s, "abc" ) == 0, exit, err = -1 );
+       
+       // Misc
+       
+       DebugSNPrintF( s, sizeof( s ), "%U", "\x10\xb8\xa7\x6b" "\xad\x9d" "\xd1\x11" "\x80\xb4" "\x00\xc0\x4f\xd4\x30\xc8" );
+       require_action( strcmp( s, "6ba7b810-9dad-11d1-80b4-00c04fd430c8" ) == 0, exit, err = -1 );
+       
+       DebugSNPrintF( s, sizeof( s ), "%m", 0 );
+       require_action( strcmp( s, "no error" ) == 0, exit, err = -1 );
+       
+       DebugSNPrintF( s, sizeof( s ), "%lm", (long) 0 );
+       require_action( strcmp( s, "no error" ) == 0, exit, err = -1 );
+       
+       DebugSNPrintF( s, sizeof( s ), "\"%H\"", "\x6b\xa7\xb8\x10\x9d\xad\x11\xd1\x80\xb4\x00\xc0\x4f\xd4\x30\xc8", 16, 16 );
+       DebugPrintF( kDebugLevelMax, "%s\n\n", s );
+       
+       DebugSNPrintF( s, sizeof( s ), "\"%H\"", 
+               "\x6b\xa7\xb8\x10\x9d\xad\x11\xd1\x80\xb4\x00\xc0\x4f\xd4\x30\xc8"
+               "\x6b\xa7\xb8\x10\x9d\xad\x11\xd1\x80\xb4\x00\xc0\x4f\xd4\x30\xc8", 
+               32, 32 );
+       DebugPrintF( kDebugLevelMax, "%s\n\n", s );
+       
+       DebugSNPrintF( s, sizeof( s ), "\"%H\"", "\x6b\xa7", 2, 2 );
+       DebugPrintF( kDebugLevelMax, "%s\n\n", s );
+       
+       // Hex Dumps
+       
+       s[ 0 ] = '\0';
+       DebugHexDump( kDebugLevelMax, 0, "My Label", kSizeCString, 0, NULL, 0, data, data, sizeof( data ), 
+               kDebugFlagsNone, s, sizeof( s ) );
+       DebugPrintF( kDebugLevelMax, "%s\n", s );
+       
+       s[ 0 ] = '\0';
+       DebugHexDump( kDebugLevelMax, 0, NULL, 0, 0, NULL, 0, data, data, sizeof( data ), 
+               kDebugFlagsNoAddress | kDebugFlagsNoOffset, s, sizeof( s ) );
+       DebugPrintF( kDebugLevelMax, "%s\n", s );
+       
+       s[ 0 ] = '\0';
+       DebugHexDump( kDebugLevelMax, 0, "My Label", kSizeCString, 0, NULL, 0, data, data, sizeof( data ), 
+               kDebugFlagsNoAddress | kDebugFlagsNoOffset, s, sizeof( s ) );
+       DebugPrintF( kDebugLevelMax, "%s\n", s );
+       
+       s[ 0 ] = '\0';
+       DebugHexDump( kDebugLevelMax, 0, "My Label", kSizeCString, 0, NULL, 0, data, data, sizeof( data ), 
+               kDebugFlagsNoAddress, s, sizeof( s ) );
+       DebugPrintF( kDebugLevelMax, "%s\n", s );
+       
+       s[ 0 ] = '\0';
+       DebugHexDump( kDebugLevelMax, 0, NULL, 0, 0, NULL, 0, data, data, sizeof( data ), 
+               kDebugFlagsNoOffset, s, sizeof( s ) );
+       DebugPrintF( kDebugLevelMax, "%s\n", s );
+       
+       s[ 0 ] = '\0';
+       DebugHexDump( kDebugLevelMax, 0, NULL, 0, 0, NULL, 0, data, data, sizeof( data ), 
+               kDebugFlagsNoAddress, s, sizeof( s ) );
+       DebugPrintF( kDebugLevelMax, "%s\n", s );
+       
+       s[ 0 ] = '\0';
+       DebugHexDump( kDebugLevelMax, 0, NULL, 0, 0, NULL, 0, data, data, sizeof( data ), 
+               kDebugFlagsNoOffset, s, sizeof( s ) );
+       DebugPrintF( kDebugLevelMax, "%s\n", s );
+       
+       s[ 0 ] = '\0';
+       DebugHexDump( kDebugLevelMax, 0, NULL, 0, 0, NULL, 0, data, data, sizeof( data ), 
+               kDebugFlagsNoByteCount, s, sizeof( s ) );
+       DebugPrintF( kDebugLevelMax, "%s\n", s );
+       
+       s[ 0 ] = '\0';
+       DebugHexDump( kDebugLevelMax, 0, NULL, 0, 0, NULL, 0, "\x41\x62\x43\x64", "\x41\x62\x43\x64", 4,        // 'AbCd'
+               kDebugFlagsNoAddress | kDebugFlagsNoOffset | kDebugFlagsNoNewLine |
+               kDebugFlagsNo32BitSeparator | kDebugFlagsNo16ByteHexPad | kDebugFlagsNoByteCount, 
+               s, sizeof( s ) );
+       DebugPrintF( kDebugLevelMax, "%s\n", s );
+       
+       s[ 0 ] = '\0';
+       DebugHexDump( kDebugLevelMax, 0, NULL, 0, 0, NULL, 0, data, data, sizeof( data ), 
+               kDebugFlagsNoAddress | kDebugFlagsNoOffset | kDebugFlagsNoASCII | kDebugFlagsNoNewLine |
+               kDebugFlags16BitSeparator | kDebugFlagsNo32BitSeparator |
+               kDebugFlagsNo16ByteHexPad | kDebugFlagsNoByteCount, s, sizeof( s ) );
+       DebugPrintF( kDebugLevelMax, "%s\n", s );
+       
+       s[ 0 ] = '\0';
+       DebugHexDump( kDebugLevelMax, 8, NULL, 0, 0, NULL, 0, data, data, sizeof( data ), kDebugFlagsNone, s, sizeof( s ) );
+       DebugPrintF( kDebugLevelMax, "%s\n", s );
+       
+       // dlog's
+       
+       dlog( kDebugLevelNotice, "dlog\n" );
+       dlog( kDebugLevelNotice, "dlog integer: %d\n", 123 );
+       dlog( kDebugLevelNotice, "dlog string:  \"%s\"\n", "test string" );
+       dlogmem( kDebugLevelNotice, data, sizeof( data ) );
+       
+       // Done
+       
+       DebugPrintF( kDebugLevelMax, "\n\nALL TESTS DONE\n\n" );
+       err = kNoErr;
+       
+exit:
+       if( err )
+       {
+               DebugPrintF( kDebugLevelMax, "\n\n### TEST FAILED ###\n\n" );
+       }
+       return( err );
+}
+
+#endif // DEBUG
diff --git a/mDNSWindows/DebugServices.h b/mDNSWindows/DebugServices.h
new file mode 100644 (file)
index 0000000..fd914ee
--- /dev/null
@@ -0,0 +1,1633 @@
+/*
+ * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+    
+$Log: DebugServices.h,v $
+Revision 1.4  2004/04/15 08:59:08  bradley
+Removed deprecated debug and log levels and replaced them with modern equivalents.
+
+Revision 1.3  2004/04/08 09:29:55  bradley
+Manually do host->network byte order conversion to avoid needing libraries for htons/htonl. Changed
+hex dumps to better separate hex and ASCII. Added support for %.8a syntax in DebugSNPrintF for Fibre
+Channel addresses (00:11:22:33:44:55:66:77). Fixed a few places where HeaderDoc was incorrect.
+
+Revision 1.2  2004/03/07 05:59:34  bradley
+Sync'd with internal version: Added expect macros, error codes, and CoreServices exclusion.
+
+Revision 1.1  2004/01/30 02:27:30  bradley
+Debugging support for various platforms.
+
+*/
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @header         DebugServices
+
+       Debugging Library
+*/
+
+#ifndef        __DEBUG_SERVICES__
+#define        __DEBUG_SERVICES__
+
+#include       <stdarg.h>
+
+#include       "CommonServices.h"
+
+#if( TARGET_OS_VXWORKS )
+       #include        "logLib.h"
+#endif
+
+#if 0
+#pragma mark == Settings ==
+#endif
+
+//===========================================================================================================================
+//     Settings
+//===========================================================================================================================
+
+// General
+
+#if( !defined( DEBUG ) )
+       #define DEBUG           0
+#endif
+
+#if( defined( NDEBUG ) && DEBUG )
+       #error NDEBUG defined and DEBUG is also enabled...they need to be in-sync
+#endif
+       
+// AssertMacros.h/Debugging.h overrides.
+
+#if( !defined( DEBUG_OVERRIDE_APPLE_MACROS ) )
+       #define DEBUG_OVERRIDE_APPLE_MACROS             1
+#endif
+
+// Routine name. Uses ISO __func__ where possible. Otherwise, uses the best thing that is available (if anything).
+
+#if( defined( __MWERKS__ ) || ( __GNUC__ > 2 ) || ( ( __GNUC__ == 2 ) && ( __GNUC_MINOR__ >= 9 ) ) )
+       #define __ROUTINE__                                     __func__
+#elif( defined( __GNUC__ ) )
+       #define __ROUTINE__                                     __PRETTY_FUNCTION__
+#elif( defined( _MSC_VER ) && !defined( _WIN32_WCE ) )
+       #define __ROUTINE__                                     __FUNCTION__
+#else
+       #define __ROUTINE__                                     ""
+#endif
+
+// Variable argument macro support. Use ANSI C99 __VA_ARGS__ where possible. Otherwise, use the next best thing.
+
+#if( defined( __GNUC__ ) )
+       #if( ( __GNUC__ > 3 ) || ( ( __GNUC__ == 3 ) && ( __GNUC_MINOR__ >= 3) ) )
+               #define DEBUG_C99_VA_ARGS               1
+               #define DEBUG_GNU_VA_ARGS               0
+       #else
+               #define DEBUG_C99_VA_ARGS               0
+               #define DEBUG_GNU_VA_ARGS               1
+       #endif
+#elif( defined( __MWERKS__ ) )
+       #define DEBUG_C99_VA_ARGS                       1
+       #define DEBUG_GNU_VA_ARGS                       0
+#else
+       #define DEBUG_C99_VA_ARGS                       0
+       #define DEBUG_GNU_VA_ARGS                       0
+#endif
+
+#if 0
+#pragma mark == Output ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        DEBUG_FPRINTF_ENABLED
+       
+       @abstract       Enables ANSI C fprintf output.
+*/
+
+#if( !defined( DEBUG_FPRINTF_ENABLED ) )
+       #if( !TARGET_API_MAC_OSX_KERNEL && !TARGET_OS_WINDOWS_CE )
+               #define DEBUG_FPRINTF_ENABLED                   1
+       #else
+               #define DEBUG_FPRINTF_ENABLED                   0
+       #endif
+#else
+       #if( TARGET_API_MAC_OSX_KERNEL || TARGET_OS_WINDOWS_CE )
+               #error fprintf enabled, but not supported on Mac OS X kernel or Windows CE
+       #endif
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        DEBUG_MAC_OS_X_IOLOG_ENABLED
+       
+       @abstract       Enables IOLog (Mac OS X Kernel) output.
+*/
+
+#if( !defined( DEBUG_MAC_OS_X_IOLOG_ENABLED ) )
+       #define DEBUG_MAC_OS_X_IOLOG_ENABLED            TARGET_API_MAC_OSX_KERNEL
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        DEBUG_KPRINTF_ENABLED
+       
+       @abstract       Enables kprintf (Mac OS X Kernel) output.
+*/
+
+#if( !defined( DEBUG_KPRINTF_ENABLED ) )
+       #define DEBUG_KPRINTF_ENABLED                           TARGET_API_MAC_OSX_KERNEL
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        DEBUG_IDEBUG_ENABLED
+       
+       @abstract       Enables iDebug (Mac OS X user and Kernel) output.
+       
+       @discussion
+       
+       For Mac OS X kernel development, iDebug is enabled by default because we can dynamically check for the presence 
+       of iDebug via some exported IOKit symbols. Mac OS X app usage doesn't allow dynamic detection because it relies
+       on statically linking to the iDebugServices.cp file so for Mac OS X app usage, you have to manually enable iDebug.
+*/
+
+#if( !defined( DEBUG_IDEBUG_ENABLED ) )
+       #define DEBUG_IDEBUG_ENABLED                            TARGET_API_MAC_OSX_KERNEL
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        DEBUG_CORE_SERVICE_ASSERTS_ENABLED
+       
+       @abstract       Controls whether Core Services assert handling is enabled. Enabling requires CoreServices framework.
+*/
+
+#if( !defined( DEBUG_CORE_SERVICE_ASSERTS_ENABLED ) )
+       #if( defined( __DEBUGGING__ ) )
+               #define DEBUG_CORE_SERVICE_ASSERTS_ENABLED              1
+       #else
+               #define DEBUG_CORE_SERVICE_ASSERTS_ENABLED              0
+       #endif
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @typedef        DebugOutputType
+       
+       @abstract       Type of debug output (i.e. where the output goes).
+*/
+
+typedef uint32_t                       DebugOutputType;
+
+#define kDebugOutputTypeNone                           0x6E6F6E65U     // 'none' - no params
+#define kDebugOutputTypeCustom                         0x63757374U     // 'cust' - 1st param = function ptr, 2nd param = context
+#define kDebugOutputTypeFPrintF                                0x66707269U     // 'fpri' - 1st param = DebugOutputTypeFlags [, 2nd param = filename]
+#define kDebugOutputTypeiDebug                         0x69646267U     // 'idbg' - no params
+#define kDebugOutputTypeKPrintF                                0x6B707266U     // 'kprf' - no params
+#define kDebugOutputTypeMacOSXIOLog                    0x696C6F67U     // 'ilog' - no params 
+#define kDebugOutputTypeMacOSXLog                      0x786C6F67U     // 'xlog' - no params
+#define kDebugOutputTypeWindowsDebugger                0x77696E64U     // 'wind' - no params
+#define kDebugOutputTypeWindowsEventLog                0x7765766CU     // 'wevl' - 1st param = C-string name, 2nd param = HMODULE or NULL.
+
+// Console meta output kind - Any kind of Console output (in horizontal order of preference):
+// 
+// Mac OS X                    = ANSI printf (viewable in Console.app)
+// Mac OS X Kernel     = IOLog (/var/log/system.log) or kprintf (serial).
+// Windows                     = ANSI printf (Console window) or OutputDebugString (debugger).
+// Other                       = ANSI printf (viewer varies).
+
+#define kDebugOutputTypeMetaConsole                    0x434F4E53U     // 'CONS' - no params
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @typedef        DebugOutputTypeFlags
+       
+       @abstract       Flags controlling how the output type is configured.
+       
+       @constant       kDebugOutputTypeFlagsTypeMask   Bit mask for the output type (e.g. stdout, stderr, file, etc.).
+       @constant       kDebugOutputTypeFlagsStdOut             fprintf should go to stdout.
+       @constant       kDebugOutputTypeFlagsStdErr             fprintf should go to stderr.
+       @constant       kDebugOutputTypeFlagsFile               fprintf should go to a specific file (filename passed as va_arg).
+*/
+
+typedef unsigned int           DebugOutputTypeFlags;
+
+#define        kDebugOutputTypeFlagsTypeMask   0xF
+#define        kDebugOutputTypeFlagsStdOut             1
+#define        kDebugOutputTypeFlagsStdErr             2
+#define        kDebugOutputTypeFlagsFile               10
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @typedef        DebugOutputFunctionPtr
+       
+       @abstract       Function ptr for a custom callback to print debug output.
+*/
+
+typedef void ( *DebugOutputFunctionPtr )( char *inData, size_t inSize, void *inContext );
+
+//===========================================================================================================================
+//     Constants
+//===========================================================================================================================
+
+#if 0
+#pragma mark == Flags ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @typedef        DebugFlags
+       
+       @abstract       Flags controlling how output is printed.
+*/
+
+typedef uint32_t               DebugFlags;
+
+#define        kDebugFlagsNone                                 0
+#define        kDebugFlagsNoAddress                    ( 1 << 0 )
+#define        kDebugFlagsNoOffset                             ( 1 << 1 )
+#define        kDebugFlags32BitOffset                  ( 1 << 2 )
+#define        kDebugFlagsNoASCII                              ( 1 << 3 )
+#define        kDebugFlagsNoNewLine                    ( 1 << 4 )
+#define        kDebugFlags8BitSeparator                ( 1 << 5 )
+#define        kDebugFlags16BitSeparator               ( 1 << 6 )
+#define        kDebugFlagsNo32BitSeparator             ( 1 << 7 )
+#define        kDebugFlagsNo16ByteHexPad               ( 1 << 8 )
+#define        kDebugFlagsNoByteCount                  ( 1 << 9 )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @enum           DebugTaskLevelFlags
+       
+       @abstract       Flags indicating the task level.
+*/
+
+enum
+{
+       kDebugInterruptLevelShift                               = 0, 
+       kDebugInterruptLevelMask                                = 0x00000007,
+       kDebugInVBLTaskMask                                             = 0x00000010,
+       kDebugInDeferredTaskMask                                = 0x00000020,
+    kDebugInSecondaryInterruptHandlerMask      = 0x00000040, 
+       kDebugPageFaultFatalMask                                = 0x00000100,   // There should be a "kPageFaultFatalMask" in Debugging.h.
+       kDebugMPTaskLevelMask                                   = 0x00000200,   // There should be a "kMPTaskLevelMask" in Debugging.h.
+       kDebugInterruptDepthShift                               = 16, 
+       kDebugInterruptDepthMask                                = 0x00FF0000
+};
+
+#define        DebugExtractTaskLevelInterruptLevel( LEVEL )    \
+       ( ( ( LEVEL ) & kDebugInterruptLevelMask ) >> kDebugInterruptLevelShift )
+       
+#define        DebugExtractTaskLevelInterruptDepth( LEVEL )    \
+       ( ( ( LEVEL ) & kDebugInterruptDepthMask ) >> kDebugInterruptDepthShift )
+
+#if 0
+#pragma mark == Levels ==
+#endif
+
+//===========================================================================================================================
+//     Constants & Types - Levels
+//===========================================================================================================================
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @typedef        DebugLevel
+       
+       @abstract       Level used to control debug logging.
+*/
+
+typedef int32_t                        DebugLevel;
+
+// Levels
+
+#define kDebugLevelMask                                        0x0000FFFF
+#define kDebugLevelChatty                              100
+#define kDebugLevelVerbose                             500
+#define kDebugLevelTrace                               800
+#define kDebugLevelInfo                                1000
+#define kDebugLevelNotice                              3000
+#define kDebugLevelWarning                             5000
+#define kDebugLevelAssert                              6000
+#define kDebugLevelRequire                             7000
+#define kDebugLevelError                               8000
+#define kDebugLevelCritical                            9000
+#define kDebugLevelAlert                               10000
+#define kDebugLevelEmergency                   11000
+#define kDebugLevelTragic                              12000
+#define kDebugLevelMax                                 0x0000FFFF
+
+// Level Flags
+       
+#define kDebugLevelFlagMask                            0xFFFF0000
+#define kDebugLevelFlagStackTrace              0x00010000
+#define kDebugLevelFlagDebugBreak              0x00020000
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @typedef        LogLevel
+       
+       @abstract       Level used to control which events are logged.
+*/
+
+typedef int32_t                                                LogLevel;
+
+#define        kLogLevelUninitialized          -1L
+#define kLogLevelAll                           0L
+#define kLogLevelChatty                                100L
+#define kLogLevelVerbose                       500L
+#define kLogLevelTrace                                 800L
+#define kLogLevelInfo                          1000L
+#define kLogLevelNotice                                3000L
+#define kLogLevelWarning                       4000L
+#define kLogLevelAssert                        6000L
+#define kLogLevelRequire                       7000L
+#define kLogLevelError                         8000L
+#define kLogLevelCritical                      9000L
+#define kLogLevelAlert                         10000L
+#define kLogLevelEmergency                     11000L
+#define kLogLevelTragic                                12000L
+#define kLogLevelOff                           0x0000FFFEL
+
+#if 0
+#pragma mark == Properties ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @typedef        DebugPropertyTag
+       
+       @abstract       Tag for properties.
+*/
+
+typedef uint32_t               DebugPropertyTag;
+
+#define        kDebugPropertyTagPrintLevelMin          0x6D696E70U             // 'minp'       Get: 1st param = DebugLevel *
+                                                                                                                       //                      Set: 1st param = DebugLevel
+
+#define        kDebugPropertyTagPrintLevel                     kDebugPropertyTagPrintLevelMin
+
+#define        kDebugPropertyTagPrintLevelMax          0x706D786CU             // 'maxp'       Get: 1st param = DebugLevel *
+                                                                                                                       //                      Set: 1st param = DebugLevel
+
+#define        kDebugPropertyTagBreakLevel                     0x62726B6CU             // 'brkl'       Get: 1st param = DebugLevel *
+                                                                                                                       //                      Set: 1st param = DebugLevel
+#if 0
+#pragma mark == General macros ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        DEBUG_UNUSED
+       
+       @abstract       Macro to mark a paramter as unused to avoid unused parameter warnings.
+       
+       @discussion     
+       
+       There is no universally supported pragma/attribute for indicating a variable is unused. DEBUG_UNUSED lets us
+       indicate a variable is unused in a manner that is supported by most compilers.
+*/
+
+#define        DEBUG_UNUSED( X )                       (void)( X )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        DEBUG_USE_ONLY
+       
+       @abstract       Macro to mark a variable as used only when debugging is enabled.
+       
+       @discussion     
+       
+       Variables are sometimes needed only for debugging. When debugging is turned off, these debug-only variables generate 
+       compiler warnings about unused variables. To eliminate these warnings, use these macros to indicate variables that 
+       are only used for debugging.
+*/
+
+#if( DEBUG )
+       #define DEBUG_USE_ONLY( X )
+#else
+       #define DEBUG_USE_ONLY( X )             (void)( X )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        DEBUG_LOCAL
+       
+       @abstract       Macros to make variables and functions static when debugging is off, but extern when debugging is on.
+       
+       @discussion     
+       
+       Rather than using "static" directly, using this macros allows you to access these variables external while 
+       debugging without being penalized for production builds.
+*/
+
+#if( DEBUG )
+       #define DEBUG_LOCAL
+#else
+       #define DEBUG_LOCAL                     static
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        DEBUG_STATIC
+       
+       @abstract       Macros to make variables and functions static when debugging is off, but extern when debugging is on.
+       
+       @discussion     
+       
+       Rather than using "static" directly, using this macros allows you to access these variables external while 
+       debugging without being penalized for production builds.
+*/
+
+#if( DEBUG )
+       #define DEBUG_STATIC
+#else
+       #define DEBUG_STATIC    static
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        DEBUG_EXPORT
+       
+       @abstract       Macros to export variables.
+       
+       @discussion     
+       
+       "__private_extern__" is a hack for IOKit to allow symbols to be exported from compilation units, but 
+       // not exported outside a driver (IOKit uses a lame global namespace for symbols). This still does not 
+       // solve the problem of multiple drivers in the same dependency chain since they share symbols.
+*/
+
+#if( TARGET_API_MAC_OSX_KERNEL )
+       #define DEBUG_EXPORT            __private_extern__
+#else
+       #define DEBUG_EXPORT            extern
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        debug_add
+       
+       @abstract       Macro to add (or subtract if negative) a value when debugging is on. Does nothing if debugging is off.
+*/
+
+#if( DEBUG )
+       #define debug_add( A, B )               ( A ) += ( B )
+#else
+       #define debug_add( A, B )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        debug_perform
+       
+       @abstract       Macro to perform something in debug-only builds.
+*/
+
+#if( DEBUG )
+       #define debug_perform( X )              do { X; } while( 0 )
+#else
+       #define debug_perform( X )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       translate_errno
+
+       @abstract       Returns 0 if the test success. If the test fails, returns errno if non-zero and othewise the alternate error.
+*/
+
+#define translate_errno( TEST, ERRNO, ALTERNATE_ERROR )                ( ( TEST ) ? 0 : ( ERRNO ) ? ( ERRNO ) : ( ALTERNATE_ERROR ) )
+
+#if 0
+#pragma mark == Compile Time macros ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        check_compile_time
+       
+       @abstract       Performs a compile-time check of something such as the size of an int.
+       
+       @discussion     
+       
+       This declares an array with a size that is determined by a compile-time expression. If the expression evaluates 
+       to 0, the array has a size of -1, which is illegal and generates a compile-time error.
+       
+       For example:
+       
+       check_compile_time( sizeof( int ) == 4 );
+       
+       Note: This only works with compile-time expressions.
+       Note: This only works in places where extern declarations are allowed (e.g. global scope).
+       
+       References:
+       
+       <http://www.jaggersoft.com/pubs/CVu11_3.html>
+       <http://www.jaggersoft.com/pubs/CVu11_5.html>
+       
+       Note: The following macros differ from the macros on the www.jaggersoft.com web site because those versions do not
+       work with GCC due to GCC allow a zero-length array. Using a -1 condition turned out to be more portable.
+*/
+
+#define        check_compile_time( X )         extern int debug_compile_time_name[ ( X ) ? 1 : -1 ]
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        check_compile_time_code
+       
+       @abstract       Perform a compile-time check, suitable for placement in code, of something such as the size of an int.
+       
+       @discussion     
+       
+       This creates a switch statement with an existing case for 0 and an additional case using the result of a 
+       compile-time expression. A switch statement cannot have two case labels with the same constant so if the
+       compile-time expression evaluates to 0, it is illegal and generates a compile-time error. If the compile-time
+       expression does not evaluate to 0, the resulting value is used as the case label and it compiles without error.
+
+       For example:
+       
+       check_compile_time_code( sizeof( int ) == 4 );
+       
+       Note: This only works with compile-time expressions.
+       Note: This does not work in a global scope so it must be inside a function.
+       
+       References:
+       
+       <http://www.jaggersoft.com/pubs/CVu11_3.html>
+       <http://www.jaggersoft.com/pubs/CVu11_5.html>
+*/
+
+#define        check_compile_time_code( X )    switch( 0 ) { case 0: case X:; }
+
+#if 0
+#pragma mark == check macros ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        check
+       
+       @abstract       Check that an expression is true (non-zero).
+       
+       @discussion     
+       
+       If expression evalulates to false, this prints debugging information (actual expression string, file, line number, 
+       function name, etc.) using the default debugging output method.
+                               
+       Code inside check() statements is not compiled into production builds. 
+*/
+
+#if( DEBUG_OVERRIDE_APPLE_MACROS )
+       #undef check
+#endif
+#if( !defined( check ) )
+       #if( DEBUG )
+               #define check( X )                                                                                                                                                                      \
+                       do                                                                                                                                                                                              \
+                       {                                                                                                                                                                                               \
+                               if( !( X ) )                                                                                                                                                            \
+                               {                                                                                                                                                                                       \
+                                       debug_print_assert( 0, #X, NULL, __FILE__, __LINE__, __ROUTINE__ );                                             \
+                               }                                                                                                                                                                                       \
+                       } while( 0 )
+       #else
+               #define check( X )
+       #endif
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        check_string
+       
+       @abstract       Check that an expression is true (non-zero) with an explanation.
+       
+       @discussion     
+       
+       If expression evalulates to false, this prints debugging information (actual expression string, file, line number, 
+       function name, etc.) and a custom explanation string using the default debugging output method.
+                               
+       Code inside check_string() statements is not compiled into production builds. 
+*/
+
+#if( DEBUG_OVERRIDE_APPLE_MACROS )
+       #undef check_string
+#endif
+#if( !defined( check_string ) )
+       #if( DEBUG )
+               #define check_string( X, STR )                                                                                                                                          \
+                       do                                                                                                                                                                                              \
+                       {                                                                                                                                                                                               \
+                               if( !( X ) )                                                                                                                                                            \
+                               {                                                                                                                                                                                       \
+                                       debug_print_assert( 0, #X, STR, __FILE__, __LINE__, __ROUTINE__ );                                              \
+                               }                                                                                                                                                                                       \
+                                                                                                                                                                                                                       \
+                       }       while( 0 )
+       #else
+               #define check_string( X, STR )
+       #endif
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        check_noerr
+       
+       @abstract       Check that an error code is noErr (0).
+       
+       @discussion     
+       
+       If the error code is non-0, this prints debugging information (actual expression string, file, line number, 
+       function name, etc.) using the default debugging output method.
+                               
+       Code inside check_noerr() statements is not compiled into production builds. 
+*/
+
+#if( DEBUG_OVERRIDE_APPLE_MACROS )
+       #undef check_noerr
+#endif
+#if( !defined( check_noerr ) )
+       #if( DEBUG )
+               #define check_noerr( ERR )                                                                                                                                                      \
+                       do                                                                                                                                                                                              \
+                       {                                                                                                                                                                                               \
+                               int_least32_t           localErr;                                                                                                                               \
+                                                                                                                                                                                                                       \
+                               localErr = (int_least32_t)( ERR );                                                                                                                      \
+                               if( localErr != 0 )                                                                                                                                             \
+                               {                                                                                                                                                                                       \
+                                       debug_print_assert( localErr, NULL, NULL, __FILE__, __LINE__, __ROUTINE__ );                    \
+                               }                                                                                                                                                                                       \
+                                                                                                                                                                                                                       \
+                       }       while( 0 )
+       #else
+               #define check_noerr( ERR )
+       #endif
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        check_noerr_string
+       
+       @abstract       Check that an error code is noErr (0) with an explanation.
+       
+       @discussion     
+       
+       If the error code is non-0, this prints debugging information (actual expression string, file, line number, 
+       function name, etc.) and a custom explanation string using the default debugging output method.
+                               
+       Code inside check_noerr_string() statements is not compiled into production builds. 
+*/
+
+#if( DEBUG_OVERRIDE_APPLE_MACROS )
+       #undef check_noerr_string
+#endif
+#if( !defined( check_noerr_string ) )
+       #if( DEBUG )
+               #define check_noerr_string( ERR, STR )                                                                                                                          \
+                       do                                                                                                                                                                                              \
+                       {                                                                                                                                                                                               \
+                               int_least32_t           localErr;                                                                                                                               \
+                                                                                                                                                                                                                       \
+                               localErr = (int_least32_t)( ERR );                                                                                                                      \
+                               if( localErr != 0 )                                                                                                                                             \
+                               {                                                                                                                                                                                       \
+                                       debug_print_assert( localErr, NULL, STR, __FILE__, __LINE__, __ROUTINE__ );                             \
+                               }                                                                                                                                                                                       \
+                                                                                                                                                                                                                       \
+                       }       while( 0 )
+       #else
+               #define check_noerr_string( ERR, STR )
+       #endif
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        check_translated_errno
+       
+       @abstract       Check a condition and prints errno (if non-zero) to the log.
+       
+       @discussion     
+       
+       Code inside check_translated_errno() statements is not compiled into production builds.
+*/
+
+#if( !defined( check_translated_errno ) )
+       #if( DEBUG )
+               #define check_translated_errno( TEST, ERRNO, ALTERNATE_ERROR )                                                                          \
+                       do                                                                                                                                                                                              \
+                       {                                                                                                                                                                                               \
+                               if( !( TEST ) )                                                                                                                                                         \
+                               {                                                                                                                                                                                       \
+                                       int_least32_t           localErr;                                                                                                                       \
+                                                                                                                                                                                                                       \
+                                       localErr = (int_least32_t)( ERRNO );                                                                                                    \
+                                       localErr = ( localErr != 0 ) ? localErr : (int_least32_t)( ALTERNATE_ERROR );                   \
+                                       debug_print_assert( localErr, #TEST, NULL, __FILE__, __LINE__, __ROUTINE__ );                   \
+                               }                                                                                                                                                                                       \
+                                                                                                                                                                                                                       \
+                       }       while( 0 )
+       #else
+               #define check_translated_errno( TEST, ERRNO, ALTERNATE_ERROR )
+       #endif
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        check_ptr_overlap
+       
+       @abstract       Checks that two ptrs do not overlap.
+*/
+
+#define        check_ptr_overlap( P1, P1_SIZE, P2, P2_SIZE )                                                                           \
+       do                                                                                                                                                                              \
+       {                                                                                                                                                                               \
+               check( !( ( (uintptr_t)( P1 ) >=     (uintptr_t)( P2 ) ) &&                                             \
+                                 ( (uintptr_t)( P1 ) <  ( ( (uintptr_t)( P2 ) ) + ( P2_SIZE ) ) ) ) );         \
+               check( !( ( (uintptr_t)( P2 ) >=     (uintptr_t)( P1 ) ) &&                                             \
+                                 ( (uintptr_t)( P2 ) <  ( ( (uintptr_t)( P1 ) ) + ( P1_SIZE ) ) ) ) );         \
+                                                                                                                                                                                       \
+       }       while( 0 )
+
+#if 0
+#pragma mark == require macros ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        require
+       
+       @abstract       Requires that an expression evaluate to true.
+       
+       @discussion     
+       
+       If expression evalulates to false, this prints debugging information (actual expression string, file, line number, 
+       function name, etc.) using the default debugging output method then jumps to a label.
+*/
+
+#if( DEBUG_OVERRIDE_APPLE_MACROS )
+       #undef require
+#endif
+#if( !defined( require ) )
+       #define require( X, LABEL )                                                                                                                                                             \
+               do                                                                                                                                                                                                      \
+               {                                                                                                                                                                                                       \
+                       if( !( X ) )                                                                                                                                                                    \
+                       {                                                                                                                                                                                               \
+                               debug_print_assert( 0, #X, NULL, __FILE__, __LINE__, __ROUTINE__ );                                                     \
+                               goto LABEL;                                                                                                                                                                     \
+                       }                                                                                                                                                                                               \
+                                                                                                                                                                                                                       \
+               }       while( 0 )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        require_string
+       
+       @abstract       Requires that an expression evaluate to true with an explanation.
+       
+       @discussion     
+       
+       If expression evalulates to false, this prints debugging information (actual expression string, file, line number, 
+       function name, etc.) and a custom explanation string using the default debugging output method then jumps to a label.
+*/
+
+#if( DEBUG_OVERRIDE_APPLE_MACROS )
+       #undef require_string
+#endif
+#if( !defined( require_string ) )
+       #define require_string( X, LABEL, STR )                                                                                                                                 \
+               do                                                                                                                                                                                                      \
+               {                                                                                                                                                                                                       \
+                       if( !( X ) )                                                                                                                                                                    \
+                       {                                                                                                                                                                                               \
+                               debug_print_assert( 0, #X, STR, __FILE__, __LINE__, __ROUTINE__ );                                                      \
+                               goto LABEL;                                                                                                                                                                     \
+                       }                                                                                                                                                                                               \
+                                                                                                                                                                                                                       \
+               }       while( 0 )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        require_quiet
+       
+       @abstract       Requires that an expression evaluate to true.
+       
+       @discussion     
+       
+       If expression evalulates to false, this jumps to a label. No debugging information is printed.
+*/
+
+#if( DEBUG_OVERRIDE_APPLE_MACROS )
+       #undef require_quiet
+#endif
+#if( !defined( require_quiet ) )
+       #define require_quiet( X, LABEL )                                                                                                                                               \
+               do                                                                                                                                                                                                      \
+               {                                                                                                                                                                                                       \
+                       if( !( X ) )                                                                                                                                                                    \
+                       {                                                                                                                                                                                               \
+                               goto LABEL;                                                                                                                                                                     \
+                       }                                                                                                                                                                                               \
+                                                                                                                                                                                                                       \
+               }       while( 0 )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        require_noerr
+       
+       @abstract       Require that an error code is noErr (0).
+       
+       @discussion     
+       
+       If the error code is non-0, this prints debugging information (actual expression string, file, line number, 
+       function name, etc.) using the default debugging output method then jumps to a label.
+*/
+
+#if( DEBUG_OVERRIDE_APPLE_MACROS )
+       #undef require_noerr
+#endif
+#if( !defined( require_noerr ) )
+       #define require_noerr( ERR, LABEL )                                                                                                                                             \
+               do                                                                                                                                                                                                      \
+               {                                                                                                                                                                                                       \
+                       int_least32_t           localErr;                                                                                                                                       \
+                                                                                                                                                                                                                       \
+                       localErr = (int_least32_t)( ERR );                                                                                                                              \
+                       if( localErr != 0 )                                                                                                                                                     \
+                       {                                                                                                                                                                                               \
+                               debug_print_assert( localErr, NULL, NULL, __FILE__, __LINE__, __ROUTINE__ );                            \
+                               goto LABEL;                                                                                                                                                                     \
+                       }                                                                                                                                                                                               \
+                                                                                                                                                                                                                       \
+               }       while( 0 )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        require_noerr_string
+       
+       @abstract       Require that an error code is noErr (0).
+       
+       @discussion     
+       
+       If the error code is non-0, this prints debugging information (actual expression string, file, line number, 
+       function name, etc.), and a custom explanation string using the default debugging output method using the 
+       default debugging output method then jumps to a label.
+*/
+
+#if( DEBUG_OVERRIDE_APPLE_MACROS )
+       #undef require_noerr_string
+#endif
+#if( !defined( require_noerr_string ) )
+       #define require_noerr_string( ERR, LABEL, STR )                                                                                                                 \
+               do                                                                                                                                                                                                      \
+               {                                                                                                                                                                                                       \
+                       int_least32_t           localErr;                                                                                                                                       \
+                                                                                                                                                                                                                       \
+                       localErr = (int_least32_t)( ERR );                                                                                                                              \
+                       if( localErr != 0 )                                                                                                                                                     \
+                       {                                                                                                                                                                                               \
+                               debug_print_assert( localErr, NULL, STR, __FILE__, __LINE__, __ROUTINE__ );                                     \
+                               goto LABEL;                                                                                                                                                                     \
+                       }                                                                                                                                                                                               \
+                                                                                                                                                                                                                       \
+               }       while( 0 )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        require_noerr_action_string
+       
+       @abstract       Require that an error code is noErr (0).
+       
+       @discussion     
+       
+       If the error code is non-0, this prints debugging information (actual expression string, file, line number, 
+       function name, etc.), and a custom explanation string using the default debugging output method using the 
+       default debugging output method then executes an action and jumps to a label.
+*/
+
+#if( DEBUG_OVERRIDE_APPLE_MACROS )
+       #undef require_noerr_action_string
+#endif
+#if( !defined( require_noerr_action_string ) )
+       #define require_noerr_action_string( ERR, LABEL, ACTION, STR )                                                                                  \
+               do                                                                                                                                                                                                      \
+               {                                                                                                                                                                                                       \
+                       int_least32_t           localErr;                                                                                                                                       \
+                                                                                                                                                                                                                       \
+                       localErr = (int_least32_t)( ERR );                                                                                                                              \
+                       if( localErr != 0 )                                                                                                                                                     \
+                       {                                                                                                                                                                                               \
+                               debug_print_assert( localErr, NULL, STR, __FILE__, __LINE__, __ROUTINE__ );                                     \
+                               { ACTION; }                                                                                                                                                                     \
+                               goto LABEL;                                                                                                                                                                     \
+                       }                                                                                                                                                                                               \
+                                                                                                                                                                                                                       \
+               }       while( 0 )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        require_noerr_quiet
+       
+       @abstract       Require that an error code is noErr (0).
+       
+       @discussion     
+       
+       If the error code is non-0, this jumps to a label. No debugging information is printed.
+*/
+
+#if( DEBUG_OVERRIDE_APPLE_MACROS )
+       #undef require_noerr_quiet
+#endif
+#if( !defined( require_noerr_quiet ) )
+       #define require_noerr_quiet( ERR, LABEL )                                                                                                                               \
+               do                                                                                                                                                                                                      \
+               {                                                                                                                                                                                                       \
+                       if( ( ERR ) != 0 )                                                                                                                                                              \
+                       {                                                                                                                                                                                               \
+                               goto LABEL;                                                                                                                                                                     \
+                       }                                                                                                                                                                                               \
+                                                                                                                                                                                                                       \
+               }       while( 0 )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        require_noerr_action
+       
+       @abstract       Require that an error code is noErr (0) with an action to execute otherwise.
+       
+       @discussion     
+       
+       If the error code is non-0, this prints debugging information (actual expression string, file, line number, 
+       function name, etc.) using the default debugging output method then executes an action and jumps to a label.
+*/
+
+#if( DEBUG_OVERRIDE_APPLE_MACROS )
+       #undef require_noerr_action
+#endif
+#if( !defined( require_noerr_action ) )
+       #define require_noerr_action( ERR, LABEL, ACTION )                                                                                                              \
+               do                                                                                                                                                                                                      \
+               {                                                                                                                                                                                                       \
+                       int_least32_t           localErr;                                                                                                                                       \
+                                                                                                                                                                                                                       \
+                       localErr = (int_least32_t)( ERR );                                                                                                                              \
+                       if( localErr != 0 )                                                                                                                                                     \
+                       {                                                                                                                                                                                               \
+                               debug_print_assert( localErr, NULL, NULL, __FILE__, __LINE__, __ROUTINE__ );                            \
+                               { ACTION; }                                                                                                                                                                     \
+                               goto LABEL;                                                                                                                                                                     \
+                       }                                                                                                                                                                                               \
+                                                                                                                                                                                                                       \
+               }       while( 0 )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        require_noerr_action_quiet
+       
+       @abstract       Require that an error code is noErr (0) with an action to execute otherwise.
+       
+       @discussion     
+       
+       If the error code is non-0, this executes an action and jumps to a label. No debugging information is printed.
+*/
+
+#if( DEBUG_OVERRIDE_APPLE_MACROS )
+       #undef require_noerr_action_quiet
+#endif
+#if( !defined( require_noerr_action_quiet ) )
+       #define require_noerr_action_quiet( ERR, LABEL, ACTION )                                                                                                \
+               do                                                                                                                                                                                                      \
+               {                                                                                                                                                                                                       \
+                       if( ( ERR ) != 0 )                                                                                                                                                              \
+                       {                                                                                                                                                                                               \
+                               { ACTION; }                                                                                                                                                                     \
+                               goto LABEL;                                                                                                                                                                     \
+                       }                                                                                                                                                                                               \
+                                                                                                                                                                                                                       \
+               }       while( 0 )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        require_action
+       
+       @abstract       Requires that an expression evaluate to true with an action to execute otherwise.
+       
+       @discussion     
+       
+       If expression evalulates to false, this prints debugging information (actual expression string, file, line number, 
+       function name, etc.) using the default debugging output method then executes an action and jumps to a label.
+*/
+
+#if( DEBUG_OVERRIDE_APPLE_MACROS )
+       #undef require_action
+#endif
+#if( !defined( require_action ) )
+       #define require_action( X, LABEL, ACTION )                                                                                                                              \
+               do                                                                                                                                                                                                      \
+               {                                                                                                                                                                                                       \
+                       if( !( X ) )                                                                                                                                                                    \
+                       {                                                                                                                                                                                               \
+                               debug_print_assert( 0, #X, NULL, __FILE__, __LINE__, __ROUTINE__ );                                                     \
+                               { ACTION; }                                                                                                                                                                     \
+                               goto LABEL;                                                                                                                                                                     \
+                       }                                                                                                                                                                                               \
+                                                                                                                                                                                                                       \
+               }       while( 0 )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        require_action_quiet
+       
+       @abstract       Requires that an expression evaluate to true with an action to execute otherwise.
+       
+       @discussion     
+       
+       If expression evalulates to false, this executes an action and jumps to a label. No debugging information is printed.
+*/
+
+#if( DEBUG_OVERRIDE_APPLE_MACROS )
+       #undef require_action_quiet
+#endif
+#if( !defined( require_action_quiet ) )
+       #define require_action_quiet( X, LABEL, ACTION )                                                                                                                \
+               do                                                                                                                                                                                                      \
+               {                                                                                                                                                                                                       \
+                       if( !( X ) )                                                                                                                                                                    \
+                       {                                                                                                                                                                                               \
+                               { ACTION; }                                                                                                                                                                     \
+                               goto LABEL;                                                                                                                                                                     \
+                       }                                                                                                                                                                                               \
+                                                                                                                                                                                                                       \
+               }       while( 0 )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        require_action_string
+       
+       @abstract       Requires that an expression evaluate to true with an explanation and action to execute otherwise.
+       
+       @discussion     
+       
+       If expression evalulates to false, this prints debugging information (actual expression string, file, line number, 
+       function name, etc.) and a custom explanation string using the default debugging output method then executes an
+       action and jumps to a label.
+*/
+
+#if( DEBUG_OVERRIDE_APPLE_MACROS )
+       #undef require_action_string
+#endif
+#if( !defined( require_action_string ) )
+       #define require_action_string( X, LABEL, ACTION, STR )                                                                                                  \
+               do                                                                                                                                                                                                      \
+               {                                                                                                                                                                                                       \
+                       if( !( X ) )                                                                                                                                                                    \
+                       {                                                                                                                                                                                               \
+                               debug_print_assert( 0, #X, STR, __FILE__, __LINE__, __ROUTINE__ );                                              \
+                               { ACTION; }                                                                                                                                                                     \
+                               goto LABEL;                                                                                                                                                                     \
+                       }                                                                                                                                                                                               \
+                                                                                                                                                                                                                       \
+               }       while( 0 )
+
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        require_throw
+       
+       @abstract       Requires that an expression evaluates to true or an exception is thrown.
+       
+       @discussion     
+       
+       If the expression evaluates to false, this prints debugging information (actual expression string, file, 
+       line number, function name, etc.) using the default debugging output method then throws an exception.
+*/
+
+#if( defined( __cplusplus ) )
+       #define require_throw( X )                                                                                                                                                              \
+               do                                                                                                                                                                                                      \
+               {                                                                                                                                                                                                       \
+                       if( !( X ) )                                                                                                                                                                    \
+                       {                                                                                                                                                                                               \
+                               debug_print_assert( 0, #X, NULL, __FILE__, __LINE__, __ROUTINE__ );                                                     \
+                               throw kUnknownErr;                                                                                                                                                      \
+                       }                                                                                                                                                                                               \
+                                                                                                                                                                                                                       \
+               }       while( 0 )
+#endif
+
+#if 0
+#pragma mark == Design-By-Contract macros ==
+#endif
+
+//===========================================================================================================================
+//     Design-By-Contract macros
+//===========================================================================================================================
+
+#define        ensure( X )                                                                                                     check( X )
+#define        ensure_string( X, STR )                                                                         check_string( X, STR )
+#define        ensure_noerr( ERR )                                                                                     check_noerr( ERR )
+#define        ensure_noerr_string( ERR, STR )                                                         check_noerr_string( ERR, STR )
+#define        ensure_translated_errno( TEST, ERRNO, ALTERNATE_ERROR )         check_translated_errno( TEST, ERRNO, ALTERNATE_ERROR )
+
+// Note: Design-By-Contract "require" macros are already defined elsewhere.
+
+#if 0
+#pragma mark == Expect macros ==
+#endif
+
+//===========================================================================================================================
+//     Expect macros
+//===========================================================================================================================
+
+// Expect macros allow code to include runtime checking of things that should not happen in shipping code (e.g. internal 
+// programmer errors, such as a NULL parameter where it is not allowed). Once the code has been verified to work correctly 
+// without asserting, the DEBUG_EXPECT_VERIFIED conditional can be set to eliminate the error checking entirely. It can 
+// also be useful to measure the cost of error checking code by profiling with it enable and with it disabled.
+
+#if( DEBUG_EXPECT_VERIFIED )
+       #define require_expect
+       #define require_string_expect
+       #define require_quiet_expect
+       #define require_noerr_expect
+       #define require_noerr_string_expect
+       #define require_noerr_action_string_expect
+       #define require_noerr_quiet_expect
+       #define require_noerr_action_expect
+       #define require_noerr_action_quiet_expect
+       #define require_action_expect
+       #define require_action_quiet_expect
+       #define require_action_string_expect
+#else
+       #define require_expect                                                  require
+       #define require_string_expect                                   require_string
+       #define require_quiet_expect                                    require_quiet
+       #define require_noerr_expect                                    require_noerr
+       #define require_noerr_string_expect                             require_noerr_string
+       #define require_noerr_action_string_expect              require_noerr_action_string
+       #define require_noerr_quiet_expect                              require_noerr_quiet
+       #define require_noerr_action_expect                             require_noerr_action
+       #define require_noerr_action_quiet_expect               require_noerr_action_quiet
+       #define require_action_expect                                   require_action
+       #define require_action_quiet_expect                             require_action_quiet
+       #define require_action_string_expect                    require_action_string
+#endif
+
+#if 0
+#pragma mark == Output macros ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        debug_string
+       
+       @abstract       Prints a debugging C string.
+*/
+
+#if( DEBUG_OVERRIDE_APPLE_MACROS )
+       #undef debug_string
+#endif
+#if( !defined( debug_string ) )
+       #if( DEBUG )
+               #define debug_string( STR )                                                                                                                                             \
+                       do                                                                                                                                                                                      \
+                       {                                                                                                                                                                                       \
+                               debug_print_assert( 0, NULL, STR, __FILE__, __LINE__, __ROUTINE__ );                                    \
+                                                                                                                                                                                                               \
+                       }       while( 0 )
+       #else
+               #define debug_string( STR )
+       #endif
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        debug_print_assert
+       
+       @abstract       Prints an assertion.
+*/
+
+#if( DEBUG )
+       #define debug_print_assert( ERROR_CODE, ASSERT_STRING, MESSAGE, FILENAME, LINE_NUMBER, FUNCTION )       \
+               DebugPrintAssert( ERROR_CODE, ASSERT_STRING, MESSAGE, FILENAME, LINE_NUMBER, FUNCTION )
+#else
+       #define debug_print_assert( ERROR_CODE, ASSERT_STRING, MESSAGE, FILENAME, LINE_NUMBER, FUNCTION )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        dlog
+       
+       @abstract       Prints a debug-only message.
+*/
+
+#if( DEBUG )
+       #if( DEBUG_C99_VA_ARGS )
+               #define dlog( ... )                     DebugPrintF( __VA_ARGS__ )
+       #elif( DEBUG_GNU_VA_ARGS )
+               #define dlog( ARGS... )         DebugPrintF( ## ARGS )                  
+       #else
+               #define dlog                            DebugPrintF
+       #endif
+#else
+       #if( DEBUG_C99_VA_ARGS )
+               #define dlog( ... )
+       #elif( DEBUG_GNU_VA_ARGS )
+               #define dlog( ARGS... )
+       #else
+               #define dlog                            while( 0 )
+       #endif
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        dlogv
+       
+       @abstract       Prints a debug-only message.
+*/
+
+#if( DEBUG )
+       #define dlogv( LEVEL, FORMAT, LIST )            DebugPrintFVAList( ( LEVEL ), ( FORMAT ), ( LIST ) )
+#else
+       #define dlogv( LEVEL, FORMAT, LIST )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        dlogmem
+       
+       @abstract       Prints a debug-only dump of memory.
+*/
+
+#if( DEBUG )
+       #define dlogmem( LEVEL, PTR, SIZE )             \
+               DebugHexDump( ( LEVEL ), 0, NULL, 0, 0, NULL, 0, ( PTR ), ( PTR ), ( SIZE ), kDebugFlagsNone, NULL, 0 )
+#else
+       #define dlogmem( LEVEL, PTR, SIZE )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        DebugNSLog
+       
+       @abstract       Debug-only macro for the Cocoa NSLog function.
+*/
+
+#if( DEBUG )
+       #if( DEBUG_C99_VA_ARGS )
+               #define DebugNSLog( ... )                       NSLog( __VA_ARGS__ )
+       #elif( DEBUG_GNU_VA_ARGS )
+               #define DebugNSLog( ARGS... )           NSLog( ## ARGS )
+       #else
+               #define DebugNSLog                                      NSLog
+       #endif
+#else
+       #if( DEBUG_C99_VA_ARGS )
+               #define DebugNSLog( ... )
+       #elif( DEBUG_GNU_VA_ARGS )
+               #define DebugNSLog( ARGS... )
+       #else
+               #define DebugNSLog                                      while( 0 )
+       #endif
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        DebugLogMsg
+       
+       @abstract       Debug-only macro for the VxWorks logMsg function.
+*/
+
+#if( TARGET_OS_VXWORKS )
+       #if( DEBUG )
+               #define DebugLogMsg( LEVEL, FORMAT, P1, P2, P3, P4, P5, P6 )                                                    \
+                       do                                                                                                                                                                      \
+                       {                                                                                                                                                                       \
+                               if( ( inLevel >= gDebugPrintLevelMin ) || ( inLevel <= gDebugPrintLevelMax ) )  \
+                               {                                                                                                                                                               \
+                                       logMsg( ( FORMAT ), ( P1 ), ( P2 ), ( P3 ), ( P4 ), ( P5 ), ( P6 ) );           \
+                               }                                                                                                                                                               \
+                                                                                                                                                                                               \
+                       }       while( 0 )
+       #else
+               #define DebugLogMsg( LEVEL, FORMAT, P1, P2, P3, P4, P5, P6 )
+       #endif
+#else
+       #define DebugLogMsg             dlog
+#endif
+
+#if 0
+#pragma mark == Routines - General ==
+#endif
+
+#ifdef __cplusplus
+       extern "C" {
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       DebugInitialize
+
+       @abstract       Initializes the debugging library for a specific kind of output.
+
+       @param          inType          
+       @param          varArg          Variable number parameters, controlled by the "inType" parameter.
+*/
+
+#if( DEBUG )
+       DEBUG_EXPORT OSStatus   DebugInitialize( DebugOutputType inType, ... );
+#endif
+
+#if( DEBUG )
+       #if( DEBUG_C99_VA_ARGS )
+               #define debug_initialize( ... )                 DebugInitialize( __VA_ARGS__ )
+       #elif( DEBUG_GNU_VA_ARGS )
+               #define debug_initialize( ARGS... )             DebugInitialize( ## ARGS )
+       #else
+               #define debug_initialize                                DebugInitialize
+       #endif
+#else
+       #if( DEBUG_C99_VA_ARGS )
+               #define debug_initialize( ... )
+       #elif( DEBUG_GNU_VA_ARGS )
+               #define debug_initialize( ARGS... )
+       #else
+               #define debug_initialize                                while( 0 )
+       #endif
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       DebugFinalize
+
+       @abstract       Releases any resources used by the debugging library
+*/
+
+#if( DEBUG )
+       DEBUG_EXPORT void               DebugFinalize( void );
+#endif
+
+#if( DEBUG )                     
+       #define debug_terminate()       DebugFinalize()
+#else
+       #define debug_terminate()
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       DebugGetProperty
+
+       @abstract       Gets the specified property from the debugging library.
+*/
+
+#if( DEBUG )
+       DEBUG_EXPORT OSStatus   DebugGetProperty( DebugPropertyTag inTag, ... );
+#endif
+
+#if( DEBUG )
+       #if( DEBUG_C99_VA_ARGS )
+               #define debug_get_property( ... )                       DebugGetProperty( __VA_ARGS__ )
+       #elif( DEBUG_GNU_VA_ARGS )
+               #define debug_get_property( ARGS... )           DebugGetProperty( ## ARGS )
+       #else
+               #define debug_get_property                                      DebugGetProperty
+       #endif
+#else
+       #if( DEBUG_C99_VA_ARGS )
+               #define debug_get_property( ... )
+       #elif( DEBUG_GNU_VA_ARGS )
+               #define debug_get_property( ARGS... )
+       #else
+               #define debug_get_property                                      while( 0 )
+       #endif
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       DebugSetProperty
+
+       @abstract       Sets the specified property from the debugging library.
+*/
+
+#if( DEBUG )
+       DEBUG_EXPORT OSStatus   DebugSetProperty( DebugPropertyTag inTag, ... );
+#endif
+
+#if( DEBUG )
+       #if( DEBUG_C99_VA_ARGS )
+               #define debug_set_property( ... )                       DebugSetProperty( __VA_ARGS__ )
+       #elif( DEBUG_GNU_VA_ARGS )
+               #define debug_set_property( ARGS... )           DebugSetProperty( ## ARGS )
+       #else
+               #define debug_set_property                                      DebugSetProperty
+       #endif
+#else
+       #if( DEBUG_C99_VA_ARGS )
+               #define debug_set_property( ... )
+       #elif( DEBUG_GNU_VA_ARGS )
+               #define debug_set_property( ARGS... )
+       #else
+               #define debug_set_property                                      while( 0 )
+       #endif
+#endif
+
+#if 0
+#pragma mark == Routines - Debugging Output ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       DebugPrintF
+
+       @abstract       Prints a debug message with printf-style formatting.
+       
+       @param          inLevel Error that generated this assert or noErr.
+       
+       @param          inFormatString
+                                       C string containing assertion text.
+
+       @param          VAR_ARG
+                                       Variable number of arguments depending on the format string.
+       
+       @result         Number of bytes printed or -1 on error.
+*/
+
+#if( DEBUG )
+       DEBUG_EXPORT size_t             DebugPrintF( DebugLevel inLevel, const char *inFormat, ... );
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       DebugPrintFVAList
+
+       @abstract       va_list version of DebugPrintF. See DebugPrintF for more info.
+*/
+
+#if( DEBUG )
+       DEBUG_EXPORT size_t             DebugPrintFVAList( DebugLevel inLevel, const char *inFormat, va_list inArgs );
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       DebugPrintAssert
+
+       @abstract       Prints a message describing the reason the (e.g. an assert failed), an optional error message, 
+                               an optional source filename, an optional source line number.
+
+       @param          inErrorCode                     Error that generated this assert or noErr.
+       @param          inAssertString          C string containing assertion text.
+       @param          inMessage                       C string containing a message about the assert.
+       @param          inFileName                      C string containing path of file where the error occurred.
+       @param          inLineNumber            Line number in source file where the error occurred.
+       @param          inFunction                      C string containing name of function where assert occurred.
+
+       @discussion
+       
+       Example output: 
+       
+       [ASSERT] assert: "dataPtr != NULL" allocate memory for object failed
+       [ASSERT] where:  "MyFile.c", line 123, ("MyFunction")
+       
+       OR
+       
+       [ASSERT] error:  -6728 (kNoMemoryErr)
+       [ASSERT] where:  "MyFile.c", line 123, ("MyFunction")
+*/
+
+#if( DEBUG )
+       DEBUG_EXPORT void
+               DebugPrintAssert( 
+                       int_least32_t   inErrorCode, 
+                       const char *    inAssertString, 
+                       const char *    inMessage, 
+                       const char *    inFilename, 
+                       int_least32_t   inLineNumber, 
+                       const char *    inFunction );
+#endif
+
+#if 0
+#pragma mark == Routines - Utilities ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       DebugSNPrintF
+       
+       @abstract       Debugging versions of standard C snprintf with extra features.
+       
+       @param          sbuffer         Buffer to receive result. Null terminated unless the buffer size is 0.
+       @param          buflen          Size of the buffer including space for the null terminator.
+       @param          fmt                     printf-style format string.
+       @param          VAR_ARG         Variable number of arguments depending on the format string.
+
+       @result         Number of characters written (minus the null terminator).
+       
+       @discussion     
+       
+       Extra features over the standard C snprintf:
+       <pre>
+               64-bit support for %d (%lld), %i (%lli), %u (%llu), %o (%llo), %x (%llx), and %b (%llb).
+               %@   - Cocoa/CoreFoundation object. Param is the object. Strings are used directly. Others use CFCopyDescription.
+               %a   - Network Address: %.4a=IPv4, %.6a=Ethernet, %.8a Fibre Channel, %.16a=IPv6. Arg=ptr to network address.
+               %#a  - IPv4 or IPv6 mDNSAddr. Arg=ptr to mDNSAddr.
+               %##a - IPv4 (if AF_INET defined) or IPv6 (if AF_INET6 defined) sockaddr. Arg=ptr to sockaddr.
+               %b   - Binary representation of integer (e.g. 01101011). Modifiers and arg=the same as %d, %x, etc.
+               %C   - Mac-style FourCharCode (e.g. 'APPL'). Arg=32-bit value to print as a Mac-style FourCharCode.
+               %H   - Hex Dump (e.g. "\x6b\xa7" -> "6B A7"). 1st arg=ptr, 2nd arg=size, 3rd arg=max size.
+               %#H  - Hex Dump & ASCII (e.g. "\x41\x62" -> "6B A7 'Ab'"). 1st arg=ptr, 2nd arg=size, 3rd arg=max size.
+               %m   - Error Message (e.g. 0 -> "kNoErr"). Modifiers and error code arg=the same as %d, %x, etc.
+               %#s  - Pascal-style length-prefixed string. Arg=ptr to string.
+               %##s - DNS label-sequence name. Arg=ptr to name.
+               %S   - UTF-16 string, 0x0000 terminated. Host order if no BOM. Precision is UTF-16 count. Precision includes BOM.
+               %#S  - Big Endian UTF-16 string (unless BOM overrides). Otherwise, the same as %S.
+               %##S - Little Endian UTF-16 string (unless BOM overrides). Otherwise, the same as %S.
+               %U   - Universally Unique Identifier (UUID) (e.g. 6ba7b810-9dad-11d1-80b4-00c04fd430c8). Arg=ptr to 16-byte UUID.
+       </pre>
+*/
+
+#if( DEBUG )
+       DEBUG_EXPORT size_t DebugSNPrintF(char *sbuffer, size_t buflen, const char *fmt, ...);
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       DebugSNPrintFVAList
+
+       @abstract       va_list version of DebugSNPrintF. See DebugSNPrintF for more info.
+*/
+
+#if( DEBUG )
+       DEBUG_EXPORT size_t DebugSNPrintFVAList(char *sbuffer, size_t buflen, const char *fmt, va_list arg);
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       DebugGetErrorString
+
+       @abstract       Gets an error string from an error code.
+
+       @param          inStatus                Error code to get the string for.
+       @param          inBuffer                Optional buffer to copy the string to for non-static strings. May be null.
+       @param          inBufferSize    Size of optional buffer. May be 0.
+       
+       @result         C string containing error string for the error code. Guaranteed to be a valid, static string. If a 
+                               buffer is supplied, the return value will always be a pointer to the supplied buffer, which will 
+                               contain the best available description of the error code. If a buffer is not supplied, the return
+                               value will be the best available description of the error code that can be represented as a static 
+                               string. This allows code that cannot use a temporary buffer to hold the result to still get a useful 
+                               error string in most cases, but also allows code that can use a temporary buffer to get the best 
+                               available description.
+*/
+
+#if( DEBUG )
+       DEBUG_EXPORT const char *       DebugGetErrorString( int_least32_t inErrorCode, char *inBuffer, size_t inBufferSize );
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       DebugHexDump
+
+       @abstract       Hex dumps data to a string or to the output device.
+*/
+
+#if( DEBUG )
+       DEBUG_EXPORT size_t
+               DebugHexDump( 
+                       DebugLevel              inLevel, 
+                       int                             inIndent, 
+                       const char *    inLabel, 
+                       size_t                  inLabelSize, 
+                       int                             inLabelMinWidth, 
+                       const char *    inType, 
+                       size_t                  inTypeSize, 
+                       const void *    inDataStart, 
+                       const void *    inData, 
+                       size_t                  inDataSize, 
+                       DebugFlags              inFlags, 
+                       char *                  outBuffer, 
+                       size_t                  inBufferSize );
+#endif
+
+#if( DEBUG )
+       #define dloghex( LEVEL, INDENT, LABEL, LABEL_SIZE, LABEL_MIN_SIZE, TYPE, TYPE_SIZE, DATA_START, DATA, DATA_SIZE, FLAGS, BUFFER, BUFFER_SIZE )   \
+               DebugHexDump( ( LEVEL ), (INDENT), ( LABEL ), ( LABEL_SIZE ), ( LABEL_MIN_SIZE ), ( TYPE ), ( TYPE_SIZE ),                                                              \
+                       ( DATA_START ), ( DATA ), ( DATA_SIZE ), ( FLAGS ), ( BUFFER ), ( BUFFER_SIZE ) )
+#else
+       #define dloghex( LEVEL, INDENT, LABEL, LABEL_SIZE, LABEL_MIN_SIZE, TYPE, TYPE_SIZE, DATA_START, DATA, DATA_SIZE, FLAGS, BUFFER, BUFFER_SIZE )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       DebugTaskLevel
+
+       @abstract       Returns the current task level.
+
+       @result         Current task level
+       
+       @discussion     
+       
+       Bit masks to isolate portions of the result (note that some masks may also need bit shifts to right justify):
+       <pre>
+               kDebugInterruptLevelMask                                - Indicates the current interrupt level (> 0 means interrupt time).
+               kDebugInVBLTaskMask                                             - Indicates if a VBL task is currently being executed.
+               kDebugInDeferredTaskMask                                - Indicates if a Deferred Task is currently being executed.
+               kDebugInSecondaryInterruptHandlerMask   - Indicates if a Secondary Interrupt Handler is currently being executed.
+               kDebugPageFaultFatalMask                                - Indicates if it is unsafe to cause a page fault (worse than interrupt time).
+               kDebugMPTaskLevelMask                                   - Indicates if being called from an MP task.
+               kDebugInterruptDepthMask                                - 0 means task level, 1 means in interrupt, > 1 means in nested interrupt.
+       </pre>
+       
+       Helpers:
+       <pre>
+               DebugExtractTaskLevelInterruptDepth()   - Macro to extract interrupt depth from task level value.
+       </pre>
+*/
+
+#if( DEBUG )
+       DEBUG_EXPORT uint32_t   DebugTaskLevel( void );
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       DebugServicesTest
+
+       @abstract       Unit test.
+*/
+
+#if( DEBUG )
+       DEBUG_EXPORT OSStatus   DebugServicesTest( void );
+#endif
+
+#ifdef __cplusplus
+       }
+#endif
+
+#endif // __DEBUG_SERVICES__
diff --git a/mDNSWindows/Installer.vct b/mDNSWindows/Installer.vct
new file mode 100644 (file)
index 0000000..c31317d
Binary files /dev/null and b/mDNSWindows/Installer.vct differ
index 52c48b19c04d5c56a2e130bcc5be71c5fa0a1720..5a7b375a5b74a74af2957953c8842a0b922572cf 100644 (file)
@@ -1,19 +1,59 @@
 This directory contains support files for running mDNS on Microsoft Windows 
-and Windows CE/PocketPC.
+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 & mDNSWin32.h are the Platform Support files that go below
-mDNS Core. These work on both Windows and Windows CE/PocketPC.
+mDNSWin32.c/.h
+       
+       Platform Support files that go below mDNS Core. These work on both Windows 
+       and Windows CE/PocketPC.
 
-DNSServices is a higher-level API for using mDNS. It manages memory, tracks 
-browers and registrations, etc.
+DNSSD.c/.h
 
-DNSServiceDiscovery is an emulation layer that sits on top of DNSServices 
-and provides the Mac OS X DNS Service Discovery API's on any platform.
+       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 builds 
+ToolWin32.vcproj is a Visual Studio .NET 7 project. These projects build 
 Tool.c to make rendezvous.exe, a small Windows command-line tool to do all 
 the standard Rendezvous stuff on Windows. It has the following features:
 
@@ -42,3 +82,4 @@ parameters, and some examples of using it.
 RendezvousBrowser 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/RMxClient.c b/mDNSWindows/RMxClient.c
new file mode 100644 (file)
index 0000000..540d4ef
--- /dev/null
@@ -0,0 +1,1302 @@
+/*
+ * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+    
+$Log: RMxClient.c,v $
+Revision 1.3  2004/04/15 01:00:05  bradley
+Removed support for automatically querying for A/AAAA records when resolving names. Platforms
+without .local name resolving support will need to manually query for A/AAAA records as needed.
+
+Revision 1.2  2004/04/09 21:03:14  bradley
+Changed port numbers to use network byte order for consistency with other platforms.
+
+Revision 1.1  2004/01/30 02:35:13  bradley
+Rendezvous Message Exchange implementation for DNS-SD IPC on Windows.
+
+*/
+
+#include       <stdlib.h>
+#include       <stdio.h>
+#include       <string.h>
+
+#include       "CommonServices.h"
+#include       "DebugServices.h"
+
+#include       "DNSSD.h"
+#include       "RMxCommon.h"
+
+#include       "RMxClient.h"
+
+#ifdef __cplusplus
+       extern "C" {
+#endif
+
+#if 0
+#pragma mark == Constants ==
+#endif
+
+//===========================================================================================================================
+//     Constants
+//===========================================================================================================================
+
+#define        DEBUG_NAME              "[RMxClient] "
+
+#if 0
+#pragma mark == Structures ==
+#endif
+
+//===========================================================================================================================
+//     Structures
+//===========================================================================================================================
+
+typedef void ( *DNSServiceRefReleaseCallBack )( DNSServiceRef inRef );
+
+// DNSServiceRef
+
+typedef struct _DNSServiceRef_t        _DNSServiceRef_t;
+struct _DNSServiceRef_t
+{
+       RMxSessionRef                                                                   session;
+       void *                                                                                  context;
+       DNSRecordRef                                                                    records;
+       
+       union
+       {
+               struct  // EnumerateDomains
+               {
+                       DNSServiceDomainEnumReply                               callback;
+               
+               }       domain;
+                               
+               struct  // Register
+               {
+                       DNSServiceRegisterReply                                 callback;
+                       uint32_t                                                                lastID;
+               
+               }       reg;
+               
+               struct  // Browse
+               {
+                       DNSServiceBrowseReply                                   callback;
+               
+               }       browse;
+               
+               struct  // Resolve
+               {
+                       DNSServiceFlags                                                 flags;
+                       DNSServiceResolveReply                                  callback;
+               
+               }       resolve;
+
+               struct  // CreateConnection
+               {
+                       DNSServiceRegisterRecordReply                   callback;
+                       uint32_t                                                                lastID;
+               
+               }       connection;
+               
+               struct  // QueryRecord
+               {
+                       DNSServiceQueryRecordReply                              callback;
+               
+               }       query;
+       
+       }       u;
+};
+
+// DNSRecordRef
+
+typedef struct _DNSRecordRef_t         _DNSRecordRef_t;
+struct _DNSRecordRef_t
+{
+       DNSRecordRef                                            next;
+       uint32_t                                                        id;
+       DNSServiceRegisterRecordReply           callback;
+       void *                                                          context;
+};
+
+#if 0
+#pragma mark == Prototypes ==
+#endif
+
+//===========================================================================================================================
+//     Prototypes
+//===========================================================================================================================
+
+// RMx
+
+DEBUG_LOCAL void       RMxClientMessageCallBack( RMxMessage *inMessage );
+
+// Properties
+
+DEBUG_LOCAL DNSServiceErrorType
+       DNSServiceCopyPropertyDecodeData_client( 
+               DNSPropertyCode         inCode, 
+               const void *            inData, 
+               size_t                          inSize, 
+               DNSPropertyData *       outData );
+
+// Domain Enumeration
+
+DEBUG_LOCAL void       DNSServiceEnumerateDomainsReply_client( RMxMessage *inMessage );
+
+// Service Discovery
+
+DEBUG_LOCAL void       DNSServiceBrowseReply_client( RMxMessage *inMessage );
+
+DEBUG_LOCAL void       DNSServiceResolveReply_client( RMxMessage *inMessage );
+
+// Service Registration
+
+DEBUG_LOCAL void       DNSServiceRegisterReply_client( RMxMessage *inMessage );
+
+// Special Purpose
+
+DEBUG_LOCAL DNSRecordRef       DNSServiceConnectionRecordRemove_client( DNSServiceRef inRef, DNSRecordRef inRecordRef );
+DEBUG_LOCAL void                       DNSServiceRegisterRecordReply_client( RMxMessage *inMessage );
+DEBUG_LOCAL void                       DNSServiceQueryRecordReply_client( RMxMessage *inMessage );
+
+#if 0
+#pragma mark -
+#pragma mark == RMx ==
+#endif
+
+//===========================================================================================================================
+//     RMxClientInitialize
+//===========================================================================================================================
+
+OSStatus       RMxClientInitialize( void )
+{
+       OSStatus                err;
+       
+       // Initialize the lower-level layer and indicate it is running.
+       
+       err = RMxInitialize();
+       require_noerr( err, exit );
+       
+       gRMxState = kRMxStateRun;
+       
+exit:
+       if( err != kNoErr )
+       {
+               RMxClientFinalize();
+       }
+       return( err );
+}
+
+//===========================================================================================================================
+//     RMxClientFinalize
+//===========================================================================================================================
+
+void   RMxClientFinalize( void )
+{
+       RMxFinalize();
+}
+
+//===========================================================================================================================
+//     RMxClientMessageCallBack
+//===========================================================================================================================
+
+DEBUG_LOCAL void       RMxClientMessageCallBack( RMxMessage *inMessage )
+{
+       check( inMessage );
+       
+       switch( inMessage->opcode )
+       {
+               case kRMxOpCodeInvalid:                 
+                       // The session is closing. We don't delete the DNS-SD object here because the client deletes DNS-SD objects.
+                       break;
+               
+               case kRMxOpCodeEnumerateDomains:
+                       DNSServiceEnumerateDomainsReply_client( inMessage );
+                       break;
+               
+               case kRMxOpCodeRegister:
+                       DNSServiceRegisterReply_client( inMessage );
+                       break;
+
+               case kRMxOpCodeBrowse:
+                       DNSServiceBrowseReply_client( inMessage );
+                       break;
+               
+               case kRMxOpCodeResolve:
+                       DNSServiceResolveReply_client( inMessage );
+                       break;
+               
+               case kRMxOpCodeRegisterRecord:
+                       DNSServiceRegisterRecordReply_client( inMessage );
+                       break;
+               
+               case kRMxOpCodeQueryRecord:
+                       DNSServiceQueryRecordReply_client( inMessage );
+                       break;
+               
+               default:
+                       dlog( kDebugLevelWarning, DEBUG_NAME "message with unknown opcode received (%d)\n", inMessage->opcode );
+                       break;
+       }
+}
+
+#if 0
+#pragma mark -
+#pragma mark == DNS-SD General ==
+#endif
+
+//===========================================================================================================================
+//     DNSServiceRefDeallocate_client
+//===========================================================================================================================
+
+void   DNSServiceRefDeallocate_client( DNSServiceRef inRef )
+{
+       OSStatus                err;
+       
+       dlog( kDebugLevelTrace, "\n" DEBUG_NAME "Deallocate ref=%#p\n", inRef );
+       require_action( inRef, exit, err = kDNSServiceErr_BadReference );
+       
+       // Close the session (if not already closed).
+       
+       if( inRef->session )
+       {
+               inRef->session->callback                = NULL;
+               inRef->session->message.context = NULL;
+               
+               err = RMxSessionClose( inRef->session, kEndingErr );
+               check_noerr( err );
+       }
+       
+       // Release any outstanding individual records.
+       
+       while( inRef->records )
+       {
+               DNSRecordRef            record;
+               
+               record = inRef->records;
+               inRef->records = record->next;
+               
+               free( record );
+       }
+       
+       // Release the object itself.
+       
+       free( inRef );
+
+exit:
+       return;
+}
+
+//===========================================================================================================================
+//     DNSServiceCheckVersion_client
+//===========================================================================================================================
+
+DNSServiceErrorType    DNSServiceCheckVersion_client( const char *inServer )
+{      
+       DNSServiceErrorType             err;
+       RMxSessionRef                   session;
+       OSStatus                                errorCode;
+       uint32_t                                serverCurrentVersion;
+       uint32_t                                serverOldestClientVersion;
+       uint32_t                                serverOldestServerVersion;
+       
+       session = NULL;
+       dlog( kDebugLevelTrace, "\n" DEBUG_NAME "CheckVersion\n" );
+       
+       // Open a session to the server and send the request. Specify no thread since we are going to manually read the message.
+       
+       err = RMxSessionOpen( inServer, kRMxSessionFlagsNoThread, kInvalidSocketRef, NULL, NULL, &session, 
+               kRMxOpCodeCheckVersion, "www", kRMxCurrentVersion, kRMxOldestClientVersion, kRMxOldestServerVersion );
+       require_noerr( err, exit );
+       
+       // Receive the respons, parse it, and check the versions.
+       
+       err = RMxSessionRecvMessage( session, kRMxClientTimeout );
+       require_noerr( err, exit );
+       check( session->message.recvData || ( session->message.recvSize == 0 ) );
+       
+       err = RMxUnpack( session->message.recvData, session->message.recvSize, "wwww", 
+               &errorCode, &serverCurrentVersion, &serverOldestClientVersion, &serverOldestServerVersion );
+       require_noerr( err, exit );
+       
+       err = RMxCheckVersion( kRMxCurrentVersion, kRMxOldestClientVersion, kRMxOldestServerVersion, 
+                                                  serverCurrentVersion, serverOldestClientVersion, serverOldestServerVersion );
+       check( err == errorCode );
+       if( ( err == kNoErr ) && ( errorCode != kNoErr ) )
+       {
+               dlog( kDebugLevelWarning, DEBUG_NAME "client/server disagree on versions\n" );
+               err = errorCode;
+       }
+       
+exit:
+       if( session )
+       {
+               RMxSessionClose( session, kEndingErr );
+       }
+       return( err );
+}
+
+#if 0
+#pragma mark -
+#pragma mark == DNS-SD Properties ==
+#endif
+
+//===========================================================================================================================
+//     DNSServiceCopyProperty_client
+//===========================================================================================================================
+
+DNSServiceErrorType    DNSServiceCopyProperty_client( const char *inServer, DNSPropertyCode inCode, DNSPropertyData *outData )
+{      
+       DNSServiceErrorType             err;
+       RMxSessionRef                   session;
+       OSStatus                                errorCode;
+       DNSPropertyCode                 code;
+       const void *                    data;
+       size_t                                  size;
+       
+       session = NULL;
+       dlog( kDebugLevelTrace, "\n" DEBUG_NAME "CopyProperty server=%s, code='%C'\n", inServer ? inServer : "<local>", inCode );
+       require_action( outData, exit, err = kDNSServiceErr_BadParam );
+       
+       // Open a session to the server and send the request. Specify no thread since we are going to manually read the message.
+       
+       err = RMxSessionOpen( inServer, kRMxSessionFlagsNoThread, kInvalidSocketRef, NULL, NULL, &session, 
+               kRMxOpCodeCopyProperty, "w", inCode );
+       require_noerr( err, exit );
+       
+       // Receive the response, parse it, and check the versions.
+       
+       err = RMxSessionRecvMessage( session, kRMxClientTimeout );
+       require_noerr( err, exit );
+       check( session->message.recvData || ( session->message.recvSize == 0 ) );
+       
+       err = RMxUnpack( session->message.recvData, session->message.recvSize, "wwn", &errorCode, &code, &data, &size );
+       require_noerr( err, exit );
+       err = errorCode;
+       require_noerr_quiet( err, exit );
+       
+       // Decode the data and fill in the results.
+       
+       err = DNSServiceCopyPropertyDecodeData_client( code, data, size, outData );
+       require_noerr( err, exit );
+       
+exit:
+       if( session )
+       {
+               RMxSessionClose( session, kEndingErr );
+       }
+       return( err );
+}
+
+//===========================================================================================================================
+//     DNSServiceCopyProperty_client
+//===========================================================================================================================
+
+DEBUG_LOCAL DNSServiceErrorType
+       DNSServiceCopyPropertyDecodeData_client( 
+               DNSPropertyCode         inCode, 
+               const void *            inData, 
+               size_t                          inSize, 
+               DNSPropertyData *       outData )
+{
+       OSStatus                err;
+       
+       check( outData );
+       
+       switch( inCode )
+       {
+               case kDNSPropertyCodeVersion:
+                       outData->u.version.clientCurrentVersion                 = kRMxCurrentVersion;
+                       outData->u.version.clientOldestServerVersion    = kRMxOldestServerVersion;
+                       
+                       err = RMxUnpack( inData, inSize, "www", 
+                               &outData->u.version.serverCurrentVersion, &outData->u.version.serverOldestClientVersion, NULL );
+                       require_noerr( err, exit );
+                       break;
+               
+               default:
+                       dlog( kDebugLevelError, DEBUG_NAME "CopyPropertyDecodeData unknown property code (%C)\n", inCode );
+                       err = kDNSServiceErr_Unsupported;
+                       goto exit;
+       }
+       err = kDNSServiceErr_NoError;
+
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     DNSServiceReleaseProperty_client
+//===========================================================================================================================
+
+DNSServiceErrorType    DNSServiceReleaseProperty_client( DNSPropertyData *inData )
+{
+       OSStatus                err;
+       
+       dlog( kDebugLevelTrace, "\n" DEBUG_NAME "ReleaseProperty\n" );
+       require_action( inData, exit, err = kDNSServiceErr_BadParam );
+       
+       switch( inData->code )
+       {
+               case kDNSPropertyCodeVersion:
+                       // Data is embedded directly in the structure so there is nothing to release.
+                       break;
+                       
+               default:
+                       dlog( kDebugLevelError, DEBUG_NAME "ReleaseProperty unknown property code (%C)\n", inData->code );
+                       err = kDNSServiceErr_Unsupported;
+                       goto exit;
+       }
+       err = kDNSServiceErr_NoError;
+       
+exit:
+       return( err );
+}
+
+#if 0
+#pragma mark -
+#pragma mark == DNS-SD Domain Enumeration ==
+#endif
+
+//===========================================================================================================================
+//     DNSServiceEnumerateDomains_client
+//===========================================================================================================================
+
+DNSServiceErrorType
+       DNSServiceEnumerateDomains_client(
+               DNSServiceRef *                                 outRef,
+               const char *                                    inServer, 
+               const DNSServiceFlags                   inFlags,
+               const uint32_t                                  inInterfaceIndex,
+               const DNSServiceDomainEnumReply inCallBack,
+               void *                                                  inContext )
+{
+       DNSServiceErrorType             err;
+       DNSServiceRef                   obj;
+       
+       obj = NULL;
+       dlog( kDebugLevelTrace, "\n" DEBUG_NAME "EnumerateDomains flags=0x%08X, ifi=%d, server=%s\n", 
+               inFlags, inInterfaceIndex, inServer ? inServer : "<local>" );
+       require_action( outRef, exit, err = kDNSServiceErr_BadParam );
+       require_action( ( inFlags == kDNSServiceFlagsBrowseDomains ) || 
+                                       ( inFlags == kDNSServiceFlagsRegistrationDomains ), 
+                                       exit, err = kDNSServiceErr_BadFlags );
+       require_action( inCallBack, exit, err = kDNSServiceErr_BadParam );
+       
+       obj = (DNSServiceRef) calloc( 1, sizeof( *obj ) );
+       require_action( obj, exit, err = kDNSServiceErr_NoMemory );
+       
+       obj->context                    = inContext;
+       obj->u.domain.callback  = inCallBack;
+       
+       // Open a session to the server and send the request.
+       
+       err = RMxSessionOpen( inServer, kRMxSessionFlagsNoClose, kInvalidSocketRef, RMxClientMessageCallBack, obj, 
+               &obj->session, kRMxOpCodeEnumerateDomains, "ww", inFlags, inInterfaceIndex );
+       require_noerr( err, exit );
+       
+       // Success!
+       
+       *outRef = obj;
+       obj             = NULL;
+       
+exit:
+       if( obj )
+       {
+               DNSServiceRefDeallocate_client( obj );
+       }
+       return( err );
+}
+
+//===========================================================================================================================
+//     DNSServiceEnumerateDomainsReply_client
+//===========================================================================================================================
+
+DEBUG_LOCAL void       DNSServiceEnumerateDomainsReply_client( RMxMessage *inMessage )
+{
+       OSStatus                                err;
+       DNSServiceRef                   obj;
+       DNSServiceFlags                 flags;
+       uint32_t                                interfaceIndex;
+       DNSServiceErrorType             errorCode;
+       const char *                    domain;
+       
+       check( inMessage );
+       obj = (DNSServiceRef) inMessage->context;
+       check( obj );
+       
+       err = inMessage->status;
+       if( err == kNoErr )
+       {
+               err = RMxUnpack( inMessage->recvData, inMessage->recvSize, "wwws", &flags, &interfaceIndex, &errorCode, &domain, NULL );
+               check_noerr( err );
+               if( err == kNoErr )
+               {
+                       dlog( kDebugLevelTrace, DEBUG_NAME "EnumerateDomains reply flags=0x%08X, ifi=%d, err=%d, domain=\"%s\"\n", 
+                               flags, interfaceIndex, errorCode, domain );
+                       
+                       obj->u.domain.callback( obj, flags, interfaceIndex, errorCode, domain, obj->context );
+               }
+       }
+       if( err != kNoErr )
+       {
+               obj->u.domain.callback( obj, 0, 0, err, "", obj->context );
+       }
+}
+
+#if 0
+#pragma mark -
+#pragma mark == DNS-SD Service Registration ==
+#endif
+
+//===========================================================================================================================
+//     DNSServiceRegister_direct
+//===========================================================================================================================
+
+DNSServiceErrorType
+       DNSServiceRegister_client(
+               DNSServiceRef *                 outRef,
+               const char *                    inServer, 
+               DNSServiceFlags                 inFlags,
+               uint32_t                                inInterfaceIndex,
+               const char *                    inName,
+               const char *                    inType,
+               const char *                    inDomain,
+               const char *                    inHost,
+               uint16_t                                inPort,
+               uint16_t                                inTXTSize,
+               const void *                    inTXT,
+               DNSServiceRegisterReply inCallBack,
+               void *                                  inContext )
+{
+       DNSServiceErrorType             err;
+       DNSServiceRef                   obj;
+       
+       obj = NULL;
+       dlog( kDebugLevelTrace, "\n" DEBUG_NAME 
+               "Resolve flags=0x%08X, ifi=%d, name=\"%s\", type=\"%s\", domain=\"%s\", host=\"%s\", port=%d, txtSize=%d\n", 
+               inFlags, inInterfaceIndex, inName ? inName : "<default>", inType, inDomain ? inDomain : "<default>", inHost, 
+               ntohs( inPort ), inTXTSize );
+       require_action( outRef, exit, err = kDNSServiceErr_BadReference );
+       require_action( ( inFlags == 0 ) || ( inFlags == kDNSServiceFlagsNoAutoRename ), exit, err = kDNSServiceErr_BadFlags );
+       require_action( inType, exit, err = kDNSServiceErr_BadParam );
+       require_action( inTXT || ( inTXTSize == 0 ), exit, err = kDNSServiceErr_BadParam );
+       require_action( inCallBack, exit, err = kDNSServiceErr_BadParam );
+       
+       obj = (DNSServiceRef) calloc( 1, sizeof( *obj ) );
+       require_action( obj, exit, err = kDNSServiceErr_NoMemory );
+       
+       obj->context            = inContext;
+       obj->u.reg.callback     = inCallBack;
+       
+       // Open a session to the server and send the request.
+       
+       err = RMxSessionOpen( inServer, kRMxSessionFlagsNoClose, kInvalidSocketRef, RMxClientMessageCallBack, obj, 
+               &obj->session, kRMxOpCodeRegister, "wwsssshn", inFlags, inInterfaceIndex, inName ? inName : "", inType, 
+               inDomain ? inDomain : "", inHost, inPort, inTXTSize, inTXT );
+       require_noerr( err, exit );
+       
+       // Success!
+       
+       *outRef = obj;
+       obj             = NULL;
+       
+exit:
+       if( obj )
+       {
+               DNSServiceRefDeallocate_client( obj );
+       }
+       return( err );
+}
+
+//===========================================================================================================================
+//     DNSServiceRegisterReply_client
+//===========================================================================================================================
+
+DEBUG_LOCAL void       DNSServiceRegisterReply_client( RMxMessage *inMessage )
+{
+       OSStatus                                err;
+       DNSServiceRef                   obj;
+       DNSServiceFlags                 flags;
+       DNSServiceErrorType             errorCode;
+       const char *                    name;
+       const char *                    type;
+       const char *                    domain;
+       
+       check( inMessage );
+       obj = (DNSServiceRef) inMessage->context;
+       check( obj );
+       
+       err = inMessage->status;
+       if( err == kNoErr )
+       {
+               err = RMxUnpack( inMessage->recvData, inMessage->recvSize, "wwsss", 
+                       &flags, &errorCode, &name, NULL, &type, NULL, &domain, NULL );
+               check_noerr( err );
+               if( err == kNoErr )
+               {
+                       dlog( kDebugLevelTrace, DEBUG_NAME "Register reply flags=0x%08X, err=%d, name=\"%s\", type=\"%s\", domain=\"%s\"\n", 
+                               flags, errorCode, name, type, domain );
+                       
+                       obj->u.reg.callback( obj, flags, errorCode, name, type, domain, obj->context );
+               }
+       }
+       if( err != kNoErr )
+       {
+               obj->u.reg.callback( obj, 0, err, "", "", "", obj->context );
+       }
+}
+
+//===========================================================================================================================
+//     DNSServiceAddRecord_client
+//===========================================================================================================================
+
+DNSServiceErrorType
+       DNSServiceAddRecord_client(
+               DNSServiceRef   inRef,
+               DNSRecordRef *  outRecordRef,
+               DNSServiceFlags inFlags,
+               uint16_t                inRRType,
+               uint16_t                inRDataSize,
+               const void *    inRData,
+               uint32_t                inTTL )
+{
+       DNSServiceErrorType             err;
+       DNSRecordRef                    obj;
+       
+       obj = NULL;
+       RMxLock();
+       dlog( kDebugLevelTrace, "\n" DEBUG_NAME "AddRecord flags=0x%08X, rrType=%d, rrDataSize=%d, ttl=%d\n", 
+               inFlags, inRRType, inRDataSize, inTTL );
+       require_action( inRef, exit, err = kDNSServiceErr_BadReference );
+       require_action( inRef->session, exit, err = kDNSServiceErr_NotInitialized );
+       require_action( outRecordRef, exit, err = kDNSServiceErr_BadParam );
+       require_action( inFlags == 0, exit, err = kDNSServiceErr_BadFlags );
+       require_action( inRData && ( inRDataSize > 0 ), exit, err = kDNSServiceErr_BadParam );
+       
+       // Allocate and initialize the object.
+       
+       obj = (DNSRecordRef) calloc( 1, sizeof( *obj ) );
+       require_action( obj, exit, err = kDNSServiceErr_NoMemory );
+       
+       // Send the message. Use an ID that should be unique for the session and avoid the reserved ID.
+       
+       obj->id = ++inRef->u.reg.lastID;
+       if( obj->id == kDNSRecordIndexDefaultTXT )
+       {
+               obj->id = ++inRef->u.reg.lastID;
+       }
+       
+       err = RMxSessionSendMessage( inRef->session, kRMxOpCodeAddRecord, kNoErr, "wwhnw", 
+               obj->id, inFlags, inRRType, inRDataSize, inRData, inTTL );
+       require_noerr( err, exit );
+       
+       // Success!
+       
+       *outRecordRef   = obj;
+       obj                     = NULL;
+       
+exit:
+       if( obj )
+       {
+               free( obj );
+       }
+       RMxUnlock();
+       return( err );
+}
+
+//===========================================================================================================================
+//     DNSServiceUpdateRecord_client
+//===========================================================================================================================
+
+DNSServiceErrorType
+       DNSServiceUpdateRecord_client(
+           DNSServiceRef       inRef,
+           DNSRecordRef        inRecordRef,
+           DNSServiceFlags     inFlags,
+           uint16_t            inRDataSize,
+           const void *        inRData,
+           uint32_t            inTTL )
+{
+       DNSServiceErrorType             err;
+       
+       RMxLock();
+       dlog( kDebugLevelTrace, "\n" DEBUG_NAME "UpdateRecord flags=0x%08X, rrDataSize=%d, ttl=%d\n", inFlags, inRDataSize, inTTL );
+       require_action( inRef, exit, err = kDNSServiceErr_BadReference );
+       require_action( inRef->session, exit, err = kDNSServiceErr_NotInitialized );
+       require_action( inFlags == 0, exit, err = kDNSServiceErr_BadFlags );
+       require_action( inRData && ( inRDataSize > 0 ), exit, err = kDNSServiceErr_BadParam );
+       
+       err = RMxSessionSendMessage( inRef->session, kRMxOpCodeUpdateRecord, kNoErr, "wwnw", 
+               inRecordRef ? inRecordRef->id : kDNSRecordIndexDefaultTXT, inFlags, inRDataSize, inRData, inTTL );
+       require_noerr( err, exit );
+       
+exit:
+       RMxUnlock();
+       return( err );
+}
+
+//===========================================================================================================================
+//     DNSServiceRemoveRecord_client
+//===========================================================================================================================
+
+DNSServiceErrorType    DNSServiceRemoveRecord_client( DNSServiceRef inRef, DNSRecordRef inRecordRef, DNSServiceFlags inFlags )
+{
+       DNSServiceErrorType             err;
+       
+       RMxLock();
+       dlog( kDebugLevelTrace, "\n" DEBUG_NAME "RemoveRecord flags=0x%08X\n", inFlags );
+       require_action( inRef, exit, err = kDNSServiceErr_BadReference );
+       require_action( inRef->session, exit, err = kDNSServiceErr_NotInitialized );
+       require_action( inRecordRef, exit, err = kDNSServiceErr_BadReference );
+       require_action( inFlags == 0, exit, err = kDNSServiceErr_BadFlags );
+       
+       err = RMxSessionSendMessage( inRef->session, kRMxOpCodeRemoveRecord, kNoErr, "ww", inRecordRef->id, inFlags );
+       DNSServiceConnectionRecordRemove_client( inRef, inRecordRef );
+       free( inRecordRef );
+       require_noerr( err, exit );
+       
+exit:
+       RMxUnlock();
+       return( err );
+}
+
+#if 0
+#pragma mark -
+#pragma mark == DNS-SD Service Discovery ==
+#endif
+
+//===========================================================================================================================
+//     DNSServiceBrowse_direct
+//===========================================================================================================================
+
+DNSServiceErrorType
+       DNSServiceBrowse_client(
+               DNSServiceRef *                 outRef,
+               const char *                    inServer, 
+               DNSServiceFlags                 inFlags,
+               uint32_t                                inInterfaceIndex,
+               const char *                    inType,   
+               const char *                    inDomain,
+               DNSServiceBrowseReply   inCallBack,
+               void *                                  inContext )
+{
+       DNSServiceErrorType             err;
+       DNSServiceRef                   obj;
+       
+       obj = NULL;
+       dlog( kDebugLevelTrace, "\n" DEBUG_NAME "Browse flags=0x%08X, ifi=%d, type=\"%s\", domain=\"%s\"\n", 
+               inFlags, inInterfaceIndex, inType, inDomain ? inDomain : "<default>" );
+       require_action( outRef, exit, err = kDNSServiceErr_BadReference );
+       require_action( inFlags == 0, exit, err = kDNSServiceErr_BadFlags );
+       require_action( inType, exit, err = kDNSServiceErr_BadParam );
+       require_action( inCallBack, exit, err = kDNSServiceErr_BadParam );
+       
+       obj = (DNSServiceRef) calloc( 1, sizeof( *obj ) );
+       require_action( obj, exit, err = kDNSServiceErr_NoMemory );
+       
+       obj->context                    = inContext;
+       obj->u.browse.callback  = inCallBack;
+       
+       // Open a session to the server and send the request.
+       
+       err = RMxSessionOpen( inServer, kRMxSessionFlagsNoClose, kInvalidSocketRef, RMxClientMessageCallBack, obj, 
+               &obj->session, kRMxOpCodeBrowse, "wwss", inFlags, inInterfaceIndex, inType, inDomain ? inDomain : "" );
+       require_noerr( err, exit );
+       
+       // Success!
+       
+       *outRef = obj;
+       obj             = NULL;
+       
+exit:
+       if( obj )
+       {
+               DNSServiceRefDeallocate_client( obj );
+       }
+       return( err );
+}
+
+//===========================================================================================================================
+//     DNSServiceBrowseReply_client
+//===========================================================================================================================
+
+DEBUG_LOCAL void       DNSServiceBrowseReply_client( RMxMessage *inMessage )
+{
+       OSStatus                                err;
+       DNSServiceRef                   obj;
+       DNSServiceFlags                 flags;
+       uint32_t                                interfaceIndex;
+       DNSServiceErrorType             errorCode;
+       const char *                    name;
+       const char *                    type;
+       const char *                    domain;
+       
+       check( inMessage );
+       obj = (DNSServiceRef) inMessage->context;
+       check( obj );
+       
+       err = inMessage->status;
+       if( err == kNoErr )
+       {
+               err = RMxUnpack( inMessage->recvData, inMessage->recvSize, "wwwsss", 
+                       &flags, &interfaceIndex, &errorCode, &name, NULL, &type, NULL, &domain, NULL );
+               check_noerr( err );
+               if( err == kNoErr )
+               {
+                       dlog( kDebugLevelTrace, DEBUG_NAME 
+                               "Browse reply flags=0x%08X, ifi=%d, err=%d, name=\"%s\", type=\"%s\", domain=\"%s\"\n", 
+                               flags, interfaceIndex, errorCode, name, type, domain );
+                               
+                       obj->u.browse.callback( obj, flags, interfaceIndex, errorCode, name, type, domain, obj->context );
+               }
+       }
+       if( err != kNoErr )
+       {
+               obj->u.browse.callback( obj, 0, 0, err, "", "", "", obj->context );
+       }
+}
+
+#if 0
+#pragma mark -
+#endif
+
+//===========================================================================================================================
+//     DNSServiceResolve_direct
+//===========================================================================================================================
+
+DNSServiceErrorType
+       DNSServiceResolve_client(
+               DNSServiceRef *                 outRef,
+               const char *                    inServer, 
+               DNSServiceFlags                 inFlags,
+               uint32_t                                inInterfaceIndex,
+               const char *                    inName,     
+               const char *                    inType,  
+               const char *                    inDomain,   
+               DNSServiceResolveReply  inCallBack,
+               void *                                  inContext )
+{
+       DNSServiceErrorType             err;
+       DNSServiceRef                   obj;
+       
+       obj = NULL;
+       dlog( kDebugLevelTrace, "\n" DEBUG_NAME "Resolve flags=0x%08X, ifi=%d, name=\"%s\", type=\"%s\", domain=\"%s\"\n", 
+               inFlags, inInterfaceIndex, inName, inType, inDomain ? inDomain : "<default>" );
+       require_action( outRef, exit, err = kDNSServiceErr_BadReference );
+       require_action( inFlags == 0, exit, err = kDNSServiceErr_BadFlags );
+       require_action( inName, exit, err = kDNSServiceErr_BadParam );
+       require_action( inType, exit, err = kDNSServiceErr_BadParam );
+       require_action( inCallBack, exit, err = kDNSServiceErr_BadParam );
+       
+       obj = (DNSServiceRef) calloc( 1, sizeof( *obj ) );
+       require_action( obj, exit, err = kDNSServiceErr_NoMemory );
+       
+       obj->context                    = inContext;
+       obj->u.resolve.flags    = inFlags;
+       obj->u.resolve.callback = inCallBack;
+               
+       // Open a session to the server and send the request.
+       
+       err = RMxSessionOpen( inServer, kRMxSessionFlagsNoClose, kInvalidSocketRef, RMxClientMessageCallBack, obj, 
+               &obj->session, kRMxOpCodeResolve, "wwsss", inFlags, inInterfaceIndex, inName, inType, inDomain ? inDomain : "" );
+       require_noerr( err, exit );
+       
+       // Success!
+       
+       *outRef = obj;
+       obj             = NULL;
+       
+exit:
+       if( obj )
+       {
+               DNSServiceRefDeallocate_client( obj );
+       }
+       return( err );
+}
+
+//===========================================================================================================================
+//     DNSServiceResolveReply_client
+//===========================================================================================================================
+
+DEBUG_LOCAL void       DNSServiceResolveReply_client( RMxMessage *inMessage )
+{
+       OSStatus                                err;
+       DNSServiceRef                   obj;
+       DNSServiceFlags                 flags;
+       uint32_t                                interfaceIndex;
+       DNSServiceErrorType             errorCode;
+       const char *                    name;
+       const char *                    host;
+       uint16_t                                port;
+       const char *                    txt;
+       size_t                                  txtSize;
+       
+       check( inMessage );
+       obj = (DNSServiceRef) inMessage->context;
+       check( obj );
+       
+       err = inMessage->status;
+       if( err == kNoErr )
+       {
+               err = RMxUnpack( inMessage->recvData, inMessage->recvSize, "wwwsshn", 
+                       &flags, &interfaceIndex, &errorCode, &name, NULL, &host, NULL, &port, &txt, &txtSize );
+               check_noerr( err );
+               if( err == kNoErr )
+               {
+                       dlog( kDebugLevelTrace, DEBUG_NAME
+                               "Resolve reply flags=0x%08X, ifi=%d, err=%d, name=\"%s\", host=\"%s\", port=%d, txtSize=%d\n", 
+                               flags, interfaceIndex, errorCode, name, host, ntohs( port ), (int) txtSize );
+                       
+                       obj->u.resolve.callback( obj, flags, interfaceIndex, errorCode, name, host, port, (uint16_t) txtSize, txt, 
+                       obj->context );
+               }
+       }
+       if( err != kNoErr )
+       {
+               obj->u.resolve.callback( obj, 0, 0, err, "", "", 0, 0, NULL, obj->context );
+       }
+}
+
+#if 0
+#pragma mark -
+#pragma mark == DNS-SD Special Purpose ==
+#endif
+
+//===========================================================================================================================
+//     DNSServiceCreateConnection_client
+//===========================================================================================================================
+
+DNSServiceErrorType    DNSServiceCreateConnection_client( DNSServiceRef *outRef, const char *inServer )
+{
+       DNSServiceErrorType             err;
+       DNSServiceRef                   obj;
+       
+       obj = NULL;
+       dlog( kDebugLevelTrace, "\n" DEBUG_NAME "CreateConnection (server=\"%s\")\n", inServer ? inServer : "<local>" );
+       require_action( outRef, exit, err = kDNSServiceErr_BadReference );
+       
+       obj = (DNSServiceRef) calloc( 1, sizeof( *obj ) );
+       require_action( obj, exit, err = kDNSServiceErr_NoMemory );
+       
+       err = RMxSessionOpen( inServer, kRMxSessionFlagsNoClose, kInvalidSocketRef, RMxClientMessageCallBack, obj, 
+               &obj->session, kRMxOpCodeCreateConnection, "" );
+       require_noerr( err, exit );
+       
+       *outRef = obj;
+       obj             = NULL;
+       
+exit:
+       if( obj )
+       {
+               DNSServiceRefDeallocate_client( obj );
+       }
+       return( err );
+}
+
+//===========================================================================================================================
+//     DNSServiceConnectionRecordRemove_client
+//
+//     Warning: Assumes the RMx lock is held (or is not needed due to a single thread having exclusive access).
+//===========================================================================================================================
+
+DEBUG_LOCAL DNSRecordRef       DNSServiceConnectionRecordRemove_client( DNSServiceRef inRef, DNSRecordRef inRecordRef )
+{
+       DNSRecordRef *          p;
+       
+       for( p = &inRef->records; *p; p = &( *p )->next )
+       {
+               if( *p == inRecordRef )
+               {
+                       break;
+               }
+       }
+       inRecordRef = *p;
+       if( inRecordRef )
+       {
+               *p = inRecordRef->next;
+       }
+       return( inRecordRef );
+}
+
+//===========================================================================================================================
+//     DNSServiceRegisterRecord_client
+//===========================================================================================================================
+
+DNSServiceErrorType
+       DNSServiceRegisterRecord_client(
+               DNSServiceRef                                   inRef,
+               DNSRecordRef *                                  outRecordRef,
+               DNSServiceFlags                                 inFlags,
+               uint32_t                                                inInterfaceIndex,
+               const char *                                    inName,   
+               uint16_t                                                inRRType,
+               uint16_t                                                inRRClass,
+               uint16_t                                                inRDataSize,
+               const void *                                    inRData,
+               uint32_t                                                inTTL,
+               DNSServiceRegisterRecordReply   inCallBack,
+               void *                                                  inContext )
+{
+       DNSServiceErrorType             err;
+       DNSRecordRef                    obj;
+       
+       DEBUG_UNUSED( inContext );
+       
+       obj = NULL;
+       RMxLock();
+       dlog( kDebugLevelTrace, "\n" DEBUG_NAME 
+               "RegisterRecord flags=0x%08X, ifi=%d, name=\"%s\" rrType=0x%04X, rrClass=0x%04X, rDataSize=%d, ttl=%d\n", 
+               inFlags, inInterfaceIndex, inName, inRRType, inRRClass, inRDataSize, inTTL );
+       require_action( inRef, exit, err = kDNSServiceErr_BadReference );
+       require_action( inRef->session, exit, err = kDNSServiceErr_NotInitialized );
+       require_action( outRecordRef, exit, err = kDNSServiceErr_BadParam );
+       require_action( ( inFlags == kDNSServiceFlagsShared ) || ( inFlags == kDNSServiceFlagsUnique ), 
+                                       exit, err = kDNSServiceErr_BadFlags );
+       require_action( inName, exit, err = kDNSServiceErr_BadParam );
+       require_action( inRData && ( inRDataSize > 0 ), exit, err = kDNSServiceErr_BadParam );
+       require_action( inCallBack, exit, err = kDNSServiceErr_BadFlags );
+       
+       // Allocate and initialize the object.
+       
+       obj = (DNSRecordRef) calloc( 1, sizeof( *obj ) );
+       require_action( obj, exit, err = kDNSServiceErr_NoMemory );
+       
+       obj->callback = inCallBack;
+       obj->context  = inContext;
+       
+       // Set up a unique ID for the session, avoiding the reserved ID 0, add the record, then send the message.
+       
+       obj->id = ++inRef->u.connection.lastID;
+       if( obj->id == kDNSRecordIndexDefaultTXT )
+       {
+               obj->id = ++inRef->u.connection.lastID;
+       }
+       obj->next = inRef->records;
+       inRef->records = obj;
+       
+       err = RMxSessionSendMessage( inRef->session, kRMxOpCodeRegisterRecord, kNoErr, "wwwshhnw", 
+               obj->id, inFlags, inInterfaceIndex, inName, inRRType, inRRClass, inRDataSize, inRData, inTTL );
+       require_noerr( err, exit );
+       
+       // Success!
+       
+       *outRecordRef   = obj;
+       obj                     = NULL;
+       
+exit:
+       if( obj )
+       {
+               DNSServiceConnectionRecordRemove_client( inRef, obj );
+               free( obj );
+       }
+       RMxUnlock();
+       return( err );
+}
+
+//===========================================================================================================================
+//     DNSServiceRegisterRecordReply_client
+//===========================================================================================================================
+
+DEBUG_LOCAL void       DNSServiceRegisterRecordReply_client( RMxMessage *inMessage )
+{
+       OSStatus                                err;
+       DNSServiceRef                   obj;
+       DNSServiceFlags                 flags;
+       DNSServiceErrorType             errorCode;
+       uint32_t                                id;
+       DNSRecordRef                    record;
+       
+       check( inMessage );
+       obj = (DNSServiceRef) inMessage->context;
+       check( obj );
+       
+       record = NULL;
+       err = inMessage->status;
+       if( err == kNoErr )
+       {
+               err = RMxUnpack( inMessage->recvData, inMessage->recvSize, "www", &flags, &errorCode, &id );
+               check_noerr( err );
+               if( err == kNoErr )
+               {
+                       RMxLock();
+                       for( record = obj->records; record; record = record->next )
+                       {
+                               if( record->id == id )
+                               {
+                                       break;
+                               }
+                       }
+                       RMxUnlock();
+                       if( !record )
+                       {
+                               dlog( kDebugLevelError, DEBUG_NAME "RegisterRecord reply with unknown record ID (%d)\n", id );
+                               err = kNotFoundErr;
+                       }
+                       if( err == kNoErr )
+                       {
+                               dlog( kDebugLevelTrace, DEBUG_NAME "RegisterRecord reply id=%d, flags=0x%08X, err=%d\n", id, flags, errorCode );
+                                               
+                               record->callback( obj, record, flags, errorCode, record->context );
+                       }
+               }
+       }
+       if( err != kNoErr )
+       {
+               check( record );
+               if( record )
+               {
+                       record->callback( obj, NULL, 0, err, NULL );
+               }
+       }
+}
+
+//===========================================================================================================================
+//     DNSServiceQueryRecord_client
+//===========================================================================================================================
+
+DNSServiceErrorType
+       DNSServiceQueryRecord_client(
+               DNSServiceRef *                         outRef,
+               const char *                            inServer, 
+               DNSServiceFlags                         inFlags,
+               uint32_t                                        inInterfaceIndex,
+               const char *                            inName,     
+               uint16_t                                        inRRType,
+               uint16_t                                        inRRClass,
+               DNSServiceQueryRecordReply      inCallBack,
+               void *                                          inContext )
+{
+       DNSServiceErrorType             err;
+       DNSServiceRef                   obj;
+       
+       obj = NULL;
+       dlog( kDebugLevelTrace, "\n" DEBUG_NAME "QueryRecord flags=0x%08X, ifi=%d, name=\"%s\", rrType=%d, rrClass=%d\n", 
+               inFlags, inInterfaceIndex, inName, inRRType, inRRClass );
+       require_action( outRef, exit, err = kDNSServiceErr_BadReference );
+       require_action( inFlags == 0, exit, err = kDNSServiceErr_BadFlags );
+       require_action( inName, exit, err = kDNSServiceErr_BadParam );
+       require_action( inCallBack, exit, err = kDNSServiceErr_BadFlags );
+       
+       obj = (DNSServiceRef) calloc( 1, sizeof( *obj ) );
+       require_action( obj, exit, err = kDNSServiceErr_NoMemory );
+       
+       obj->context                    = inContext;
+       obj->u.query.callback   = inCallBack;
+       
+       // Open a session to the server and send the request.
+       
+       err = RMxSessionOpen( inServer, kRMxSessionFlagsNoClose, kInvalidSocketRef, RMxClientMessageCallBack, obj, 
+               &obj->session, kRMxOpCodeQueryRecord, "wwshh", inFlags, inInterfaceIndex, inName, inRRType, inRRClass );
+       require_noerr( err, exit );
+       
+       // Success!
+       
+       *outRef = obj;
+       obj             = NULL;
+       
+exit:
+       if( obj )
+       {
+               DNSServiceRefDeallocate_client( obj );
+       }
+       return( err );
+}
+
+//===========================================================================================================================
+//     DNSServiceQueryRecordReply_client
+//===========================================================================================================================
+
+DEBUG_LOCAL void       DNSServiceQueryRecordReply_client( RMxMessage *inMessage )
+{
+       OSStatus                                err;
+       DNSServiceRef                   obj;
+       DNSServiceFlags                 flags;
+       uint32_t                                interfaceIndex;
+       DNSServiceErrorType             errorCode;
+       const char *                    name;
+       uint16_t                                rrType;
+       uint16_t                                rrClass;
+       uint8_t *                               rData;
+       size_t                                  rDataSize;
+       uint32_t                                ttl;
+       
+       check( inMessage );
+       obj = (DNSServiceRef) inMessage->context;
+       check( obj );
+       
+       err = inMessage->status;
+       if( err == kNoErr )
+       {
+               err = RMxUnpack( inMessage->recvData, inMessage->recvSize, "wwwshhnw", 
+                       &flags, &interfaceIndex, &errorCode, &name, NULL, &rrType, &rrClass, &rData, &rDataSize, &ttl );
+               check_noerr( err );
+               if( err == kNoErr )
+               {
+                       dlog( kDebugLevelTrace, DEBUG_NAME
+                               "QueryRecord reply flags=0x%08X, ifi=%d, err=%d, name=\"%s\", rrType=%d, rrClass=%d, rDataSize=%d, ttl=%d\n", 
+                               flags, interfaceIndex, errorCode, name, rrType, rrClass, rDataSize, ttl );
+                       
+                       obj->u.query.callback( obj, flags, interfaceIndex, errorCode, name, rrType, rrClass, (uint16_t) rDataSize, rData, 
+                               ttl, obj->context );
+               }
+       }
+       if( err != kNoErr )
+       {
+               obj->u.query.callback( obj, 0, 0, err, "", 0, 0, 0, NULL, 0, obj->context );
+       }
+}
+
+//===========================================================================================================================
+//     DNSServiceReconfirmRecord_client
+//===========================================================================================================================
+
+void
+       DNSServiceReconfirmRecord_client(
+               const char *    inServer, 
+               DNSServiceFlags inFlags,
+               uint32_t                inInterfaceIndex,
+               const char *    inName,   
+               uint16_t                inRRType,
+               uint16_t                inRRClass,
+               uint16_t                inRDataSize,
+               const void *    inRData )
+{
+       DNSServiceErrorType             err;
+       
+       dlog( kDebugLevelTrace, "\n" DEBUG_NAME "ReconfirmRecord flags=0x%08X, ifi=%d, name=\"%s\", rrType=%d, rrClass=%d\n", 
+               inFlags, inInterfaceIndex, inName, inRRType, inRRClass );
+       require_action( inFlags == 0, exit, err = kDNSServiceErr_BadFlags );
+       require_action( inName, exit, err = kDNSServiceErr_BadParam );
+       require_action( inRData && ( inRDataSize > 0 ), exit, err = kDNSServiceErr_BadParam );
+               
+       err = RMxSessionOpen( inServer, kRMxSessionFlagsNoClose, kInvalidSocketRef, NULL, NULL, NULL, 
+               kRMxOpCodeReconfirmRecord, "wwshhn", inFlags, inInterfaceIndex, inName, inRRType, inRRClass, inRDataSize, inRData );
+       require_noerr( err, exit );
+       
+exit:
+       return;
+}
+
+#ifdef __cplusplus
+       }
+#endif
diff --git a/mDNSWindows/RMxClient.h b/mDNSWindows/RMxClient.h
new file mode 100644 (file)
index 0000000..798f9e9
--- /dev/null
@@ -0,0 +1,307 @@
+/*
+ * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+
+$Log: RMxClient.h,v $
+Revision 1.1  2004/01/30 02:35:13  bradley
+Rendezvous Message Exchange implementation for DNS-SD IPC on Windows.
+
+*/
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @header         RMxClient.h
+       
+       @abstract       Client-side implementation of the DNS-SD IPC API.
+       
+       @discussion     
+       
+       This handles sending and receiving messages from the service to perform DNS-SD operations and get DNS-SD responses.
+*/
+
+#ifndef __RMx_CLIENT__
+#define __RMx_CLIENT__
+
+#include       "DNSSD.h"
+
+#ifdef __cplusplus
+       extern "C" {
+#endif
+
+#if 0
+#pragma mark == RMx ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       RMxClientInitialize
+
+       @abstract       Initializes RMx for client usage. This must be called before any RMx functions are called.
+*/
+
+OSStatus       RMxClientInitialize( void );
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       RMxClientFinalize
+
+       @abstract       Finalizes client usage of RMx. No RMx calls should be made after this call is made.
+*/
+
+void           RMxClientFinalize( void );
+
+#if 0
+#pragma mark == DNS-SD General ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       DNSServiceRefDeallocate_client
+
+       @abstract       Client-side version of DNSServiceRefDeallocate.
+*/
+
+void   DNSServiceRefDeallocate_client( DNSServiceRef inRef );
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       DNSServiceCheckVersion_client
+
+       @abstract       Client-side version of DNSServiceCheckVersion.
+*/
+
+DNSServiceErrorType    DNSServiceCheckVersion_client( const char *inServer );
+
+#if 0
+#pragma mark == DNS-SD Properties ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       DNSServiceCopyProperty_client
+
+       @abstract       Client-side version of DNSServiceCopyProperty.
+*/
+
+DNSServiceErrorType    DNSServiceCopyProperty_client( const char *inServer, DNSPropertyCode inCode, DNSPropertyData *outData );
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       DNSServiceReleaseProperty_client
+
+       @abstract       Client-side version of DNSServiceReleaseProperty.
+*/
+
+DNSServiceErrorType    DNSServiceReleaseProperty_client( DNSPropertyData *inData );
+
+#if 0
+#pragma mark == DNS-SD Domain Enumeration ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       DNSServiceEnumerateDomains_client
+
+       @abstract       Client-side version of DNSServiceEnumerateDomains.
+*/
+
+DNSServiceErrorType
+       DNSServiceEnumerateDomains_client(
+               DNSServiceRef *                                 outRef,
+               const char *                                    inServer, 
+               const DNSServiceFlags                   inFlags,
+               const uint32_t                                  inInterfaceIndex,
+               const DNSServiceDomainEnumReply inCallBack,
+               void *                                                  inContext );
+
+#if 0
+#pragma mark == DNS-SD Service Registration ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       DNSServiceRegister_client
+
+       @abstract       Client-side version of DNSServiceRegister.
+*/
+
+DNSServiceErrorType
+       DNSServiceRegister_client(
+               DNSServiceRef *                 outRef,
+               const char *                    inServer, 
+               DNSServiceFlags                 inFlags,
+               uint32_t                                inInterfaceIndex,
+               const char *                    inName,
+               const char *                    inType,
+               const char *                    inDomain,
+               const char *                    inHost,
+               uint16_t                                inPort,
+               uint16_t                                inTXTSize,
+               const void *                    inTXT,
+               DNSServiceRegisterReply inCallBack,
+               void *                                  inContext );
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       DNSServiceAddRecord_client
+
+       @abstract       Client-side version of DNSServiceAddRecord.
+*/
+
+DNSServiceErrorType
+       DNSServiceAddRecord_client(
+               DNSServiceRef   inRef,
+               DNSRecordRef *  outRecordRef,
+               DNSServiceFlags inFlags,
+               uint16_t                inRRType,
+               uint16_t                inRDataSize,
+               const void *    inRData,
+               uint32_t                inTTL );
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       DNSServiceUpdateRecord_client
+
+       @abstract       Client-side version of DNSServiceUpdateRecord.
+*/
+
+DNSServiceErrorType
+       DNSServiceUpdateRecord_client(
+           DNSServiceRef       inRef,
+           DNSRecordRef        inRecordRef,
+           DNSServiceFlags     inFlags,
+           uint16_t            inRDataSize,
+           const void *        inRData,
+           uint32_t            inTTL );
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       DNSServiceRemoveRecord_client
+
+       @abstract       Client-side version of DNSServiceRemoveRecord.
+*/
+
+DNSServiceErrorType    DNSServiceRemoveRecord_client( DNSServiceRef inRef, DNSRecordRef inRecordRef, DNSServiceFlags inFlags );
+
+#if 0
+#pragma mark == DNS-SD Service Discovery ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       DNSServiceBrowse_client
+
+       @abstract       Client-side version of DNSServiceBrowse.
+*/
+
+DNSServiceErrorType
+       DNSServiceBrowse_client(
+               DNSServiceRef *                 outRef,
+               const char *                    inServer, 
+               DNSServiceFlags                 inFlags,
+               uint32_t                                inInterfaceIndex,
+               const char *                    inType,   
+               const char *                    inDomain,
+               DNSServiceBrowseReply   inCallBack,
+               void *                                  inContext );
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       DNSServiceResolve_client
+
+       @abstract       Client-side version of DNSServiceResolve.
+*/
+
+DNSServiceErrorType
+       DNSServiceResolve_client(
+               DNSServiceRef *                 outRef,
+               const char *                    inServer, 
+               DNSServiceFlags                 inFlags,
+               uint32_t                                inInterfaceIndex,
+               const char *                    inName,     
+               const char *                    inType,  
+               const char *                    inDomain,   
+               DNSServiceResolveReply  inCallBack,
+               void *                                  inContext );
+
+#if 0
+#pragma mark == DNS-SD Special Purpose ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       DNSServiceCreateConnection_client
+
+       @abstract       Client-side version of DNSServiceCreateConnection.
+*/
+
+DNSServiceErrorType    DNSServiceCreateConnection_client( DNSServiceRef *outRef, const char *inServer );
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       DNSServiceRegisterRecord_client
+
+       @abstract       Client-side version of DNSServiceRegisterRecord.
+*/
+
+DNSServiceErrorType
+       DNSServiceRegisterRecord_client(
+               DNSServiceRef                                   inRef,
+               DNSRecordRef *                                  outRecordRef,
+               DNSServiceFlags                                 inFlags,
+               uint32_t                                                inInterfaceIndex,
+               const char *                                    inName,   
+               uint16_t                                                inRRType,
+               uint16_t                                                inRRClass,
+               uint16_t                                                inRDataSize,
+               const void *                                    inRData,
+               uint32_t                                                inTTL,
+               DNSServiceRegisterRecordReply   inCallBack,
+               void *                                                  inContext );
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       DNSServiceQueryRecord_client
+
+       @abstract       Client-side version of DNSServiceQueryRecord.
+*/
+
+DNSServiceErrorType
+       DNSServiceQueryRecord_client(
+               DNSServiceRef *                         outRef,
+               const char *                            inServer, 
+               DNSServiceFlags                         inFlags,
+               uint32_t                                        inInterfaceIndex,
+               const char *                            inName,     
+               uint16_t                                        inRRType,
+               uint16_t                                        inRRClass,
+               DNSServiceQueryRecordReply      inCallBack,
+               void *                                          inContext );
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       DNSServiceReconfirmRecord_client
+
+       @abstract       Client-side version of DNSServiceReconfirmRecord.
+*/
+
+void
+       DNSServiceReconfirmRecord_client(
+               const char *    inServer, 
+               DNSServiceFlags inFlags,
+               uint32_t                inInterfaceIndex,
+               const char *    inName,   
+               uint16_t                inRRType,
+               uint16_t                inRRClass,
+               uint16_t                inRDataSize,
+               const void *    inRData );
+
+#ifdef __cplusplus
+       }
+#endif
+
+#endif  // __RMx_CLIENT__
diff --git a/mDNSWindows/RMxCommon.c b/mDNSWindows/RMxCommon.c
new file mode 100644 (file)
index 0000000..686ee93
--- /dev/null
@@ -0,0 +1,1501 @@
+/*
+ * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+    
+$Log: RMxCommon.c,v $
+Revision 1.2  2004/03/16 22:09:03  bradley
+Skip socket creation failures to handle local IPv6 addresses being returned by Windows even when
+they are not actually supported by the OS; Log a message and only fail if no sockets can be created.
+
+Revision 1.1  2004/01/30 02:35:13  bradley
+Rendezvous Message Exchange implementation for DNS-SD IPC on Windows.
+
+*/
+
+#include       <stdlib.h>
+#include       <stdio.h>
+#include       <string.h>
+
+#include       "CommonServices.h"
+
+#include       <process.h>
+
+#include       "RMxCommon.h"
+
+#ifdef __cplusplus
+       extern "C" {
+#endif
+
+//===========================================================================================================================
+//     Constants
+//===========================================================================================================================
+
+#define        DEBUG_NAME                                              "[RMxCommon] "
+
+#define        kRMxSessionOpenValidFlags               ( kRMxSessionFlagsNoThread | kRMxSessionFlagsNoClose )
+
+#if 0
+#pragma mark == Prototypes ==
+#endif
+
+//===========================================================================================================================
+//     Prototypes
+//===========================================================================================================================
+
+// Session
+
+DEBUG_LOCAL unsigned WINAPI    RMxSessionThread( LPVOID inParam );
+DEBUG_LOCAL OSStatus           RMxSessionInitServer( RMxSessionRef inSession );
+DEBUG_LOCAL OSStatus           RMxSessionInitClient( RMxSessionRef inSession, const char *inServer );
+DEBUG_LOCAL OSStatus           RMxSessionConnect( RMxSessionRef inSession, const struct sockaddr *inAddr, size_t inAddrSize );
+DEBUG_LOCAL OSStatus
+       RMxSessionSendMessageVAList( 
+               RMxSessionRef   inSession, 
+               RMxOpCode               inOpCode, 
+               OSStatus                inStatus, 
+               const char *    inFormat, 
+               va_list                 inArgs1, 
+               va_list                 inArgs2 );
+
+#if 0
+#pragma mark == Globals ==
+#endif
+
+//===========================================================================================================================
+//     Globals
+//===========================================================================================================================
+
+// General
+
+DEBUG_LOCAL CRITICAL_SECTION           gRMxLock;
+DEBUG_LOCAL bool                                       gRMxLockInitialized             = false;
+DEBUG_LOCAL RMxSessionRef                      gRMxSessionList                 = NULL;
+RMxState                                                       gRMxState                               = kRMxStateInvalid;
+HANDLE                                                         gRMxStateChangeEvent    = NULL;
+
+#if 0
+#pragma mark -
+#pragma mark == General ==
+#endif
+
+//===========================================================================================================================
+//     RMxInitialize
+//===========================================================================================================================
+
+OSStatus       RMxInitialize( void )
+{
+       OSStatus                err;
+       WSADATA                 wsaData;
+       
+       // Set up WinSock.
+       
+       err = WSAStartup( MAKEWORD( 2, 2 ), &wsaData );
+       require_noerr( err, exit );
+       require_action( ( LOBYTE( wsaData.wVersion ) == 2 ) && ( HIBYTE( wsaData.wVersion ) == 2 ), exit, err = kUnsupportedErr );
+       
+       // Set up the global locked used to protect things like the session list.
+       
+       InitializeCriticalSection( &gRMxLock );
+       gRMxLockInitialized = true;
+       
+       // Set up the state and state changed event. A manual-reset event is used so all threads wake up when it is signaled.
+       
+       gRMxState = kRMxStateInvalid;
+       gRMxStateChangeEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
+       err = translate_errno( gRMxStateChangeEvent, errno_compat(), kNoResourcesErr );
+       require_noerr( err, exit );
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     RMxFinalize
+//===========================================================================================================================
+
+void   RMxFinalize( void )
+{
+       BOOL                    ok;
+       OSStatus                err;
+       
+       // Signal a state changed event to trigger everything to stop. Note: This is a manual-reset event so it will 
+       // remain signaled to allow all running threads to wake up and exit cleanly.
+       
+       gRMxState = kRMxStateStop;
+       if( gRMxStateChangeEvent )
+       {
+               ok = SetEvent( gRMxStateChangeEvent );
+               check_translated_errno( ok, errno_compat(), kUnknownErr );
+       }
+       
+       // Close any open sessions.
+       
+       while( gRMxSessionList )
+       {
+               err = RMxSessionClose( gRMxSessionList, kEndingErr );
+               check( ( err == kNoErr ) || ( err == kNotFoundErr ) );
+       }
+       
+       // Release the state changed event.
+       
+       if( gRMxStateChangeEvent )
+       {
+               ok = CloseHandle( gRMxStateChangeEvent );
+               check_translated_errno( ok, errno_compat(), kUnknownErr );
+               gRMxStateChangeEvent = NULL;
+       }
+       
+       // Release the lock.
+       
+       if( gRMxLockInitialized )
+       {
+               gRMxLockInitialized = false;
+               DeleteCriticalSection( &gRMxLock );
+       }
+       
+       // Tear down WinSock.
+       
+       WSACleanup();
+}
+
+//===========================================================================================================================
+//     RMxLock
+//===========================================================================================================================
+
+void   RMxLock( void )
+{
+       check( gRMxLockInitialized );
+       if( gRMxLockInitialized )
+       {
+               EnterCriticalSection( &gRMxLock );
+       }
+}
+
+//===========================================================================================================================
+//     RMxUnlock
+//===========================================================================================================================
+
+void   RMxUnlock( void )
+{
+       check( gRMxLockInitialized );
+       if( gRMxLockInitialized )
+       {
+               LeaveCriticalSection( &gRMxLock );
+       }
+}
+
+#if 0
+#pragma mark -
+#pragma mark == Messages ==
+#endif
+
+//===========================================================================================================================
+//     RMxMessageInitialize
+//===========================================================================================================================
+
+void   RMxMessageInitialize( RMxMessage *inMessage )
+{
+       check( inMessage );
+       if( inMessage )
+       {
+               inMessage->sendSize     = 0;
+               inMessage->sendData     = NULL;
+               inMessage->recvSize     = 0;
+               inMessage->recvData     = NULL;
+               inMessage->bufferSize   = 0;
+               inMessage->buffer               = NULL;
+       }
+}
+
+//===========================================================================================================================
+//     RMxMessageRelease
+//===========================================================================================================================
+
+void   RMxMessageRelease( RMxMessage *inMessage )
+{
+       check( inMessage );
+       if( inMessage )
+       {
+               // Assert if a malloc'd buffer was used for a small message that could have used the inline message buffer.
+               
+               check(  !inMessage->recvData                                                                    || 
+                          ( inMessage->recvSize > sizeof( inMessage->storage ) )       || 
+                          ( inMessage->recvData == inMessage->storage ) );
+               
+               // Free the memory if it was malloc'd (non-null and not the inline message buffer).
+               
+               if( inMessage->recvData && ( inMessage->recvData != inMessage->storage ) )
+               {
+                       free( inMessage->recvData );
+               }
+               inMessage->recvData = NULL;
+       }
+}
+
+#if 0
+#pragma mark -
+#pragma mark == Sessions ==
+#endif
+
+//===========================================================================================================================
+//     RMxSessionOpen
+//===========================================================================================================================
+
+OSStatus
+       RMxSessionOpen( 
+               const char *            inServer, 
+               RMxSessionFlags         inFlags, 
+               SocketRef                       inSock, 
+               RMxMessageCallBack      inCallBack, 
+               void *                          inContext, 
+               RMxSessionRef *         outSession, 
+               RMxOpCode                       inMessageOpCode, 
+               const char *            inMessageFormat, 
+               ... )
+{
+       OSStatus                        err;
+       RMxSessionRef           session;
+       DWORD                           result;
+       bool                            locked;
+       
+       session = NULL;
+       locked  = false;
+       dlog( kDebugLevelNotice, DEBUG_NAME "opening %s session to %s\n", IsValidSocket( inSock ) ? "server" : "client", 
+               inServer ? inServer : "<local>" );
+       require_action( gRMxState == kRMxStateRun, exit, err = kStateErr );
+       require_action( ( inFlags & ~kRMxSessionOpenValidFlags ) == 0, exit, err = kFlagErr );
+       
+       // Allocate and initialize the object and add it to the session list.
+       
+       session = (RMxSessionRef) calloc( 1, sizeof( *session ) );
+       require_action( session, exit, err = kNoMemoryErr );
+       
+       session->flags                                  = inFlags;                              
+       session->sock                                   = kInvalidSocketRef;    
+       session->callback                               = inCallBack;
+       RMxMessageInitialize( &session->message );
+       session->message.context                = inContext;
+       session->message.session                = session;
+       session->messageRecvBuffer              = session->message.storage;
+       session->messageRecvBufferPtr   = session->messageRecvBuffer;
+       session->messageRecvRemaining   = kRMxMessageHeaderSize;
+       session->messageRecvHeaderDone  = false;
+       
+       RMxLock();
+       session->next   = gRMxSessionList;
+       gRMxSessionList = session;
+       RMxUnlock();
+       
+       session->closeEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
+       err = translate_errno( session->closeEvent, errno_compat(), kNoResourcesErr );
+       require_noerr( err, exit );
+       
+       // Set up the sockets and socket events.
+       
+       if( IsValidSocket( inSock ) )
+       {
+               // Server: accepted a connection from a client.
+               
+               session->flags |= kRMxSessionFlagsServer;
+               session->sock   = inSock;
+               inSock                  = kInvalidSocketRef;
+               
+               err = RMxSessionInitServer( session );
+               require_noerr( err, exit );
+       }
+       else
+       {
+               // Client: initiate a connection to the server.
+               
+               err = RMxSessionInitClient( session, inServer );
+               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>.
+       // Create the thread suspended then resume it so the thread handle and ID are valid before the thread starts running.
+       
+       RMxLock();
+       locked = true;
+       if( !( inFlags & kRMxSessionFlagsNoThread ) )
+       {
+               session->thread = (HANDLE) _beginthreadex_compat( NULL, 0, RMxSessionThread, session, CREATE_SUSPENDED, &session->threadID );
+               err = translate_errno( session->thread, errno_compat(), kNoResourcesErr );
+               require_noerr( err, exit );
+               
+               result = ResumeThread( session->thread );
+               err = translate_errno( result != (DWORD) -1, errno_compat(), kNoResourcesErr );
+               require_noerr( err, exit );
+       }
+       
+       // Send the optional message. Note: we have to do 2 va_start/va_end because va_copy is not widely supported yet.
+       
+       if( inMessageFormat )
+       {
+               va_list         args1;
+               va_list         args2;
+               
+               va_start( args1, inMessageFormat );
+               va_start( args2, inMessageFormat );
+               err = RMxSessionSendMessageVAList( session, inMessageOpCode, kNoErr, inMessageFormat, args1, args2 );
+               va_end( args1 );
+               va_end( args2 );
+               require_noerr( err, exit );
+       }
+       
+       // Success!
+       
+       if( outSession )
+       {
+               *outSession     = session;
+       }
+       session = NULL;
+       
+exit:
+       if( locked )
+       {
+               RMxUnlock();
+       }
+       if( session )
+       {
+               RMxSessionClose( session, err );
+       }
+       if( IsValidSocket( inSock ) )
+       {
+               close_compat( inSock );
+       }
+       return( err );
+}
+
+//===========================================================================================================================
+//     RMxSessionClose
+//===========================================================================================================================
+
+OSStatus       RMxSessionClose( RMxSessionRef inSession, OSStatus inReason )
+{
+       OSStatus                        err;
+       bool                            locked;
+       RMxSessionRef *         p;
+       bool                            sameThread;
+       bool                            deferClose;
+       BOOL                            ok;
+       DWORD                           threadID;
+       DWORD                           result;
+       
+       DEBUG_USE_ONLY( inReason );
+       
+       check( inSession );
+       
+       // Find the session in the list.
+       
+       RMxLock();
+       locked = true;
+       
+       for( p = &gRMxSessionList; *p; p = &( *p )->next )
+       {
+               if( *p == inSession )
+               {
+                       break;
+               }
+       }
+       require_action( *p, exit, err = kNotFoundErr );
+       
+       // If we're being called from the same thread as the session (e.g. message callback is closing the session) then 
+       // we must defer the close until the thread is done because the thread is still using the session object.
+       
+       deferClose      = false;
+       threadID        = GetCurrentThreadId();
+       sameThread      = inSession->thread && ( threadID == inSession->threadID );
+       if( sameThread && !( inSession->flags & kRMxSessionFlagsThreadDone ) )
+       {
+               inSession->flags &= ~kRMxSessionFlagsNoClose;
+               deferClose = true;
+       }
+       
+       // If the thread we're not being called from the session thread, but the thread has already marked itself as
+       // as done (e.g. session closed from something like a peer disconnect and at the same time the client also 
+       // tried to close) then we only want to continue with the close if the thread is not going to close itself.
+       
+       if( !sameThread && ( inSession->flags & kRMxSessionFlagsThreadDone ) && !( inSession->flags & kRMxSessionFlagsNoClose ) )
+       {
+               deferClose = true;
+       }
+       
+       // Signal a close so the thread exits.
+       
+       inSession->quit = true;
+       if( inSession->closeEvent )
+       {
+               ok = SetEvent( inSession->closeEvent );
+               check_translated_errno( ok, errno_compat(), kUnknownErr );
+       }       
+       if( deferClose )
+       {
+               err = kNoErr;
+               goto exit;
+       }
+       inSession->flags |= kRMxSessionFlagsNoClose;
+       
+       // Remove the session from the list.
+       
+       *p = inSession->next;
+       
+       RMxUnlock();
+       locked = false;
+       
+       // Wait for the thread to exit. Give up after 10 seconds to handle a hung thread.
+       
+       if( inSession->thread && ( threadID != inSession->threadID ) )
+       {
+               result = WaitForSingleObject( inSession->thread, 10 * 1000 );
+               check_translated_errno( result == WAIT_OBJECT_0, (OSStatus) GetLastError(), result );
+       }
+       
+       // Release the thread.
+       
+       if( inSession->thread )
+       {
+               ok = CloseHandle( inSession->thread );
+               check_translated_errno( ok, errno_compat(), kUnknownErr );
+               inSession->thread = NULL;
+       }
+       
+       // Release the socket event.
+       
+       if( inSession->sockEvent )
+       {
+               ok = CloseHandle( inSession->sockEvent );
+               check_translated_errno( ok, errno_compat(), kUnknownErr );
+               inSession->sockEvent = NULL;
+       }
+       
+       // Close the socket.
+       
+       if( IsValidSocket( inSession->sock ) )
+       {
+               err = close_compat( inSession->sock );
+               err = translate_errno( err == 0, errno_compat(), kUnknownErr );
+               check_noerr( err );
+               inSession->sock = kInvalidSocketRef;
+       }
+       
+       // Release the close event.
+       
+       if( inSession->closeEvent )
+       {
+               ok = CloseHandle( inSession->closeEvent );
+               check_translated_errno( ok, errno_compat(), kUnknownErr );
+               inSession->closeEvent = NULL;
+       }
+       
+       // Release the memory used by the object.
+       
+       RMxMessageRelease( &inSession->message );
+       free( inSession );
+       err = kNoErr;
+       
+       dlog( kDebugLevelNotice, DEBUG_NAME "session closed (%d %m)\n", inReason, inReason );
+       
+exit:
+       if( locked )
+       {
+               RMxUnlock();
+       }
+       return( err );
+}
+
+//===========================================================================================================================
+//     RMxSessionThread
+//===========================================================================================================================
+
+DEBUG_LOCAL unsigned WINAPI    RMxSessionThread( LPVOID inParam )
+{
+       OSStatus                        err;
+       RMxSessionRef           session;
+       bool                            safeToClose;
+       
+       session = (RMxSessionRef) inParam;
+       check( session );
+       
+       // Process messages until the session is told to close or the remote site disconnects.
+       
+       for( ;; )
+       {
+               if( session->quit || ( gRMxState != kRMxStateRun ) )
+               {
+                       dlog( kDebugLevelNotice, DEBUG_NAME "session state exit (quit=%d, state=%d)\n", session->quit, gRMxState );
+                       err = kEndingErr;
+                       break;
+               }
+               
+               err = RMxSessionRecvMessage( session, INFINITE );
+               if( err == kNoErr )
+               {
+                       if( session->callback )
+                       {
+                               session->callback( &session->message );
+                       }
+                       RMxMessageRelease( &session->message );
+               }
+               else
+               {
+                       dlog( kDebugLevelNotice, DEBUG_NAME "session closing (%d %m)\n", err, err );
+                       break;
+               }
+       }
+       
+       // Tell the callback the session is closing.
+       
+       if( session->callback )
+       {
+               session->message.opcode         = kRMxOpCodeInvalid;
+               session->message.status         = kNoErr;
+               session->message.sendSize       = 0;
+               session->message.sendData       = NULL;
+               session->message.recvSize       = 0;
+               session->message.recvData       = NULL;
+               session->callback( &session->message );
+       }
+       
+       // Mark the thread as done and close the session (unless asked not to).
+       
+       RMxLock();
+       session->flags |= kRMxSessionFlagsThreadDone;
+       safeToClose = !( session->flags & kRMxSessionFlagsNoClose );
+       RMxUnlock();
+       if( safeToClose )
+       {
+               RMxSessionClose( session, err );
+       }
+       
+       // Call _endthreadex() explicitly instead of just exiting normally to avoid memory leaks when using static run-time
+       // libraries. See <http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/createthread.asp>.
+       
+       _endthreadex_compat( (unsigned) err );
+       return( (unsigned) err );       
+}
+
+//===========================================================================================================================
+//     RMxSessionAccept
+//===========================================================================================================================
+
+DEBUG_LOCAL OSStatus   RMxSessionInitServer( RMxSessionRef inSession )
+{
+       OSStatus                err;
+       
+       inSession->sockEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
+       err = translate_errno( inSession->sockEvent, errno_compat(), kNoResourcesErr );
+       require_noerr( err, exit );
+       
+       err = WSAEventSelect( inSession->sock, inSession->sockEvent, FD_READ | FD_CLOSE );
+       err = translate_errno( err == 0, errno_compat(), kNoResourcesErr );
+       require_noerr( err, exit );
+       
+       inSession->waitCount = 0;
+       inSession->waitHandles[ inSession->waitCount++ ] = inSession->sockEvent;
+       inSession->waitHandles[ inSession->waitCount++ ] = inSession->closeEvent;
+       inSession->waitHandles[ inSession->waitCount++ ] = gRMxStateChangeEvent;
+       check( inSession->waitCount == sizeof_array( inSession->waitHandles ) );
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     RMxSessionInitClient
+//===========================================================================================================================
+
+DEBUG_LOCAL OSStatus   RMxSessionInitClient( RMxSessionRef inSession, const char *inServer )
+{
+       OSStatus                                err;
+       struct addrinfo                 hints;
+       struct addrinfo *               addrList;
+       struct addrinfo *               addr;
+       BOOL                                    ok;
+       
+       addrList = NULL;
+       
+       // Initiate a connection to the server (if we're the client).
+       
+       memset( &hints, 0, sizeof( hints ) );
+       hints.ai_family         = AF_UNSPEC;
+       hints.ai_socktype       = SOCK_STREAM;
+       hints.ai_protocol       = IPPROTO_TCP;
+       
+       err = getaddrinfo( inServer, kRMxServerPortString, &hints, &addrList );
+       require_noerr( err, exit );
+       
+       for( addr = addrList; addr; addr = addr->ai_next )
+       {
+               check( addr->ai_addr && ( addr->ai_addrlen > 0 ) );
+               
+               if( inSession->quit || ( gRMxState != kRMxStateRun ) )
+               {
+                       dlog( kDebugLevelNotice, DEBUG_NAME "session state exit while connecting (quit=%d, state=%d)\n", 
+                               inSession->quit, gRMxState );
+                       err = kEndingErr;
+                       break;
+               }
+               
+               // Clean up for any previous iteration that failed. Normal cleanup will occur when closing the session.
+               
+               if( IsValidSocket( inSession->sock ) )
+               {
+                       err = close_compat( inSession->sock );
+                       check_translated_errno( err == 0, errno_compat(), kUnknownErr );
+                       inSession->sock = kInvalidSocketRef;
+               }
+               
+               if( inSession->sockEvent )
+               {
+                       ok = CloseHandle( inSession->sockEvent );
+                       check_translated_errno( ok, errno_compat(), kUnknownErr );
+                       inSession->sockEvent = NULL;
+               }
+               
+               // Set up the socket and try to connect.
+               
+               dlog( kDebugLevelTrace, DEBUG_NAME "connecting %s socket to %s/%##a\n", 
+                       ( addr->ai_family == AF_INET ) ? "AF_INET" : ( addr->ai_family == AF_INET6 ) ? "AF_INET6" : "<unknown>", 
+                       inServer ? inServer : "<local>", addr->ai_addr );
+               
+               inSession->sock = socket( addr->ai_family, addr->ai_socktype, addr->ai_protocol );
+               err = translate_errno( IsValidSocket( inSession->sock ), errno_compat(), kNoResourcesErr );
+               if( err != kNoErr )
+               {
+                       dlog( kDebugLevelNotice, DEBUG_NAME "%s socket not supported...skipping (%d %m)\n", 
+                               ( addr->ai_family == AF_INET ) ? "AF_INET" : ( addr->ai_family == AF_INET6 ) ? "AF_INET6" : "<unknown>", 
+                               err, err );
+                       continue;
+               }
+               
+               inSession->sockEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
+               err = translate_errno( inSession->sockEvent, errno_compat(), kNoResourcesErr );
+               require_noerr( err, exit );
+               
+               err = WSAEventSelect( inSession->sock, inSession->sockEvent, FD_READ | FD_CONNECT | FD_CLOSE );
+               err = translate_errno( err == 0, errno_compat(), kNoResourcesErr );
+               require_noerr( err, exit );
+               
+               inSession->waitCount = 0;
+               inSession->waitHandles[ inSession->waitCount++ ] = inSession->sockEvent;
+               inSession->waitHandles[ inSession->waitCount++ ] = inSession->closeEvent;
+               inSession->waitHandles[ inSession->waitCount++ ] = gRMxStateChangeEvent;
+               check( inSession->waitCount == sizeof_array( inSession->waitHandles ) );
+               
+               err = RMxSessionConnect( inSession, addr->ai_addr, addr->ai_addrlen );
+               if( err == kNoErr )
+               {
+                       break;
+               }
+       }
+       require_action( addr, exit, err = kConnectionErr );
+       
+exit:
+       if( addrList )
+       {
+               freeaddrinfo( addrList );
+       }
+       return( err );
+}
+
+//===========================================================================================================================
+//     RMxSessionConnect
+//===========================================================================================================================
+
+DEBUG_LOCAL OSStatus   RMxSessionConnect( RMxSessionRef inSession, const struct sockaddr *inAddr, size_t inAddrSize )
+{
+       OSStatus                err;
+       DWORD                   result;
+       
+       check( inSession );
+       check( inSession->sock );
+       check( inSession->waitCount > 0 );
+       check( inAddr && ( inAddrSize > 0 ) );
+       
+       // Start the connection process. This returns immediately. If the error is 0, it means the connection has 
+       // successfully completed (usually only if the host is local). Otherwise, it returns an error to indicate 
+       // that the connection process has started and we must use wait for it to complete.
+       
+       err = connect( inSession->sock, inAddr, (int) inAddrSize );
+       if( err == 0 ) goto exit;
+       
+       // Wait for the connection to complete, timeout, or be canceled.
+       
+       result = WaitForMultipleObjects( inSession->waitCount, inSession->waitHandles, FALSE, kRMxClientTimeout );
+       if( result == WAIT_OBJECT_0 )           // Socket Event
+       {
+               WSANETWORKEVENTS                events;
+               
+               // Check the result of the FD_CONNECT event to see if the connection was successful or not.
+               
+               err = WSAEnumNetworkEvents( inSession->sock, NULL, &events );
+               require_noerr( err, exit );
+               require_action( events.lNetworkEvents & FD_CONNECT, exit, err = kSelectorErr );
+               err = events.iErrorCode[ FD_CONNECT_BIT ];
+       }
+       else if( result == WAIT_TIMEOUT )
+       {
+               err = kTimeoutErr;
+       }
+       else
+       {
+               err = kEndingErr;
+       }
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     RMxSessionSendMessage
+//
+//     Warning: Assumes the RMx lock is held.
+//===========================================================================================================================
+
+OSStatus       RMxSessionSendMessage( RMxSessionRef inSession, RMxOpCode inOpCode, OSStatus inStatus, const char *inFormat, ... )
+{
+       OSStatus                err;
+       va_list                 args1;
+       va_list                 args2;
+       
+       // Note: 2 va_list's need to be provided as the va_list needs to be processed twice (once to preflight, once for 
+       // real) and this is illegal without C99 va_copy, but some environments do not yet support va_copy (e.g. Visual C++).
+       
+       va_start( args1, inFormat );
+       va_start( args2, inFormat );
+       err = RMxSessionSendMessageVAList( inSession, inOpCode, inStatus, inFormat, args1, args2 );
+       va_end( args1 );
+       va_end( args2 );
+       require_noerr( err, exit );
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     RMxSessionSendMessageVAList
+//
+//     Warning: Assumes the RMx lock is held.
+//===========================================================================================================================
+
+DEBUG_LOCAL OSStatus
+       RMxSessionSendMessageVAList( 
+               RMxSessionRef   inSession, 
+               RMxOpCode               inOpCode, 
+               OSStatus                inStatus, 
+               const char *    inFormat, 
+               va_list                 inArgs1, 
+               va_list                 inArgs2 )
+{
+       OSStatus                err;
+       RMxMessage              msg;
+       uint8_t *               bufferStorage;
+       uint8_t *               buffer;
+       size_t                  bodySize;
+       size_t                  headerSize;
+       size_t                  size;
+       int                             n;
+       
+       bufferStorage = NULL;
+       check( inSession );
+       check( IsValidSocket( inSession->sock ) );
+       check( inFormat );
+       
+       // Calculate the size of the data section of the message and set up the buffer for the entire message.
+       // If the entire message will fit in the inline message buffer, use it. Otherwise, allocate a buffer for it.
+       
+       err = RMxPackedSizeVAList( &bodySize, inFormat, inArgs1 );
+       require_noerr( err, exit );
+       
+       size = kRMxMessageHeaderSize + bodySize;
+       if( size <= sizeof( msg.storage ) )
+       {
+               buffer = msg.storage;
+       }
+       else
+       {
+               bufferStorage = (uint8_t *) malloc( size );
+               require_action( bufferStorage, exit, err = kNoMemoryErr );
+               buffer = bufferStorage;
+       }
+       
+       // Build the message header.
+       
+       err = RMxPack( buffer, kRMxMessageHeaderSize, &headerSize, "wwwwww", 
+               kRMxSignatureVersion1,          // signature
+               inOpCode,                                       // opcode
+               kRMxFlagsNone,                          // flags
+               0,                                                      // xid
+               inStatus,                                       // status
+               (uint32_t) bodySize );          // size
+       require_noerr( err, exit );
+       check( headerSize == kRMxMessageHeaderSize );
+               
+       // Build the message body.
+       
+       err = RMxPackVAList( buffer + kRMxMessageHeaderSize, size - kRMxMessageHeaderSize, &size, inFormat, inArgs2 );
+       require_noerr( err, exit );
+       check( size == bodySize );
+       
+       // Send the entire message.
+       
+       size = headerSize + size;
+       n = send( inSession->sock, (const char *) buffer, (int) size, 0 );
+       err = translate_errno( n == (int) size, errno_compat(), kWriteErr );
+       require_noerr( err, exit );
+       
+exit:
+       if( bufferStorage )
+       {
+               free( bufferStorage );
+       }
+       return( err );
+}
+
+//===========================================================================================================================
+//     RMxSessionRecvMessage
+//
+//     Note: This routine maintains state within the session data structure and can resume partial message reception.
+//===========================================================================================================================
+
+OSStatus       RMxSessionRecvMessage( RMxSessionRef inSession, DWORD inTimeout )
+{
+       OSStatus                err;
+       DWORD                   result;
+       int                             n;
+       
+       for( ;; )
+       {
+               if( inSession->quit || ( gRMxState != kRMxStateRun ) )
+               {
+                       dlog( kDebugLevelNotice, DEBUG_NAME "session recv state exit (quit=%d, state=%d)\n", inSession->quit, gRMxState );
+                       err = kEndingErr;
+                       goto exit;
+               }
+               
+               // Wait for data to become available or another event to occur.
+               
+               result = WaitForMultipleObjects( inSession->waitCount, inSession->waitHandles, FALSE, inTimeout );
+               if( result == WAIT_OBJECT_0 )                           // Socket Event (i.e. data available to read)
+               {
+                       n = recv( inSession->sock, (char *) inSession->messageRecvBufferPtr, inSession->messageRecvRemaining, 0 );
+                       if( n > 0 )
+                       {
+                               inSession->messageRecvBufferPtr += n;
+                               inSession->messageRecvRemaining -= n;
+                               if( inSession->messageRecvRemaining == 0 )
+                               {
+                                       // Complete chunk ready. If we haven't read the header yet, it's the header. Otherwise, it's the data. 
+                                       
+                                       if( !inSession->messageRecvHeaderDone )
+                                       {
+                                               // Parse the buffer into the message header structure and mark the header as complete.
+                                               
+                                               err = RMxUnpack( inSession->messageRecvBuffer, kRMxMessageHeaderSize, 
+                                                       "wwwwww", 
+                                                       &inSession->message.signature, 
+                                                       &inSession->message.opcode, 
+                                                       &inSession->message.flags, 
+                                                       &inSession->message.xid, 
+                                                       &inSession->message.status, 
+                                                       &inSession->message.recvSize );
+                                               require_noerr( err, exit );
+                                               require_action( inSession->message.signature == kRMxSignatureVersion1, exit, err = kMismatchErr );
+                                               require_action( inSession->message.opcode != kRMxOpCodeInvalid, exit, err = kMismatchErr );
+                                               inSession->messageRecvHeaderDone = true;
+                                               
+                                               // Set up to read the data section (if any). Use the inline message buffer if the data will fit.
+                                               
+                                               if( inSession->message.recvSize > 0 )
+                                               {
+                                                       if( inSession->message.recvSize <= sizeof( inSession->message.storage ) )
+                                                       {
+                                                               inSession->message.recvData = inSession->message.storage;
+                                                       }
+                                                       else
+                                                       {
+                                                               inSession->message.recvData = (uint8_t *) malloc( inSession->message.recvSize );
+                                                               require_action( inSession->message.recvData, exit, err = kNoMemoryErr );
+                                                       }
+                                                       inSession->messageRecvBufferPtr = inSession->message.recvData;
+                                                       inSession->messageRecvRemaining = (int) inSession->message.recvSize;
+                                               }
+                                       }                       
+                               }
+                               if( inSession->messageRecvHeaderDone && ( inSession->messageRecvRemaining == 0 ) )
+                               {
+                                       // Complete message ready. Reset state for next message. Exit to allow message to be processed.
+                                       
+                                       inSession->messageRecvBufferPtr         = inSession->messageRecvBuffer;
+                                       inSession->messageRecvRemaining         = kRMxMessageHeaderSize;
+                                       inSession->messageRecvHeaderDone        = false;
+                                       break;
+                               }
+                       }
+                       else
+                       {
+                               err = errno_compat();
+                               dlog( kDebugLevelNotice, DEBUG_NAME "session recv peer disconnected (%d/%d %m)\n", n, err, err );
+                               err = kConnectionErr;
+                               goto exit;
+                       }
+               }
+               else if( result == ( WAIT_OBJECT_0 + 1 ) )      // Close Event
+               {
+                       dlog( kDebugLevelNotice, DEBUG_NAME "session recv close signaled\n" );
+                       err = kEndingErr;
+                       goto exit;
+               }
+               else if( result == ( WAIT_OBJECT_0 + 2 ) )      // State Change Event
+               {
+                       dlog( kDebugLevelNotice, DEBUG_NAME "session recv state change (%d)\n", gRMxState );
+                       err = kEndingErr;
+                       goto exit;
+               }
+               else if( result == WAIT_TIMEOUT )                       // Timeout
+               {
+                       dlog( kDebugLevelNotice, DEBUG_NAME "session recv timeout\n" );
+                       err = kTimeoutErr;
+                       goto exit;
+               }
+               else
+               {
+                       err = errno_compat();
+                       dlog( kDebugLevelAlert, DEBUG_NAME "session recv message wait error: 0x%08X, %d (%m)\n", result, err, err );
+                       err = (OSStatus) result;
+                       goto exit;
+               }
+       }
+       err = kNoErr;
+       
+exit:
+       return( err );
+}
+
+#if 0
+#pragma mark -
+#pragma mark == Utilities ==
+#endif
+
+//===========================================================================================================================
+//     RMxCheckVersion
+//===========================================================================================================================
+
+OSStatus
+       RMxCheckVersion( 
+               uint32_t inClientCurrentVersion, uint32_t inClientOldestClientVersion, uint32_t inClientOldestServerVersion, 
+               uint32_t inServerCurrentVersion, uint32_t inServerOldestClientVersion, uint32_t inServerOldestServerVersion )
+{
+       OSStatus                        err;
+       const char *            message;
+       
+       DEBUG_USE_ONLY( inClientOldestClientVersion );
+       DEBUG_USE_ONLY( inServerOldestServerVersion );
+       DEBUG_USE_ONLY( message );
+       
+       // Determine if the version information on both sides is compatible.
+       
+       if( inClientCurrentVersion == inServerCurrentVersion )
+       {       
+               message         = "versions exactly match";
+               err             = kNoErr;
+       }
+       else if( inClientCurrentVersion > inServerCurrentVersion )
+       {
+               if( inClientOldestServerVersion <= inServerCurrentVersion )
+               {
+                       message = "client newer, but compatible";
+                       err     = kNoErr;
+               }
+               else
+               {
+                       message = "server too old for client";
+                       err             = kIncompatibleErr;
+               }
+       }
+       else
+       {
+               if( inServerOldestClientVersion <= inClientCurrentVersion )
+               {
+                       message = "server newer, but compatible";
+                       err             = kNoErr;
+               }
+               else
+               {
+                       message = "client too old for server";
+                       err             = kIncompatibleErr;
+               }
+       }
+       dlog( kDebugLevelNotice, DEBUG_NAME "%s (client=%v/%v/%v vs server=%v/%v/%v)\n", message, 
+               inClientCurrentVersion, inClientOldestClientVersion, inClientOldestServerVersion, 
+               inServerCurrentVersion, inServerOldestClientVersion, inServerOldestServerVersion );
+
+       return( err );
+}
+
+//===========================================================================================================================
+//     RMxPackedSize
+//===========================================================================================================================
+
+OSStatus       RMxPackedSize( size_t *outSize, const char *inFormat, ... )
+{
+       OSStatus                err;
+       va_list                 args;
+       
+       va_start( args, inFormat );
+       err = RMxPackedSizeVAList( outSize, inFormat, args );
+       va_end( args );
+       
+       return( err );
+}
+
+//===========================================================================================================================
+//     RMxPackedSizeVAList
+//===========================================================================================================================
+
+OSStatus       RMxPackedSizeVAList( size_t *outSize, const char *inFormat, va_list inArgs )
+{
+       OSStatus                        err;
+       size_t                          size;
+       char                            c;
+       const uint8_t *         src;
+       uint32_t                        tempU32;
+       const uint8_t *         p;
+       
+       check_compile_time_code( sizeof( unsigned int ) >= 4 );
+       
+       size = 0;
+       
+       // Loop thru each character in the format string, decode it, and add the size required to pack it.
+       
+       for( c = *inFormat; c != '\0'; c = *( ++inFormat ) )
+       {
+               switch( c )
+               {
+                       case 'b':       // Byte (8-bit)
+                               
+                               va_arg( inArgs, unsigned int );
+                               size += 1;
+                               break;
+                       
+                       case 'h':       // Half-word (16-bit)
+                               
+                               va_arg( inArgs, unsigned int );
+                               size += 2;
+                               break;
+                       
+                       case 'w':       // Word (32-bit)
+                               
+                               va_arg( inArgs, unsigned int );
+                               size += 4;
+                               break;
+                       
+                       case 's':       // UTF-8 String, null terminated
+                               
+                               src = va_arg( inArgs, const uint8_t * );
+                               check( src );
+                               
+                               p = src;
+                               while( *p++ != 0 ) {}
+                               size += ( p - src );
+                               break;
+                       
+                       case 'n':       // N bytes of raw data; 1st arg is size, 2nd arg is ptr; stored with 32-bit length prefix.
+                               
+                               tempU32 = (uint32_t) va_arg( inArgs, unsigned int );                            
+                               src = va_arg( inArgs, const uint8_t * );
+                               check( src || ( tempU32 == 0 ) );
+                               
+                               size += ( 4 + tempU32 );
+                               break;
+                       
+                       case ' ':       // Ignore spaces (they're just for format string readability).
+                               break;
+                       
+                       default:        // Unknown format specifier
+                               
+                               err = kUnsupportedErr;
+                               goto exit;
+               }
+       }
+       
+       // Success!
+       
+       if( outSize )
+       {
+               *outSize = size;
+       }
+       err = kNoErr;
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     RMxPack
+//===========================================================================================================================
+
+OSStatus       RMxPack( void *inBuffer, size_t inMaxSize, size_t *outSize, const char *inFormat, ... )
+{
+       OSStatus                err;
+       va_list                 args;
+       
+       va_start( args, inFormat );
+       err = RMxPackVAList( inBuffer, inMaxSize, outSize, inFormat, args );
+       va_end( args );
+       
+       return( err );
+}
+
+//===========================================================================================================================
+//     RMxPackVAList
+//===========================================================================================================================
+
+OSStatus       RMxPackVAList( void *inBuffer, size_t inMaxSize, size_t *outSize, const char *inFormat, va_list inArgs )
+{
+       OSStatus                        err;
+       char                            c;
+       const uint8_t *         src;
+       uint8_t *                       dst;
+       uint8_t *                       end;
+       uint8_t                         tempU8;
+       uint16_t                        tempU16;
+       uint32_t                        tempU32;
+       const uint8_t *         p;
+       size_t                          size;
+       
+       check_compile_time_code( sizeof( unsigned int ) >= 4 );
+       
+       dst = (uint8_t *) inBuffer;
+       end = dst + inMaxSize;
+       
+       // Loop thru each character in the format string, decode it, and pack the data appropriately.
+       
+       for( c = *inFormat; c != '\0'; c = *( ++inFormat ) )
+       {
+               switch( c )
+               {
+                       case 'b':       // Byte (8-bit)
+                               
+                               check( ( end - dst ) >= 1 );
+                               tempU8 = (uint8_t) va_arg( inArgs, unsigned int );
+                               *dst++ = tempU8;
+                               break;
+                       
+                       case 'h':       // Half-word (16-bit)
+                               
+                               check( ( end - dst ) >= 2 );
+                               tempU16 = (uint16_t) va_arg( inArgs, unsigned int );
+                               *dst++  = (uint8_t)( ( tempU16 >> 8 ) & 0xFF );
+                               *dst++  = (uint8_t)(   tempU16        & 0xFF );
+                               break;
+                       
+                       case 'w':       // Word (32-bit)
+                               
+                               check( ( end - dst ) >= 4 );
+                               tempU32 = (uint32_t) va_arg( inArgs, unsigned int );
+                               *dst++  = (uint8_t)( ( tempU32 >> 24 ) & 0xFF );
+                               *dst++  = (uint8_t)( ( tempU32 >> 16 ) & 0xFF );
+                               *dst++  = (uint8_t)( ( tempU32 >>  8 ) & 0xFF );
+                               *dst++  = (uint8_t)(   tempU32         & 0xFF );
+                               break;
+                       
+                       case 's':       // UTF-8 String, null terminated
+                               
+                               src = va_arg( inArgs, const uint8_t * );
+                               check( src );
+                               
+                               p = src;
+                               while( *p++ != 0 ) {}
+                               size = (size_t)( p - src );
+                               check( ( end - dst ) >= (ptrdiff_t) size );
+                               
+                               while( size-- > 0 )
+                               {
+                                       *dst++ = *src++;
+                               }
+                               break;
+                       
+                       case 'n':       // N bytes of raw data; 1st arg is size, 2nd arg is ptr; stored with 32-bit length prefix.
+                               
+                               tempU32 = (uint32_t) va_arg( inArgs, unsigned int );
+                               check( ( end - dst ) >= (ptrdiff_t)( 4 + tempU32 ) );
+                               
+                               src = va_arg( inArgs, const uint8_t * );
+                               check( src || ( tempU32 == 0 ) );
+                               
+                               *dst++ = (uint8_t)( ( tempU32 >> 24 ) & 0xFF );
+                               *dst++ = (uint8_t)( ( tempU32 >> 16 ) & 0xFF );
+                               *dst++ = (uint8_t)( ( tempU32 >>  8 ) & 0xFF );
+                               *dst++ = (uint8_t)(   tempU32         & 0xFF );
+                               while( tempU32-- > 0 )
+                               {
+                                       *dst++ = *src++;
+                               }
+                               break;
+                       
+                       case ' ':       // Ignore spaces (they're just for format string readability).
+                               break;
+                       
+                       default:        // Unknown format specifier
+                               
+                               err = kUnsupportedErr;
+                               goto exit;
+               }
+       }
+       
+       // Success!
+       
+       if( outSize )
+       {
+               *outSize = (size_t)( dst - ( (uint8_t *) inBuffer ) );
+       }
+       err = kNoErr;
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     RMxUnpack
+//===========================================================================================================================
+
+OSStatus       RMxUnpack( const void *inData, size_t inSize, const char *inFormat, ... )
+{
+       OSStatus                err;
+       va_list                 args;
+       
+       va_start( args, inFormat );
+       err = RMxUnpackVAList( inData, inSize, inFormat, args );
+       va_end( args );
+       
+       return( err );
+}
+
+//===========================================================================================================================
+//     DNSUnpackVAList
+//===========================================================================================================================
+
+OSStatus       RMxUnpackVAList( const void *inData, size_t inSize, const char *inFormat, va_list inArgs )
+{
+       OSStatus                                err;
+       char                                    c;
+       const uint8_t *                 src;
+       const uint8_t *                 end;
+       uint8_t *                               b;
+       uint16_t *                              h;
+       uint32_t *                              w;
+       uint16_t                                tempU16;
+       uint32_t                                tempU32;
+       const uint8_t *                 p;
+       size_t                                  size;
+       const uint8_t **                ptrArg;
+       size_t *                                sizeArg;
+       
+       check_compile_time_code( sizeof( unsigned int ) >= 4 );
+       
+       src = (const uint8_t *) inData;
+       end = src + inSize;
+       
+       // Loop thru each character in the format string, decode it, and unpack the data appropriately.
+       
+       for( c = *inFormat; c != '\0'; c = *( ++inFormat ) )
+       {
+               switch( c )
+               {
+                       case 'b':       // Byte (8-bit)
+                               
+                               require_action( ( end - src ) >= 1, exit, err = kSizeErr );
+                               b  = va_arg( inArgs, uint8_t * );
+                               if( b )
+                               {
+                                       *b = *src;
+                               }
+                               ++src;
+                               break;
+                       
+                       case 'h':       // Half-word (16-bit)
+                               
+                               require_action( ( end - src ) >= 2, exit, err = kSizeErr );
+                               tempU16  = (uint16_t)( *src++ << 8 );
+                               tempU16 |= (uint16_t)( *src++ );
+                               h                = va_arg( inArgs, uint16_t * );
+                               if( h )
+                               {
+                                       *h = tempU16;
+                               }
+                               break;
+                       
+                       case 'w':       // Word (32-bit)
+                               
+                               require_action( ( end - src ) >= 4, exit, err = kSizeErr );
+                               tempU32  = (uint32_t)( *src++ << 24 );
+                               tempU32 |= (uint32_t)( *src++ << 16 );
+                               tempU32 |= (uint32_t)( *src++ << 8 );
+                               tempU32 |= (uint32_t)( *src++ );
+                               w                = va_arg( inArgs, uint32_t * );
+                               if( w )
+                               {
+                                       *w = tempU32;
+                               }
+                               break;
+                       
+                       case 's':       // UTF-8 String, null terminated; 1st arg=ptr to ptr, 2nd arg=ptr to size, excluding null terminator.
+                               
+                               p = src;
+                               while( ( ( end - p ) > 0 ) && ( *p != 0 ) )
+                               {
+                                       ++p;
+                               }
+                               require_action( ( end - p ) > 0, exit, err = kSizeErr );
+                               size = (size_t)( p - src );
+                               
+                               ptrArg = va_arg( inArgs, const uint8_t ** );
+                               if( ptrArg )
+                               {
+                                       *ptrArg = src;
+                               }
+                               
+                               sizeArg = va_arg( inArgs, size_t * );
+                               if( sizeArg )
+                               {
+                                       *sizeArg = size;
+                               }
+                               
+                               src = p + 1;
+                               break;
+                       
+                       case 'n':       // N bytes of raw data; 1st arg is ptr to ptr, 2nd arg is ptr to size.
+                               
+                               require_action( ( end - src ) >= 4, exit, err = kSizeErr );
+                               tempU32  = (uint32_t)( *src++ << 24 );
+                               tempU32 |= (uint32_t)( *src++ << 16 );
+                               tempU32 |= (uint32_t)( *src++ << 8 );
+                               tempU32 |= (uint32_t)( *src++ );
+                               require_action( ( end - src ) >= (ptrdiff_t) tempU32, exit, err = kSizeErr );
+                               size = (size_t) tempU32;
+                               
+                               ptrArg = va_arg( inArgs, const uint8_t ** );
+                               if( ptrArg )
+                               {
+                                       *ptrArg = src;
+                               }
+                               
+                               sizeArg = va_arg( inArgs, size_t * );
+                               if( sizeArg )
+                               {
+                                       *sizeArg = size;
+                               }
+                               
+                               src += size;
+                               break;
+                       
+                       case ' ':       // Ignore spaces (they're just for format string readability).
+                               break;
+                       
+                       default:        // Unknown format specifier
+                               
+                               err = kUnsupportedErr;
+                               goto exit;
+               }
+       }
+
+       // Success!
+       
+       err = kNoErr;
+       
+exit:
+       return( err );
+}
+
+#if( DEBUG )
+//===========================================================================================================================
+//     RMxPackUnpackTest
+//===========================================================================================================================
+
+OSStatus       RMxPackUnpackTest( void );
+
+OSStatus       RMxPackUnpackTest( void )
+{
+       static const uint8_t            data[] = 
+       {
+               0xAA, 
+               0xBB, 0xCC, 
+               0x11, 0x22, 0x33, 0x44, 
+               0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x70, 0x65, 0x6F, 0x70, 0x6C, 0x65, 0x00,   // hello people\0
+               0x00, 0x00, 0x00, 0x05, 0x74, 0x65, 0x73, 0x74, 0x73                                                    // tests
+       };
+       OSStatus                err;
+       uint8_t                 buffer[ 128 ];
+       size_t                  size;
+       uint8_t                 b;
+       uint16_t                h;
+       uint32_t                w;
+       char *                  s;
+       size_t                  sSize;
+       uint8_t *               d;
+       size_t                  dSize;
+       
+       check_compile_time_code( sizeof( data ) >= 29 );
+       
+       // simple API test.
+       //
+       
+       printf( "\nsimple API test\n" );
+       
+       err = RMxPackedSize( &size, "bhwsn ", 0xAA, 0xBBCC, 0x11223344, "hello people", 5, "tests" );
+       require_noerr( err, exit );
+       require_action( size == 29, exit, err = kSizeErr );
+       
+       err = RMxPack( buffer, 29, &size, " bhwsn", 0xAA, 0xBBCC, 0x11223344, "hello people", 5, "tests" );
+       require_noerr( err, exit );
+       require_action( size == 29, exit, err = kSizeErr );
+       require_action( memcmp( buffer, data, size ) == 0, exit, err = kMismatchErr );
+       
+       err = RMxUnpack( data, sizeof( data ), "bhw sn", &b, &h, &w, &s, &sSize, &d, &dSize );
+       require_noerr( err, exit );
+       require_action( b == 0xAA, exit, err = kMismatchErr );
+       require_action( h == 0xBBCC, exit, err = kMismatchErr );
+       require_action( w == 0x11223344, exit, err = kMismatchErr );
+       require_action( sSize == 12, exit, err = kSizeErr );
+       require_action( strcmp( s, "hello people" ) == 0, exit, err = kMismatchErr );
+       require_action( dSize == 5, exit, err = kSizeErr );
+       require_action( memcmp( d, "tests", 5 ) == 0, exit, err = kMismatchErr );
+       
+       printf( "\nsimple API test done\n\n" );
+       
+       // Done
+       
+       printf( "\n\nALL TESTS PASSED\n\n" );
+
+exit:
+       return( err );
+}
+#endif // DEBUG
+
+#ifdef __cplusplus
+       }
+#endif
diff --git a/mDNSWindows/RMxCommon.h b/mDNSWindows/RMxCommon.h
new file mode 100644 (file)
index 0000000..a28da74
--- /dev/null
@@ -0,0 +1,662 @@
+/*
+ * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+
+$Log: RMxCommon.h,v $
+Revision 1.1  2004/01/30 02:35:13  bradley
+Rendezvous Message Exchange implementation for DNS-SD IPC on Windows.
+
+*/
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @header         RMxCommon.h
+       
+       @abstract       Common code between the RMxClient and RMxServer.
+       
+       @discussion     
+       
+       This handles establishing and accepting connections, the underying message sending and receiving, portable data 
+       packing an unpacking, and shared utility routines.
+*/
+
+#ifndef __RMx_COMMON__
+#define __RMx_COMMON__
+
+#include       "CommonServices.h"
+#include       "DebugServices.h"
+
+#ifdef __cplusplus
+       extern "C" {
+#endif
+
+#if 0
+#pragma mark == Documentation ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @header         RMxCommon
+       
+       @abstract       Rendezvous Message Exchange (RMx) protocol.
+       
+       @discussion
+       
+       Data Type Notes
+       ===============
+       
+       All multi-byte data types are transmitted in network byte order (i.e. big endian).
+       
+       Data types requiring the use of specific values (e.g. opcodes) are typedef'd to an abstract type. Data types used 
+       in this manner can be easily searched to determine the appropriate values for the data type. Modern development 
+       environments can jump directly to a type and therefore the appropriate constants, which speeds up development.
+       
+       Naming Conventions
+       ==================
+       
+       All data types and related constants are named to make it easy to associate them. The general scheme is:
+       
+       Data Types: RMx<type>
+       
+               <type>  Describes the data type (e.g. "OpCode" is used for operation codes).
+               
+               For example: RMxOpCode
+               
+       Constants:      kRMx<type><name>
+       
+               <type>  Describes the data type (e.g. "OpCode" is used for operation codes in RMx messages).
+               <name>  Symbolic name for the constant (e.g. "Browse" for browse messages).
+               
+               For example: kRMxOpCodeBrowse
+       
+       These conventions make it easier for users to associate data types with their values and to find places where 
+       these data types and constants are used. You can always search for the base portion of symbolic name (e.g. 
+       "RMxOpCode" in kRMxOpCodeBrowse) and find all the data types and constants associated with it. Modern 
+       development environments also allow you to jump directly to the data type or constant.
+       
+       Packet Format
+       =============
+       
+       All data exchanged between client and server is encapsulated in packets of a specific format. There is a 
+       generic header followed by an optional, opcode-specific data section:
+
+                               1                   2                   3
+           0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+        0 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+          |                       signature (RMx1)                        |
+        4 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+          |                            opcode                             |
+        8 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+          |                            flags                              |
+       12 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+          |                             xid                               |
+       16 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+          |                            status                             |
+       20 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+          |                             size                              |
+       24 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+          |                      data ("size" octets)                     |
+          \                                                               \
+          \                                                               \
+          |                                                               |
+        n +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       
+       The packet format uses implicit typing, which means the sender and receiver must know the types and ordering of the 
+       data based on the opcode of the message. There are standard primitive data types defined that all data structures
+       are built on:
+       
+       Byte            - 8-bit value. Uses the "b" pack/unpack format specifier.
+       Half-Word       - 16-bit value. Uses the "h" pack/unpack format specifier.
+       Word            - 32-bit value. Uses the "w" pack/unpack format specifier.
+       String          - UTF-8 string, null-terminated. Uses the "s" pack/unpack format specifier.
+       Raw Bytes       - 32-bit length-prefixed block of data. Uses the "n" pack/unpack format specifier.
+       
+       The String and Raw Byte data types are designed to support directly referencing the raw packet data without 
+       copying them into a temporary buffer for efficiency, easy of use, and to reduce the possibility of resource
+       leaks. The String data type contains a null terminator in the packet data so it can be treated as a normal 
+       C-style string (e.g. strcpy works on it). The Raw Bytes data type can be used via a pointer and size. The data 
+       packing and unpacking routines are designed around the packet format to allow for efficient packet handling.
+       
+       Protocol
+       ========
+       
+       The RMx protocol is a TCP-based client/server protocol. The server listens on a well-known TCP port. The client 
+       connects to the server port and a session of message exchange begins. The client drives the session by sending
+       the initial message describing the action it wants performed by the server. The server performs operations
+       requested by the client and asynchronously sends reply messages as specified by the type of request.
+       
+       The general operation of the RMx server is as follows:
+       
+               1) Initialize server (set up synchronization support, etc.).
+               2) Run server by creating socket(s) for listening and wait until a connection is accepted.
+               3) If a connection is accepted:
+                       3a) Accept session (allocate, link into session list, create session thread, etc.).
+
+       The general operation of the RMx client is as follows:
+       
+               1) Initialize client (set up synchronization support, etc.).
+               2) Start a session to the server.
+       
+       The general operation of the RMx session thread (used by the client and server) is as follows:
+       
+               1) Initialize session (set up synchronization support, etc.).
+               2) Wait for a message to be received.
+               3) If a message is received:
+                       3a) Process the message.
+*/
+
+#if 0
+#pragma mark == Versions ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @typedef        kRMxCurrentVersion
+
+       @abstract       Current version of the RMx implementation.
+*/
+
+#define kRMxCurrentVersion                     NumVersionBuild( 1, 0, 0, kVersionStageFinal, 0 )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @typedef        kRMxOldestClientVersion
+
+       @abstract       Oldest version of the RMx client that works with this server.
+*/
+
+#define kRMxOldestClientVersion                NumVersionBuild( 1, 0, 0, kVersionStageFinal, 0 )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @typedef        kRMxOldestServerVersion
+
+       @abstract       Oldest version of the RMx server that works with this client.
+*/
+
+#define kRMxOldestServerVersion                NumVersionBuild( 1, 0, 0, kVersionStageFinal, 0 )
+
+#if 0
+#pragma mark == General ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        kRMxServerPort
+
+       @abstract       TCP port of DNS-SD server in host byte order.
+*/
+
+#define        kRMxServerPort                          5354
+#define        kRMxServerPortString            "5354"
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        kRMxClientTimeout
+
+       @abstract       Default client timeout.
+*/
+
+#define        kRMxClientTimeout               ( 5 * 1000 )    // 5 seconds
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @defined        kDNSRecordIndexDefault
+
+       @abstract       Record index for the default TXT record.
+*/
+
+#define        kDNSRecordIndexDefaultTXT               0
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @enum           RMxState
+
+       @abstract       State of the RMx engine.
+       
+       @constant       kRMxStateInvalid        Not in a valid state.
+       @constant       kRMxStateStop           Stopped.
+       @constant       kRMxStateRun            Running.
+*/
+
+typedef enum
+{
+       kRMxStateInvalid, 
+       kRMxStateStop, 
+       kRMxStateRun
+       
+}      RMxState;
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @var            gRMxState
+
+       @abstract       Global state of the RMx engine.
+*/
+
+extern RMxState                gRMxState;
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @var            gRMxState
+
+       @abstract       Global state change event associated with the RMx engine.
+*/
+
+extern HANDLE          gRMxStateChangeEvent;
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       RMxInitialize
+
+       @abstract       Initializes the RMx engine.
+*/
+
+OSStatus       RMxInitialize( void );
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       RMxFinalize
+
+       @abstract       Finalizes the RMx engine.
+*/
+
+void   RMxFinalize( void );
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       RMxLock
+
+       @abstract       Locks the RMx engine.
+*/
+
+void   RMxLock( void );
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       RMxUnlock
+
+       @abstract       Unlocks the RMx engine.
+*/
+
+void   RMxUnlock( void );
+
+#if 0
+#pragma mark == Messages ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @typedef        RMxSignature
+
+       @abstract       Signature for RMx messages.
+       
+       @constant       kRMxSignatureVersion1           Version 1 message.
+*/
+
+typedef uint32_t       RMxSignature;
+
+#define        kRMxSignatureVersion1           0x524D7831      // 'RMx1' Version 1 message.
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @typedef        RMxFlags
+
+       @abstract       Flags for RMx messages.
+       
+       @constant       kRMxFlagsNone   No flags.
+*/
+
+typedef uint32_t       RMxFlags;
+
+#define        kRMxFlagsNone           0
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @typedef        RMxOpCode
+
+       @abstract       Operation code for RMx messages.
+       
+       @constant       kRMxOpCodeInvalid                               Invalid message.
+       @constant       kRMxOpCodeCheckVersion                  DNSServiceCheckVersion message.
+       @constant       kRMxOpCodeCopyProperty                  DNSServiceCopyProperty message.
+       @constant       kRMxOpCodeEnumerateDomains              DNSServiceEnumerateDomains message.
+       @constant       kRMxOpCodeRegister                              DNSServiceRegister message.
+       @constant       kRMxOpCodeAddRecord                             DNSServiceAddRecord message.
+       @constant       kRMxOpCodeUpdateRecord                  DNSServiceUpdateRecord message.
+       @constant       kRMxOpCodeRemoveRecord                  DNSServiceRemoveRecord message.
+       @constant       kRMxOpCodeBrowse                                DNSServiceBrowse message.
+       @constant       kRMxOpCodeResolve                               DNSServiceResolve message.
+       @constant       kRMxOpCodeCreateConnection              DNSServiceCreateConnection message.
+       @constant       kRMxOpCodeRegisterRecord                DNSServiceRegisterRecord message.
+       @constant       kRMxOpCodeQueryRecord                   DNSServiceQueryRecord message.
+       @constant       kRMxOpCodeReconfirmRecord               DNSServiceReconfirmRecord message.
+*/
+
+typedef uint32_t       RMxOpCode;
+
+#define        kRMxOpCodeInvalid                               0
+
+#define kRMxOpCodeCheckVersion                 10
+       // Request:     <w:clientCurrentVersion> <w:clientOldestClientVersion> <w:clientOldestServerVersion> 
+       // Reply:       <w:errorCode> <w:serverCurrentVersion> <w:serverOldestClientVersion> <w:serverOldestServerVersion> 
+
+#define kRMxOpCodeCopyProperty                 11
+       // Request:     <w:propertyCode> 
+       // Reply:       <w:errorCode> <w:propertyCode> <n:propertyData>
+
+#define kRMxOpCodeEnumerateDomains             100
+       // Request:     <w:flags> <w:interfaceIndex>
+       // Reply:       <w:flags> <w:interfaceIndex> <w:errorCode> <s:domain>
+
+#define kRMxOpCodeRegister                             200
+       // Request:     <w:flags> <w:interfaceIndex> <s:name> <s:type> <s:domain> <s:host> <h:port> <n:txt>
+       // Reply:       <w:flags> <w:errorCode> <s:name> <s:type> <s:domain>
+
+#define kRMxOpCodeAddRecord                            201
+       // Request:     <w:id> <w:flags> <h:rrType> <n:rrData> <w:ttl>
+       // Reply:       no reply
+
+#define kRMxOpCodeUpdateRecord                 202
+       // Request:     <w:id> <w:flags> <n:rrData> <w:ttl>
+       // Reply:       no reply
+
+#define kRMxOpCodeRemoveRecord                 203
+       // Request:     <w:id> <w:flags>
+       // Reply:       no reply
+
+#define kRMxOpCodeBrowse                               300
+       // Request:     <w:flags> <w:interfaceIndex> <s:type> <s:domain>
+       // Reply:       <w:flags> <w:interfaceIndex> <w:errorCode> <s:name> <s:type> <s:domain>
+
+#define kRMxOpCodeResolve                              400
+       // Request:     <w:flags> <w:interfaceIndex> <s:name> <s:type> <s:domain>
+       // Reply:       <w:flags> <w:interfaceIndex> <w:errorCode> <s:fullName> <n:addr> <s:hostName> <h:port> <n:txtRecord>
+
+#define kRMxOpCodeCreateConnection             500
+       // Request:     no data
+       // Reply:       no reply
+
+#define        kRMxOpCodeRegisterRecord                510
+       // Request:     <w:flags> <w:interfaceIndex> <s:name> <h:rrType> <h:rrClass> <n:rrData> <w:ttl>
+       // Reply:       <w:flags> <w:errorCode> <w:recordID>
+
+#define        kRMxOpCodeQueryRecord                   511
+       // Request:     <w:flags> <w:interfaceIndex> <s:name> <h:rrType> <h:rrClass>
+       // Reply:       <w:flags> <w:interfaceIndex> <w:errorCode> <s:name> <h:rrType> <h:rrClass> <n:rrData> <w:ttl>
+
+#define        kRMxOpCodeReconfirmRecord               512
+       // Request:     <w:flags> <w:interfaceIndex> <s:name> <h:rrType> <h:rrClass> <n:rrData>
+       // Reply:       no reply
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @typedef        RMxMessageCallBack
+
+       @abstract       Callback function for a message.
+*/
+
+typedef struct RMxMessage      RMxMessage;
+
+typedef void ( *RMxMessageCallBack )( RMxMessage *inMessage );
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @typedef        RMxSessionRef
+
+       @abstract       References to a session.
+*/
+
+typedef struct RMxSession *            RMxSessionRef;
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @struct         RMxMessage
+
+       @abstract       RMx message.
+       
+       @field          signature                       Signature identifying message as an RMx message (and for future versioning).
+       @field          opcode                          Operation code of the message.
+       @field          flags                           Flags for the message.
+       @field          xid                                     Transaction ID. WARNING: Must be unique within execution environment (e.g. process).
+       @field          status                          Status of the message (used to return error replies).
+       
+       @field          sendSize                        Size of data to send.
+       @field          sendData                        Data to send.
+       @field          recvSize                        Size of received data.
+       @field          recvData                        Received data.
+       
+       @field          context                         Context for the completion callback (specified when session started).
+       @field          session                         Session where the message is sent/received.
+       
+       @field          bufferSize                      PRIVATE: Size of entire message buffer or 0 if message not constructed.
+       @field          buffer                          PRIVATE: Ptr to entire message buffer or NULL if message not constructed.
+       @field          storage                         PRIVATE: Local storage for small messages.
+
+       @constant       kRMxMessageSynchronous                  Meta-message indicating operation should be performed synchronously.
+       @constant       kRMxMessageHeaderSize                   Size of the header section of an RMx message packet.
+       @constant       kRMxMessageInlineBufferSize             Size of the inline message buffer.
+       
+       @discussion
+       
+       Meanings of the field descriptions:
+       
+       PRIVATE - Indicates field is private and should not be touched.
+       IN              - Input field that must be set up before passing the message to RMx.
+       OUT             - Output field that whose value on input will be ignore and replaced with a new value on completion.
+       
+       When a message is passed to RMx, the message becomes the ownership of RMx until completion of the message. 
+       No fields of the messages should be touched while a message is in use by RMx.
+       
+       When sending messages asynchronously, the underlying storage for the message must be valid for the duration
+       of the message. This means stack-based storage cannot be for asynchronous messages because when the function
+       that allocated the stack-based variable returns, the message storage will go out of scope and become invalid.
+*/
+
+#define        kRMxMessageHeaderSize                   24              // <w:signature> <w:opcode> <w:flags> <w:xid> <w:status> <w:size>
+#define        kRMxMessageInlineBufferSize             1024    
+
+check_compile_time( kRMxMessageHeaderSize <= kRMxMessageInlineBufferSize );
+
+struct RMxMessage
+{
+       RMxSignature                    signature;
+       RMxOpCode                               opcode;
+       RMxFlags                                flags;
+       uint32_t                                xid;
+       OSStatus                                status;
+
+       uint32_t                                sendSize;
+       uint8_t *                               sendData;
+       uint32_t                                recvSize;
+       uint8_t *                               recvData;
+       
+       void *                                  context;
+       RMxSessionRef                   session;
+       
+       // PRIVATE (internal use only)
+       
+       uint32_t                                bufferSize;
+       uint8_t *                               buffer;
+       uint8_t                                 storage[ kRMxMessageInlineBufferSize ];
+};
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       RMxMessageInitialize
+
+       @abstract       Initializes an RMx message structure. Must be called before the message structure can be used.
+*/
+
+void   RMxMessageInitialize( RMxMessage *inMessage );
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       RMxMessageRelease
+
+       @abstract       Releases the resources used by an RMx message.
+*/
+
+void   RMxMessageRelease( RMxMessage *inMessage );
+
+#if 0
+#pragma mark == Sessions ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @typedef        RMxSessionFlags
+
+       @abstract       Session flags.
+       
+       @constant       kRMxSessionFlagsNone                    No flags.
+       @constant       kRMxSessionFlagServer                   Session is operating in server mode (replying to requests).
+       @constant       kRMxSessionFlagsNoThread                Do not create a thread to process messages (i.e. one-shot sync session).
+       @constant       kRMxSessionFlagsThreadDone              Thread is no longer active.
+       @constant       kRMxSessionFlagsNoClose                 Do not close the session when the thread exits.
+*/
+
+typedef uint32_t               RMxSessionFlags;
+
+#define        kRMxSessionFlagsNone                    0
+#define        kRMxSessionFlagsServer                  ( 1 << 0 )
+#define        kRMxSessionFlagsNoThread                ( 1 << 1 )
+#define        kRMxSessionFlagsThreadDone              ( 1 << 2 )
+#define        kRMxSessionFlagsNoClose                 ( 1 << 3 )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @struct         RMxSession
+
+       @abstract       Data structure for a session.
+*/
+
+typedef struct RMxSession              RMxSession;
+struct RMxSession
+{
+       RMxSessionRef                   next;
+       RMxSessionFlags                 flags;
+       SocketRef                               sock;
+       HANDLE                                  sockEvent;
+       HANDLE                                  closeEvent;
+       HANDLE                                  thread;
+       unsigned                                threadID;
+       DWORD                                   waitCount;
+       HANDLE                                  waitHandles[ 3 ];
+       bool                                    quit;
+       
+       RMxMessageCallBack              callback;
+       RMxMessage                              message;
+       uint8_t *                               messageRecvBuffer;
+       uint8_t *                               messageRecvBufferPtr;
+       int                                             messageRecvRemaining;
+       bool                                    messageRecvHeaderDone;
+};
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       RMxSessionOpen
+
+       @abstract       Opens a session and optionally sends a formatted message.
+*/
+
+OSStatus
+       RMxSessionOpen( 
+               const char *            inServer, 
+               RMxSessionFlags         inFlags, 
+               SocketRef                       inSock, 
+               RMxMessageCallBack      inCallBack, 
+               void *                          inContext, 
+               RMxSessionRef *         outSession, 
+               RMxOpCode                       inMessageOpCode, 
+               const char *            inMessageFormat, 
+               ... );
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       RMxSessionClose
+
+       @abstract       Closes a session.
+*/
+
+OSStatus       RMxSessionClose( RMxSessionRef inSession, OSStatus inReason );
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       RMxSessionSendMessage
+
+       @abstract       Sends a formatted message.
+*/
+
+OSStatus       RMxSessionSendMessage( RMxSessionRef inSession, RMxOpCode inOpCode, OSStatus inStatus, const char *inFormat, ... );
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       RMxSessionRecvMessage
+
+       @abstract       Synchronously receives a message.
+*/
+
+OSStatus       RMxSessionRecvMessage( RMxSessionRef inSession, DWORD inTimeout );
+
+#if 0
+#pragma mark == Utilities ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       RMxCheckVersion
+
+       @abstract       Compares client and server version information and returns if they are compatible.
+*/
+
+OSStatus
+       RMxCheckVersion( 
+               uint32_t inClientCurrentVersion, uint32_t inClientOldestClientVersion, uint32_t inClientOldestServerVersion, 
+               uint32_t inServerCurrentVersion, uint32_t inServerOldestClientVersion, uint32_t inServerOldestServerVersion );
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       RMxPackedSize
+
+       @abstract       Determines the number of bytes required to pack data using the specified format string and arguments.
+*/
+
+OSStatus       RMxPackedSize( size_t *outSize, const char *inFormat, ... );
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       RMxPackedSizeVAList
+
+       @abstract       Determines the number of bytes required to pack data using the format string and argument list.
+*/
+
+OSStatus       RMxPackedSizeVAList( size_t *outSize, const char *inFormat, va_list inArgs );
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       RMxPack
+
+       @abstract       Packs data into a buffer using the format string and arguments. 
+*/
+
+OSStatus       RMxPack( void *inBuffer, size_t inMaxSize, size_t *outSize, const char *inFormat, ... );
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       RMxPackVAList
+
+       @abstract       Packs data into a buffer using the format string and argument list. 
+*/
+
+OSStatus       RMxPackVAList( void *inBuffer, size_t inMaxSize, size_t *outSize, const char *inFormat, va_list inArgs );
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       RMxUnpack
+
+       @abstract       Unpacks data from a buffer using the format string and arguments.
+*/
+
+OSStatus       RMxUnpack( const void *inData, size_t inSize, const char *inFormat, ... );
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       RMxUnpackVAList
+
+       @abstract       Unpacks data from a buffer using the format string and argument list.
+*/
+
+OSStatus       RMxUnpackVAList( const void *inData, size_t inSize, const char *inFormat, va_list inArgs );
+
+#ifdef __cplusplus
+       }
+#endif
+
+#endif  // __RMx_COMMON__
diff --git a/mDNSWindows/RMxServer.c b/mDNSWindows/RMxServer.c
new file mode 100644 (file)
index 0000000..3c28089
--- /dev/null
@@ -0,0 +1,1656 @@
+/*
+ * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+    
+$Log: RMxServer.c,v $
+Revision 1.6  2004/04/15 01:00:05  bradley
+Removed support for automatically querying for A/AAAA records when resolving names. Platforms
+without .local name resolving support will need to manually query for A/AAAA records as needed.
+
+Revision 1.5  2004/04/09 21:03:14  bradley
+Changed port numbers to use network byte order for consistency with other platforms.
+
+Revision 1.4  2004/04/08 21:14:19  bradley
+Changed resolve callback to use correct calling conventions (previously hidden by a cast).
+
+Revision 1.3  2004/04/08 09:43:43  bradley
+Changed callback calling conventions to __stdcall so they can be used with C# delegates.
+
+Revision 1.2  2004/03/16 22:09:03  bradley
+Skip socket creation failures to handle local IPv6 addresses being returned by Windows even when
+they are not actually supported by the OS; Log a message and only fail if no sockets can be created.
+
+Revision 1.1  2004/01/30 02:35:13  bradley
+Rendezvous Message Exchange implementation for DNS-SD IPC on Windows.
+
+*/
+
+#include       <stdlib.h>
+#include       <stdio.h>
+#include       <string.h>
+
+#include       "CommonServices.h"
+#include       "DebugServices.h"
+
+#include       "DNSSD.h"
+#include       "DNSSDDirect.h"
+#include       "RMxCommon.h"
+
+#include       "RMxServer.h"
+
+#ifdef __cplusplus
+       extern "C" {
+#endif
+
+#if 0
+#pragma mark == Constants ==
+#endif
+
+//===========================================================================================================================
+//     Constants
+//===========================================================================================================================
+
+#define        DEBUG_NAME              "[RMxServer] "
+
+#if 0
+#pragma mark == Structures ==
+#endif
+
+//===========================================================================================================================
+//     Structures
+//===========================================================================================================================
+
+typedef void ( *DNSServiceRefReleaseCallBack )( DNSServiceRef inRef );
+
+// DNSServiceRef
+
+typedef struct _DNSServiceRef_t        _DNSServiceRef_t;
+struct _DNSServiceRef_t
+{
+       RMxOpCode                       opcode;
+       bool                            sessionClosing;
+       RMxSessionRef           session;
+       DNSServiceRef           directObj;
+       DNSRecordRef            records;
+};
+
+// DNSRecordRef
+
+typedef struct _DNSRecordRef_t         _DNSRecordRef_t;
+struct _DNSRecordRef_t
+{
+       DNSRecordRef            next;
+       uint32_t                        id;
+       DNSServiceRef           owner;
+       DNSRecordRef            directObj;
+};
+
+#if 0
+#pragma mark == Prototypes ==
+#endif
+
+//===========================================================================================================================
+//     Prototypes
+//===========================================================================================================================
+
+// RMx
+
+DEBUG_LOCAL OSStatus   RMxServerRunInitialize( void );
+DEBUG_LOCAL void               RMxServerRunFinalize( void );
+DEBUG_LOCAL void               RMxServerMessageCallBack( RMxMessage *inMessage );
+
+// General
+
+DEBUG_LOCAL void       DNSServiceRefDeallocate_server( DNSServiceRef inRef );
+DEBUG_LOCAL void       DNSServiceCheckVersion_server( RMxMessage *inMessage );
+
+// Properties
+
+DEBUG_LOCAL void               DNSServiceCopyProperty_server( RMxMessage *inMessage );
+DEBUG_LOCAL OSStatus   DNSServiceCopyPropertySendData_server( DNSPropertyCode inCode, RMxMessage *inMessage );
+
+// Domain Enumeration
+
+DEBUG_LOCAL void       DNSServiceEnumerateDomains_server( RMxMessage *inMessage );
+DEBUG_LOCAL void CALLBACK_COMPAT
+       DNSServiceEnumerateDomainsCallBack_server(
+               DNSServiceRef           sdRef,
+               DNSServiceFlags         flags,
+               uint32_t                        interfaceIndex,
+               DNSServiceErrorType     errorCode,
+               const char *            replyDomain,  
+               void *                          context );
+
+// Service Registration
+
+DEBUG_LOCAL void       DNSServiceRegister_server( RMxMessage *inMessage );
+DEBUG_LOCAL void CALLBACK_COMPAT
+       DNSServiceRegisterCallBack_server(
+               DNSServiceRef           inRef,
+               DNSServiceFlags         inFlags,
+               DNSServiceErrorType     inErrorCode,
+               const char *            inName,  
+               const char *            inType,  
+               const char *            inDomain,  
+               void *                          inContext );
+
+DEBUG_LOCAL void       DNSServiceAddRecord_server( RMxMessage *inMessage );
+DEBUG_LOCAL void       DNSServiceUpdateRecord_server( RMxMessage *inMessage );
+DEBUG_LOCAL void       DNSServiceRemoveRecord_server( RMxMessage *inMessage );
+
+// Service Discovery
+
+DEBUG_LOCAL void       DNSServiceBrowse_server( RMxMessage *inMessage );
+DEBUG_LOCAL void CALLBACK_COMPAT
+       DNSServiceBrowseCallBack_server(
+               DNSServiceRef           inRef,
+               DNSServiceFlags         inFlags,
+               uint32_t                        inInterfaceIndex,
+               DNSServiceErrorType     inErrorCode,
+               const char *            inName,  
+               const char *            inType,  
+               const char *            inDomain,  
+               void *                          inContext );
+
+DEBUG_LOCAL void       DNSServiceResolve_server( RMxMessage *inMessage );
+DEBUG_LOCAL void CALLBACK_COMPAT
+       DNSServiceResolveCallBack_server(
+               DNSServiceRef                   inRef,
+               DNSServiceFlags                 inFlags,
+               uint32_t                                inInterfaceIndex,
+               DNSServiceErrorType             inErrorCode,
+               const char *                    inFullName,  
+               const char *                    inHostName,  
+               uint16_t                                inPort, 
+               uint16_t                                inTXTSize, 
+               const char *                    inTXT, 
+               void *                                  inContext );
+
+// Special Purpose
+
+DEBUG_LOCAL void       DNSServiceCreateConnection_server( RMxMessage *inMessage );
+
+DEBUG_LOCAL void       DNSServiceRegisterRecord_server( RMxMessage *inMessage );
+DEBUG_LOCAL void CALLBACK_COMPAT
+       DNSServiceRegisterRecordCallBack_server( 
+               DNSServiceRef           inRef,
+               DNSRecordRef            inRecordRef,
+               DNSServiceFlags         inFlags,
+               DNSServiceErrorType     inErrorCode,
+               void *                          inContext );
+
+DEBUG_LOCAL void       DNSServiceQueryRecord_server( RMxMessage *inMessage );
+DEBUG_LOCAL void CALLBACK_COMPAT
+       DNSServiceQueryRecordCallBack_server(
+               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       DNSServiceReconfirmRecord_server( RMxMessage *inMessage );
+
+#if 0
+#pragma mark == Globals ==
+#endif
+
+//===========================================================================================================================
+//     Globals
+//===========================================================================================================================
+
+DEBUG_LOCAL RMxServerFlags             gRMxServerFlags                         = kRMxServerFlagsNone;
+DEBUG_LOCAL SocketRef                  gRMxServerSockets[ 2 ]          = { kInvalidSocketRef, kInvalidSocketRef };
+DEBUG_LOCAL HANDLE                             gRMxServerSocketEvents[ 2 ]     = { NULL, NULL };
+DEBUG_LOCAL HANDLE                             gRMxServerQuitDoneEvent         = NULL;
+
+#if 0
+#pragma mark -
+#pragma mark == RMx ==
+#endif
+
+//===========================================================================================================================
+//     RMxServerInitialize
+//===========================================================================================================================
+
+OSStatus       RMxServerInitialize( RMxServerFlags inFlags )
+{
+       OSStatus                err;
+       
+       err = RMxInitialize();
+       require_noerr( err, exit );
+       
+       // Set up the quit done event to allow for waiting until the run loop is quit. A manual-reset event is used so 
+       // multiple calls to the stopping code will all see that the quit event has been signaled (not just the first). 
+       // The event is also created as signaled so even if run is not called, a stop or finalize will still run successfully.
+       // The event will be explicitly reset to an unsignaled state when the run loop starts.
+       
+       gRMxServerQuitDoneEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
+       err = translate_errno( gRMxServerQuitDoneEvent, errno_compat(), kNoResourcesErr );
+       require_noerr( err, exit );
+       
+       gRMxServerFlags = inFlags;
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     RMxServerFinalize
+//===========================================================================================================================
+
+void   RMxServerFinalize( void )
+{
+       BOOL            ok;
+       
+       RMxServerStop( kRMxServerStopFlagsNone );
+       
+       // Release the quit event.
+       
+       if( gRMxServerQuitDoneEvent )
+       {
+               ok = CloseHandle( gRMxServerQuitDoneEvent );
+               check_translated_errno( ok, errno_compat(), kUnknownErr );
+               gRMxServerQuitDoneEvent = NULL;
+       }
+       
+       RMxFinalize();
+}
+
+//===========================================================================================================================
+//     RMxServerRun
+//===========================================================================================================================
+
+OSStatus       RMxServerRun( void )
+{
+       OSStatus                err;
+       DWORD                   waitCount;
+       HANDLE                  waitHandles[ 3 ];
+       
+       // Initialize the server run loop and set up the list of objects to wait for.
+       
+       err = RMxServerRunInitialize();
+       require_noerr( err, exit );
+       
+       waitCount = 0;
+       waitHandles[ waitCount++ ] = gRMxServerSocketEvents[ 0 ];
+       waitHandles[ waitCount++ ] = gRMxServerSocketEvents[ 1 ];
+       waitHandles[ waitCount++ ] = gRMxStateChangeEvent;
+       check( waitCount == sizeof_array( waitHandles ) );
+       
+       // Main event loop. Process connection requests and state changes (i.e. quit).
+       
+       while( gRMxState == kRMxStateRun )
+       {
+               DWORD           result;
+               
+               result = WaitForMultipleObjects( waitCount, waitHandles, FALSE, INFINITE );
+               if( ( result ==   WAIT_OBJECT_0 ) ||                            
+                       ( result == ( WAIT_OBJECT_0 + 1 ) ) )   // Socket Events
+               {
+                       SocketRef                                       sock;
+                       struct sockaddr_storage         addr;
+                       socklen_t                                       addrSize;
+                       DWORD                                           index;
+                       
+                       index = result - WAIT_OBJECT_0;
+                       check( ( index == 0 ) || IsValidSocket( gRMxServerSockets[ index ] ) );
+                       
+                       // The socket event is only set up to notify on connection requests so try to accept the connection.
+                       // Note: It is possible for accept to fail if the client aborts the connection after the network stack
+                       // sees the connection request, but before accept is called. See UNPv1 section 15.6 for more information.
+                       
+                       addrSize = sizeof( addr );
+                       sock = accept( gRMxServerSockets[ index ], (struct sockaddr *) &addr, &addrSize );
+                       if( IsValidSocket( sock ) )
+                       {
+                               if( ( gRMxServerFlags & kRMxServerFlagsAllowRemote ) || SOCKADDR_IS_IP_LOOPBACK( &addr ) )
+                               {
+                                       dlog( kDebugLevelNotice, "\n" DEBUG_NAME "accepting connection from %##a\n", &addr );
+                                       
+                                       err = RMxSessionOpen( NULL, kRMxSessionFlagsNone, sock, RMxServerMessageCallBack, NULL, NULL, 
+                                               kRMxOpCodeInvalid, NULL );
+                                       check_noerr( err );
+                               }
+                               else
+                               {
+                                       dlog( kDebugLevelNotice, DEBUG_NAME "remote connection attempt from %##a when local-only\n", &addr );
+                                       
+                                       err = close_compat( sock );
+                                       check_translated_errno( err == 0, errno_compat(), kUnknownErr );
+                               }
+                       }
+                       else
+                       {
+                               err = errno_compat();
+                               dlog( kDebugLevelWarning, DEBUG_NAME "connection abort before accept (%d %m)\n", err, err );
+                       }
+               }
+               else if( result == ( WAIT_OBJECT_0 + 2 ) )      // State Change Event
+               {
+                       dlog( kDebugLevelNotice, DEBUG_NAME "state change (%d)\n", gRMxState );
+                       break;
+               }
+               else
+               {
+                       err = (OSStatus) GetLastError();
+                       dlog( kDebugLevelAlert, DEBUG_NAME "wait error: 0x%08X, %d (%m)\n", result, err, err );
+                       err = (OSStatus) result;
+                       goto exit;
+               }
+       }
+       err = kNoErr;
+       
+exit:
+       RMxServerRunFinalize();
+       return( err );
+}
+
+//===========================================================================================================================
+//     RMxServerRunInitialize
+//===========================================================================================================================
+
+DEBUG_LOCAL OSStatus   RMxServerRunInitialize( void )
+{
+       OSStatus                                        err;
+       struct addrinfo                         hints;
+       struct addrinfo *                       addrList;
+       struct addrinfo *                       addr;
+       int                                                     nAddrs;
+       BOOL                                            ok;
+       int                                                     option;
+       
+       addrList = NULL;
+       
+       // Set up a socket for each address (only expected to be a single IPv4 and optionally a single IPv6 address). 
+       // Windows does not support IPv4-mapped IPv6 addresses so we have to create a separate socket for each type.
+
+       memset( &hints, 0, sizeof( hints ) );
+       hints.ai_flags          = AI_PASSIVE;
+       hints.ai_family         = AF_UNSPEC;
+       hints.ai_socktype       = SOCK_STREAM;
+       hints.ai_protocol       = IPPROTO_TCP;
+       
+       err = getaddrinfo( NULL, kRMxServerPortString, &hints, &addrList );
+       require_noerr( err, exit );
+       
+       nAddrs = 0;
+       for( addr = addrList; addr; addr = addr->ai_next )
+       {
+               dlog( kDebugLevelTrace, DEBUG_NAME "setting up %s socket\n", 
+                       ( addr->ai_family == AF_INET ) ? "AF_INET" : ( addr->ai_family == AF_INET6 ) ? "AF_INET6" : "<unknown>" );
+               if( nAddrs > 1 )
+               {
+                       dlog( kDebugLevelWarning, DEBUG_NAME "cannot handle more than 2 listening sockets (unexpected)\n" );
+                       break;
+               }
+               
+               gRMxServerSockets[ nAddrs ] = socket( addr->ai_family, addr->ai_socktype, addr->ai_protocol );
+               err = translate_errno( IsValidSocket( gRMxServerSockets[ nAddrs ] ), errno_compat(), kNoResourcesErr );
+               if( err != kNoErr )
+               {
+                       dlog( kDebugLevelNotice, DEBUG_NAME "%s socket not supported (%d %m)\n", 
+                               ( addr->ai_family == AF_INET ) ? "AF_INET" : ( addr->ai_family == AF_INET6 ) ? "AF_INET6" : "<unknown>", 
+                               err, err );
+                       continue;
+               }
+               
+               // Enable the address-reuse option so the server can be stopped and re-started without the TIME_WAIT delay.
+               
+               option = 1;
+               err = setsockopt( gRMxServerSockets[ nAddrs ], SOL_SOCKET, SO_REUSEADDR, (char *) &option, sizeof( option ) );
+               err = translate_errno( err == 0, errno_compat(), kInUseErr );
+               require_noerr( err, exit );
+               
+               // Set up to signal an event when a connection can be accepted so we can wait for it with WaitForMultipleObjects.
+               // Note: WSAEventSelect makes the socket non-blocking so it does not need to made non-blocking separately.
+               
+               gRMxServerSocketEvents[ nAddrs ] = CreateEvent( NULL, FALSE, FALSE, NULL );
+               err = translate_errno( gRMxServerSocketEvents[ nAddrs ], errno_compat(), kNoResourcesErr );
+               require_noerr( err, exit );
+               
+               err = WSAEventSelect( gRMxServerSockets[ nAddrs ], gRMxServerSocketEvents[ nAddrs ], FD_ACCEPT );
+               err = translate_errno( err == 0, errno_compat(), kInUseErr );
+               require_noerr( err, exit );
+               
+               // Bind to the server port and enable listening for connections.
+               
+               err = bind( gRMxServerSockets[ nAddrs ], addr->ai_addr, (int) addr->ai_addrlen );
+               err = translate_errno( err == 0, errno_compat(), kNoResourcesErr );
+               require_noerr( err, exit );
+               
+               err = listen( gRMxServerSockets[ nAddrs ], SOMAXCONN );
+               err = translate_errno( err == 0, errno_compat(), kNoResourcesErr );
+               require_noerr( err, exit );
+               
+               ++nAddrs;
+       }
+       require_action( nAddrs > 0, exit, err = kUnknownErr );
+       
+       // Create a dummy event (which will never be signaled) to simplify WaitForMultipleObjects usage,
+       
+       if( !gRMxServerSocketEvents[ 1 ] )
+       {
+               gRMxServerSocketEvents[ 1 ] = CreateEvent( NULL, FALSE, FALSE, NULL );
+               err = translate_errno( gRMxServerSocketEvents[ 1 ], errno_compat(), kNoResourcesErr );
+               require_noerr( err, exit );
+       }
+       
+       // Reset the quit event to an unsignaled state so other code can wait for the run loop to quit.
+       
+       gRMxState = kRMxStateRun;
+       ok = ResetEvent( gRMxServerQuitDoneEvent );
+       err = translate_errno( ok, errno_compat(), kUnknownErr );
+       require_noerr( err, exit );
+       
+exit:
+       if( addrList )
+       {
+               freeaddrinfo( addrList );
+       }
+       if( err != kNoErr )
+       {
+               RMxServerRunFinalize();
+       }
+       return( err );
+}
+
+//===========================================================================================================================
+//     RMxServerRunFinalize
+//
+//     Note: This routine is safe to call multiple times (for easier cleanup).
+//===========================================================================================================================
+
+DEBUG_LOCAL void       RMxServerRunFinalize( void )
+{
+       OSStatus                err;
+       BOOL                    ok;
+       
+       // Release the socket events
+       
+       if( gRMxServerSocketEvents[ 0 ] )
+       {
+               ok = CloseHandle( gRMxServerSocketEvents[ 0 ] );
+               check_translated_errno( ok, errno_compat(), kUnknownErr );
+               gRMxServerSocketEvents[ 0 ] = NULL;
+       }
+       if( gRMxServerSocketEvents[ 1 ] )
+       {
+               ok = CloseHandle( gRMxServerSocketEvents[ 1 ] );
+               check_translated_errno( ok, errno_compat(), kUnknownErr );
+               gRMxServerSocketEvents[ 1 ] = NULL;
+       }
+       
+       // Close the sockets.
+       
+       if( IsValidSocket( gRMxServerSockets[ 0 ] ) )
+       {
+               err = close_compat( gRMxServerSockets[ 0 ] );
+               check_translated_errno( err == 0, errno_compat(), kUnknownErr );
+               gRMxServerSockets[ 0 ] = kInvalidSocketRef;
+       }
+       if( IsValidSocket( gRMxServerSockets[ 1 ] ) )
+       {
+               err = close_compat( gRMxServerSockets[ 1 ] );
+               check_translated_errno( err == 0, errno_compat(), kUnknownErr );
+               gRMxServerSockets[ 1 ] = kInvalidSocketRef;
+       }
+       
+       // Signal the quit event to indicate the run loop has quit.
+       
+       ok = SetEvent( gRMxServerQuitDoneEvent );
+       check_translated_errno( ok, errno_compat(), kUnknownErr );
+}
+
+//===========================================================================================================================
+//     RMxServerStop
+//===========================================================================================================================
+
+OSStatus       RMxServerStop( RMxServerStopFlags inFlags )
+{
+       BOOL            ok;
+       DWORD           result;
+       
+       // Signal a state changed event to trigger everything to stop. Note: This is a manual-reset event so it will 
+       // remain signaled to allow all running threads to wake up and exit cleanly.
+       
+       gRMxState = kRMxStateStop;
+       if( gRMxStateChangeEvent )
+       {
+               ok = SetEvent( gRMxStateChangeEvent );
+               check_translated_errno( ok, errno_compat(), kUnknownErr );
+       }
+       
+       // Wait for the quit event indicating the run loop has quit. Give up after 10 seconds to handle a hung thread.
+       
+       if( !( inFlags & kRMxServerStopFlagsNoWait ) )
+       {
+               if( gRMxServerQuitDoneEvent )
+               {
+                       result = WaitForSingleObject( gRMxServerQuitDoneEvent, 10 * 1000 );
+                       check_translated_errno( result == WAIT_OBJECT_0, errno_compat(), result );
+               }
+       }
+       
+       return( kNoErr );
+}
+
+//===========================================================================================================================
+//     RMxServerMessageCallBack
+//===========================================================================================================================
+
+DEBUG_LOCAL void       RMxServerMessageCallBack( RMxMessage *inMessage )
+{
+       DNSServiceRef           obj;
+       OSStatus                        err;
+       
+       check( inMessage );
+       check( inMessage->session );
+       
+       switch( inMessage->opcode )
+       {
+               // General
+               
+               case kRMxOpCodeInvalid:
+                       
+                       // The session is closing so delete the object (if still valid). Invalidate the session because the session
+                       // is already in the process of closing so we don't want the deallocate code closing it again.
+                       
+                       obj = (DNSServiceRef) inMessage->context;
+                       if( obj )
+                       {
+                               obj->sessionClosing = true;
+                               DNSServiceRefDeallocate_server( obj );
+                       }
+                       break;
+               
+               case kRMxOpCodeCheckVersion:
+                       DNSServiceCheckVersion_server( inMessage );
+                       break;
+               
+               // Properties
+               
+               case kRMxOpCodeCopyProperty:
+                       DNSServiceCopyProperty_server( inMessage );
+                       break;
+               
+               // Domain Enumeration
+               
+               case kRMxOpCodeEnumerateDomains:
+                       DNSServiceEnumerateDomains_server( inMessage );
+                       break;
+               
+               // Service Registration
+               
+               case kRMxOpCodeRegister:
+                       DNSServiceRegister_server( inMessage );
+                       break;
+               
+               case kRMxOpCodeAddRecord:
+                       DNSServiceAddRecord_server( inMessage );
+                       break;
+               
+               case kRMxOpCodeUpdateRecord:
+                       DNSServiceUpdateRecord_server( inMessage );
+                       break;
+               
+               case kRMxOpCodeRemoveRecord:
+                       DNSServiceRemoveRecord_server( inMessage );
+                       break;
+               
+               // Service Discovery
+               
+               case kRMxOpCodeBrowse:
+                       DNSServiceBrowse_server( inMessage );
+                       break;
+               
+               case kRMxOpCodeResolve:
+                       DNSServiceResolve_server( inMessage );
+                       break;
+               
+               // Special Purpose
+               
+               case kRMxOpCodeCreateConnection:
+                       DNSServiceCreateConnection_server( inMessage );
+                       break;
+               
+               case kRMxOpCodeRegisterRecord:
+                       DNSServiceRegisterRecord_server( inMessage );
+                       break;
+               
+               case kRMxOpCodeQueryRecord:
+                       DNSServiceQueryRecord_server( inMessage );
+                       break;
+               
+               case kRMxOpCodeReconfirmRecord:
+                       DNSServiceReconfirmRecord_server( inMessage );
+                       break;
+               
+               default:
+                       dlog( kDebugLevelWarning, DEBUG_NAME "message with unknown opcode received (%d)\n", inMessage->opcode );
+                       err = RMxSessionSendMessage( inMessage->session, inMessage->opcode, kUnsupportedErr, "" );
+                       check_noerr( err );
+                       break;
+       }
+}
+
+#if 0
+#pragma mark -
+#pragma mark == DNS-SD General ==
+#endif
+
+//===========================================================================================================================
+//     DNSServiceRefDeallocate_server
+//===========================================================================================================================
+
+DEBUG_LOCAL void       DNSServiceRefDeallocate_server( DNSServiceRef inRef )
+{
+       OSStatus                err;
+       
+       check( inRef );
+       
+       dlog( kDebugLevelTrace, DEBUG_NAME "%s: ref=%#p\n", __ROUTINE__, inRef );
+               
+       // Release the direct object if active.
+       
+       if( inRef->directObj )
+       {
+               DNSServiceRefDeallocate_direct( inRef->directObj );
+       }
+       
+       // Close the session.
+       
+       if( inRef->session && !inRef->sessionClosing )
+       {
+               inRef->session->callback                = NULL;
+               inRef->session->message.context = NULL;
+               
+               err = RMxSessionClose( inRef->session, kEndingErr );
+               check_noerr( err );
+       }
+       
+       // Release any extra records.
+       
+       while( inRef->records )
+       {
+               DNSRecordRef            record;
+               
+               record = inRef->records;
+               inRef->records = record->next;
+               
+               free( record );
+       }
+       
+       // Release the object.
+       
+       free( inRef );
+}
+
+//===========================================================================================================================
+//     DNSServiceCheckVersion_server
+//===========================================================================================================================
+
+DEBUG_LOCAL void       DNSServiceCheckVersion_server( RMxMessage *inMessage )
+{
+       OSStatus                err;
+       uint32_t                clientCurrentVersion;
+       uint32_t                clientOldestClientVersion;
+       uint32_t                clientOldestServerVersion;
+       
+       check( inMessage );
+       check( inMessage->session );
+       
+       // Extract parameters from the message.
+       
+       err = RMxUnpack( inMessage->recvData, inMessage->recvSize, "www", 
+               &clientCurrentVersion, &clientOldestClientVersion, &clientOldestServerVersion );
+       require_noerr( err, exit );
+       
+       dlog( kDebugLevelTrace, DEBUG_NAME "%s: clientCurrent=%v, clientOldestClient=%v, clientOldestServer=%v\n", 
+               __ROUTINE__, clientCurrentVersion, clientOldestClientVersion, clientOldestServerVersion );
+       
+       err = RMxCheckVersion( clientCurrentVersion, clientOldestClientVersion, clientOldestServerVersion, 
+                                                  kRMxCurrentVersion, kRMxOldestClientVersion, kRMxOldestServerVersion );
+               
+       // Send the response and our version information. Cause the session to quit since this is a one-shot session.
+       
+exit:
+       err = RMxSessionSendMessage( inMessage->session, inMessage->opcode, kNoErr, "wwww", 
+               err, kRMxCurrentVersion, kRMxOldestClientVersion, kRMxOldestServerVersion );
+       check_noerr( err );
+       
+       inMessage->session->quit = true;
+}
+
+#if 0
+#pragma mark -
+#pragma mark == DNS-SD Properties ==
+#endif
+
+//===========================================================================================================================
+//     DNSServiceCopyProperty_server
+//===========================================================================================================================
+
+DEBUG_LOCAL void       DNSServiceCopyProperty_server( RMxMessage *inMessage )
+{
+       OSStatus                        err;
+       DNSPropertyCode         code;
+       
+       check( inMessage );
+       check( inMessage->session );
+       
+       // Extract parameters from the message.
+       
+       err = RMxUnpack( inMessage->recvData, inMessage->recvSize, "w", &code );
+       require_noerr( err, exit );
+       
+       dlog( kDebugLevelTrace, DEBUG_NAME "%s: code='%C'\n", __ROUTINE__, code );
+       
+               
+       // Send the response and our version information. Cause the session to quit since this is a one-shot session.
+       
+exit:
+       err = DNSServiceCopyPropertySendData_server( code, inMessage );
+       check_noerr( err );
+       
+       inMessage->session->quit = true;
+}
+
+//===========================================================================================================================
+//     DNSServiceCopyPropertySendData_server
+//===========================================================================================================================
+
+DEBUG_LOCAL OSStatus   DNSServiceCopyPropertySendData_server( DNSPropertyCode inCode, RMxMessage *inMessage )
+{
+       OSStatus                err;
+       
+       switch( inCode )
+       {
+               case kDNSPropertyCodeVersion:
+                       
+                       // Note: This manually builds the "n" data type using a "w" size followed by the data to avoid a temporary buffer.
+                       
+                       err = RMxSessionSendMessage( inMessage->session, inMessage->opcode, kNoErr, "ww wwww", kNoErr, inCode, 
+                               4 + 4 + 4, kRMxCurrentVersion, kRMxOldestClientVersion, kRMxOldestServerVersion );
+                       require_noerr( err, exit );
+                       break;
+               
+               default:
+                       dlog( kDebugLevelWarning, DEBUG_NAME "%s: unknown property code (%C)\n", __ROUTINE__, inCode );
+                       err = kDNSServiceErr_Unsupported;
+                       err = RMxSessionSendMessage( inMessage->session, inMessage->opcode, kNoErr, "wn", err, 0, NULL );
+                       require_noerr( err, exit );
+                       break;
+       }
+       err = kNoErr;
+       
+exit:
+       return( err );
+}
+
+#if 0
+#pragma mark DNSServiceReleaseProperty_server
+#endif
+
+// Note: DNSServiceReleaseProperty_server is not needed on the server side because memory is released immediately after sending.
+
+#if 0
+#pragma mark -
+#pragma mark == DNS-SD Domain Enumeration ==
+#endif
+
+//===========================================================================================================================
+//     DNSServiceEnumerateDomains_server
+//===========================================================================================================================
+
+DEBUG_LOCAL void       DNSServiceEnumerateDomains_server( RMxMessage *inMessage )
+{
+       OSStatus                        err;
+       DNSServiceRef           obj;
+       DNSServiceFlags         flags;
+       uint32_t                        interfaceIndex;
+       
+       obj = NULL;
+       check( inMessage );
+       check( inMessage->session );
+       require_action( !inMessage->session->message.context, exit, err = kTypeErr );
+       
+       // Extract parameters from the message.
+       
+       err = RMxUnpack( inMessage->recvData, inMessage->recvSize, "ww", &flags, &interfaceIndex );
+       require_noerr( err, exit );
+       
+       dlog( kDebugLevelTrace, DEBUG_NAME "%s: flags=0x%08X, ifi=%d\n", __ROUTINE__, flags, interfaceIndex );
+       
+       // Allocate and initialize the object.
+       
+       obj = (DNSServiceRef) calloc( 1, sizeof( *obj ) );
+       require_action( obj, exit, err = kNoMemoryErr );
+       
+       obj->opcode  = inMessage->opcode;
+       obj->session = inMessage->session;
+       
+       err = DNSServiceEnumerateDomains_direct( &obj->directObj, flags, interfaceIndex, 
+               DNSServiceEnumerateDomainsCallBack_server, obj );
+       require_noerr( err, exit );
+       
+       // Success!
+       
+       inMessage->session->message.context = obj;
+       obj = NULL;
+       
+exit:
+       if( err != kNoErr )
+       {
+               err = RMxSessionSendMessage( inMessage->session, inMessage->opcode, err, "" );
+               check_noerr( err );
+       }
+       if( obj )
+       {
+               DNSServiceRefDeallocate_server( obj );
+       }
+}
+
+//===========================================================================================================================
+//     DNSServiceEnumerateDomainsCallBack_server
+//===========================================================================================================================
+
+DEBUG_LOCAL void CALLBACK_COMPAT
+       DNSServiceEnumerateDomainsCallBack_server(
+               DNSServiceRef           inRef,
+               DNSServiceFlags         inFlags,
+               uint32_t                        inInterfaceIndex,
+               DNSServiceErrorType     inErrorCode,
+               const char *            inDomain,  
+               void *                          inContext )
+{
+       DNSServiceRef           obj;
+       OSStatus                        err;
+       
+       DEBUG_UNUSED( inRef );
+       
+       check( inDomain );
+       obj = (DNSServiceRef) inContext;
+       check( obj );
+       check( obj->session );
+       
+       err = RMxSessionSendMessage( obj->session, kRMxOpCodeEnumerateDomains, kNoErr, "wwws", 
+               inFlags, inInterfaceIndex, inErrorCode, inDomain );
+       check_noerr( err );
+}
+
+#if 0
+#pragma mark -
+#pragma mark == DNS-SD Service Registration ==
+#endif
+
+//===========================================================================================================================
+//     DNSServiceRegister_server
+//===========================================================================================================================
+
+DEBUG_LOCAL void       DNSServiceRegister_server( RMxMessage *inMessage )
+{
+       OSStatus                        err;
+       DNSServiceRef           obj;
+       DNSServiceFlags         flags;
+       uint32_t                        interfaceIndex;
+       const char *            name;
+       const char *            type;
+       const char *            domain;
+       const char *            host;
+       uint16_t                        port;
+       const void *            txt;
+       size_t                          txtSize;
+       
+       obj = NULL;
+       check( inMessage );
+       check( inMessage->session );
+       require_action( !inMessage->session->message.context, exit, err = kTypeErr );
+       
+       // Extract parameters from the message.
+       
+       err = RMxUnpack( inMessage->recvData, inMessage->recvSize, "wwsssshn", 
+               &flags, &interfaceIndex, &name, NULL, &type, NULL, &domain, NULL, &host, NULL, &port, &txt, &txtSize );
+       require_noerr( err, exit );
+       
+       dlog( kDebugLevelTrace, DEBUG_NAME
+               "%s: flags=0x%08X, ifi=%ld, name=\"%s\", type=\"%s\", domain=\"%s\", host=\"%s\", port=%d, txtSize=%d\n", 
+               __ROUTINE__, flags, interfaceIndex, name, type, domain, host, ntohs( port ), txtSize );
+       
+       // Allocate and initialize the object.
+       
+       obj = (DNSServiceRef) calloc( 1, sizeof( *obj ) );
+       require_action( obj, exit, err = kNoMemoryErr );
+       
+       obj->opcode  = inMessage->opcode;
+       obj->session = inMessage->session;
+       
+       err = DNSServiceRegister_direct( &obj->directObj, flags, interfaceIndex, name, type, domain, host, port, 
+               (uint16_t) txtSize, txt, DNSServiceRegisterCallBack_server, obj );
+       require_noerr( err, exit );
+       
+       // Success!
+       
+       inMessage->session->message.context = obj;
+       obj = NULL;
+       
+exit:
+       if( err != kNoErr )
+       {
+               err = RMxSessionSendMessage( inMessage->session, inMessage->opcode, err, "" );
+               check_noerr( err );
+       }
+       if( obj )
+       {
+               DNSServiceRefDeallocate_server( obj );
+       }
+}
+
+//===========================================================================================================================
+//     DNSServiceRegisterCallBack_server
+//===========================================================================================================================
+
+DEBUG_LOCAL void CALLBACK_COMPAT
+       DNSServiceRegisterCallBack_server(
+               DNSServiceRef           inRef,
+               DNSServiceFlags         inFlags,
+               DNSServiceErrorType     inErrorCode,
+               const char *            inName,  
+               const char *            inType,  
+               const char *            inDomain,  
+               void *                          inContext )
+{
+       DNSServiceRef           obj;
+       OSStatus                        err;
+       
+       DEBUG_UNUSED( inRef );
+       
+       check( inDomain );
+       obj = (DNSServiceRef) inContext;
+       check( obj );
+       check( obj->session );
+       
+       err = RMxSessionSendMessage( obj->session, kRMxOpCodeRegister, kNoErr, "wwsss", 
+               inFlags, inErrorCode, inName, inType, inDomain );
+       check_noerr( err );
+}
+
+//===========================================================================================================================
+//     DNSServiceAddRecord_server
+//===========================================================================================================================
+
+DEBUG_LOCAL void       DNSServiceAddRecord_server( RMxMessage *inMessage )
+{
+       OSStatus                        err;
+       DNSRecordRef            obj;
+       DNSServiceRef           ref;
+       uint32_t                        id;
+       DNSServiceFlags         flags;
+       uint16_t                        rrType;
+       uint8_t *                       rData;
+       size_t                          rDataSize;
+       uint32_t                        ttl;
+       DNSRecordRef *          p;
+       
+       obj = NULL;
+       check( inMessage );
+       check( inMessage->session );
+       ref = (DNSServiceRef) inMessage->context;
+       require_action( ref, exit, err = kNotInitializedErr );
+       require_action( ref->opcode == kRMxOpCodeRegister, exit, err = kTypeErr );
+       check( ref->directObj );
+       
+       // Extract parameters from the message.
+       
+       err = RMxUnpack( inMessage->recvData, inMessage->recvSize, "wwhnw", &id, &flags, &rrType, &rData, &rDataSize, &ttl );
+       require_noerr( err, exit );
+       
+       dlog( kDebugLevelTrace, DEBUG_NAME "%s: id=%d, flags=0x%08X, rrType=%d, rDataSize=%d, ttl=%d\n", 
+               __ROUTINE__, id, flags, rrType, rDataSize, ttl );
+       
+       // Allocate and initialize the object and add it to the list of records.
+       
+       obj = (DNSRecordRef) calloc( 1, sizeof( *obj ) );
+       require_action( obj, exit, err = kNoMemoryErr );
+       
+       obj->id                 = id;
+       
+       obj->next               = ref->records;
+       ref->records    = obj;
+       
+       err = DNSServiceAddRecord_direct( ref->directObj, &obj->directObj, flags, rrType, (uint16_t) rDataSize, rData, ttl );
+       require_noerr( err, exit );
+       
+       obj = NULL;
+       
+exit:
+       if( err != kNoErr )
+       {
+               err = RMxSessionSendMessage( inMessage->session, inMessage->opcode, err, "" );
+               check_noerr( err );
+       }
+       if( obj )
+       {
+               for( p = &ref->records; *p; p = &( *p )->next )
+               {
+                       if( *p == obj )
+                       {
+                               *p = obj->next;
+                               free( obj );
+                               break;
+                       }
+               }
+       }
+}
+
+//===========================================================================================================================
+//     DNSServiceUpdateRecord_server
+//===========================================================================================================================
+
+DEBUG_LOCAL void       DNSServiceUpdateRecord_server( RMxMessage *inMessage )
+{
+       OSStatus                        err;
+       DNSServiceRef           ref;
+       uint32_t                        id;
+       DNSServiceFlags         flags;
+       uint8_t *                       rData;
+       size_t                          rDataSize;
+       uint32_t                        ttl;
+       DNSRecordRef            obj;
+       
+       check( inMessage );
+       check( inMessage->session );
+       ref = (DNSServiceRef) inMessage->context;
+       require_action( ref, exit, err = kNotInitializedErr );
+       require_action( ( ref->opcode == kRMxOpCodeRegister ) || ( ref->opcode == kRMxOpCodeCreateConnection ), exit, err = kTypeErr );
+       check( ref->directObj );
+       
+       // Extract parameters from the message.
+       
+       err = RMxUnpack( inMessage->recvData, inMessage->recvSize, "wwnw", &id, &flags, &rData, &rDataSize, &ttl );
+       require_noerr( err, exit );
+       
+       dlog( kDebugLevelTrace, DEBUG_NAME "%s: id=%d, flags=0x%08X, rDataSize=%d, ttl=%d\n", __ROUTINE__, id, flags, rDataSize, ttl );
+       
+       // Find the record with the specified ID and update it.
+       
+       if( id == kDNSRecordIndexDefaultTXT )
+       {
+               obj = NULL;
+       }
+       else
+       {
+               for( obj = ref->records; obj; obj = obj->next )
+               {
+                       if( obj->id == id )
+                       {
+                               break;
+                       }
+               }
+               require_action( obj, exit, err = kNotFoundErr );
+               check( obj->directObj );
+       }
+       
+       err = DNSServiceUpdateRecord_direct( ref->directObj, obj->directObj, flags, (uint16_t) rDataSize, rData, ttl );
+       require_noerr( err, exit );
+       
+exit:
+       if( err != kNoErr )
+       {
+               err = RMxSessionSendMessage( inMessage->session, inMessage->opcode, err, "" );
+               check_noerr( err );
+       }
+}
+
+//===========================================================================================================================
+//     DNSServiceRemoveRecord_server
+//===========================================================================================================================
+
+DEBUG_LOCAL void       DNSServiceRemoveRecord_server( RMxMessage *inMessage )
+{
+       OSStatus                        err;
+       DNSServiceRef           ref;
+       uint32_t                        id;
+       DNSServiceFlags         flags;
+       DNSRecordRef *          p;
+       DNSRecordRef            obj;
+       DNSRecordRef            directObj;
+       
+       check( inMessage );
+       check( inMessage->session );
+       ref = (DNSServiceRef) inMessage->context;
+       require_action( ref, exit, err = kNotInitializedErr );
+       require_action( ( ref->opcode == kRMxOpCodeRegister ) || ( ref->opcode == kRMxOpCodeCreateConnection ), exit, err = kTypeErr );
+       check( ref->directObj );
+       
+       // Extract parameters from the message.
+       
+       err = RMxUnpack( inMessage->recvData, inMessage->recvSize, "ww", &id, &flags );
+       require_noerr( err, exit );
+       
+       dlog( kDebugLevelTrace, DEBUG_NAME "%s: id=%d, flags=0x%08X\n", __ROUTINE__, id, flags );
+       
+       // Find the record with the specified ID, remove it from the list, and free it.
+       
+       for( p = &ref->records; *p; p = &( *p )->next )
+       {
+               if( ( *p )->id == id )
+               {
+                       break;
+               }
+       }
+       obj = *p;
+       require_action( obj, exit, err = kNotFoundErr );
+       *p = obj->next;
+       
+       directObj = obj->directObj;
+       check( directObj );
+       free( obj );
+       
+       err = DNSServiceRemoveRecord_direct( ref->directObj, directObj, flags );
+       require_noerr( err, exit );
+       
+exit:
+       if( err != kNoErr )
+       {
+               err = RMxSessionSendMessage( inMessage->session, inMessage->opcode, err, "" );
+               check_noerr( err );
+       }
+}
+
+#if 0
+#pragma mark -
+#pragma mark == DNS-SD Service Discovery ==
+#endif
+
+//===========================================================================================================================
+//     DNSServiceBrowse_server
+//===========================================================================================================================
+
+DEBUG_LOCAL void       DNSServiceBrowse_server( RMxMessage *inMessage )
+{
+       OSStatus                        err;
+       DNSServiceRef           obj;
+       DNSServiceFlags         flags;
+       uint32_t                        interfaceIndex;
+       const char *            type;
+       const char *            domain;
+       
+       obj = NULL;
+       check( inMessage );
+       check( inMessage->session );
+       require_action( !inMessage->session->message.context, exit, err = kTypeErr );
+       
+       // Extract parameters from the message.
+       
+       err = RMxUnpack( inMessage->recvData, inMessage->recvSize, "wwss", &flags, &interfaceIndex, &type, NULL, &domain, NULL );
+       require_noerr( err, exit );
+       
+       dlog( kDebugLevelTrace, DEBUG_NAME "%s: flags=0x%08X, ifi=%d, type=\"%s\", domain=\"%s\"\n", 
+               __ROUTINE__, flags, interfaceIndex, type, domain );
+       
+       // Allocate and initialize the object.
+       
+       obj = (DNSServiceRef) calloc( 1, sizeof( *obj ) );
+       require_action( obj, exit, err = kNoMemoryErr );
+       
+       obj->opcode  = inMessage->opcode;
+       obj->session = inMessage->session;
+       
+       err = DNSServiceBrowse_direct( &obj->directObj, flags, interfaceIndex, type, domain, DNSServiceBrowseCallBack_server, obj );
+       require_noerr( err, exit );
+       
+       // Success!
+       
+       inMessage->session->message.context = obj;
+       obj = NULL;
+       
+exit:
+       if( err != kNoErr )
+       {
+               err = RMxSessionSendMessage( inMessage->session, inMessage->opcode, err, "" );
+               check_noerr( err );
+       }
+       if( obj )
+       {
+               DNSServiceRefDeallocate_server( obj );
+       }
+}
+
+//===========================================================================================================================
+//     DNSServiceBrowseCallBack_server
+//===========================================================================================================================
+
+DEBUG_LOCAL void CALLBACK_COMPAT
+       DNSServiceBrowseCallBack_server(
+               DNSServiceRef           inRef,
+               DNSServiceFlags         inFlags,
+               uint32_t                        inInterfaceIndex,
+               DNSServiceErrorType     inErrorCode,
+               const char *            inName,  
+               const char *            inType,  
+               const char *            inDomain,  
+               void *                          inContext )
+{
+       DNSServiceRef           obj;
+       OSStatus                        err;
+       
+       DEBUG_UNUSED( inRef );
+       
+       check( inName );
+       check( inType );
+       check( inDomain );
+       obj = (DNSServiceRef) inContext;
+       check( obj );
+       check( obj->session );
+       
+       err = RMxSessionSendMessage( obj->session, kRMxOpCodeBrowse, kNoErr, "wwwsss", 
+               inFlags, inInterfaceIndex, inErrorCode, inName, inType, inDomain );
+       check_noerr( err );
+}
+
+#if 0
+#pragma mark -
+#endif
+
+//===========================================================================================================================
+//     DNSServiceResolve_server
+//===========================================================================================================================
+
+DEBUG_LOCAL void       DNSServiceResolve_server( RMxMessage *inMessage )
+{
+       OSStatus                        err;
+       DNSServiceRef           obj;
+       DNSServiceFlags         flags;
+       uint32_t                        interfaceIndex;
+       const char *            name;
+       const char *            type;
+       const char *            domain;
+       
+       obj = NULL;
+       check( inMessage );
+       check( inMessage->session );
+       require_action( !inMessage->session->message.context, exit, err = kTypeErr );
+       
+       // Extract parameters from the message.
+       
+       err = RMxUnpack( inMessage->recvData, inMessage->recvSize, "wwsss", 
+               &flags, &interfaceIndex, &name, NULL, &type, NULL, &domain, NULL );
+       require_noerr( err, exit );
+
+       dlog( kDebugLevelTrace, DEBUG_NAME "%s: flags=0x%08X, ifi=%d, name=\"%s\", type=\"%s\", domain=\"%s\"\n", 
+               __ROUTINE__, flags, interfaceIndex, name, type, domain );
+       
+       // Allocate and initialize the object.
+       
+       obj = (DNSServiceRef) calloc( 1, sizeof( *obj ) );
+       require_action( obj, exit, err = kNoMemoryErr );
+       
+       obj->opcode  = inMessage->opcode;
+       obj->session = inMessage->session;
+       
+       err = DNSServiceResolve_direct( &obj->directObj, flags, interfaceIndex, name, type, domain, 
+               DNSServiceResolveCallBack_server, obj );
+       require_noerr( err, exit );
+       
+       // Success!
+       
+       inMessage->session->message.context = obj;
+       obj = NULL;
+       
+exit:
+       if( err != kNoErr )
+       {
+               err = RMxSessionSendMessage( inMessage->session, inMessage->opcode, err, "" );
+               check_noerr( err );
+       }
+       if( obj )
+       {
+               DNSServiceRefDeallocate_server( obj );
+       }
+}
+
+//===========================================================================================================================
+//     DNSServiceResolveCallBack_server
+//===========================================================================================================================
+
+DEBUG_LOCAL void CALLBACK_COMPAT
+       DNSServiceResolveCallBack_server(
+               DNSServiceRef                   inRef,
+               DNSServiceFlags                 inFlags,
+               uint32_t                                inInterfaceIndex,
+               DNSServiceErrorType             inErrorCode,
+               const char *                    inFullName,  
+               const char *                    inHostName,  
+               uint16_t                                inPort, 
+               uint16_t                                inTXTSize, 
+               const char *                    inTXT, 
+               void *                                  inContext )
+{
+       DNSServiceRef           obj;
+       OSStatus                        err;
+       
+       DEBUG_UNUSED( inRef );
+       
+       check( inFullName );
+       check( inHostName );
+       obj = (DNSServiceRef) inContext;
+       dlog( kDebugLevelTrace, DEBUG_NAME "%s: ref=%#p, directRef=%#p\n", __ROUTINE__, obj, inRef );
+       check( obj );
+       check( obj->session );
+       
+       err = RMxSessionSendMessage( obj->session, kRMxOpCodeResolve, kNoErr, "wwwsshn", 
+               inFlags, inInterfaceIndex, inErrorCode, inFullName, inHostName, inPort, inTXTSize, inTXT );
+       check_noerr( err );
+}
+
+#if 0
+#pragma mark -
+#pragma mark == DNS-SD Special Purpose ==
+#endif
+
+//===========================================================================================================================
+//     DNSServiceCreateConnection_server
+//===========================================================================================================================
+
+DEBUG_LOCAL void       DNSServiceCreateConnection_server( RMxMessage *inMessage )
+{
+       OSStatus                        err;
+       DNSServiceRef           obj;
+       
+       obj = NULL;
+       check( inMessage );
+       check( inMessage->session );
+       require_action( !inMessage->session->message.context, exit, err = kTypeErr );
+       
+       dlog( kDebugLevelTrace, DEBUG_NAME "%s\n", __ROUTINE__ );
+       
+       // Allocate and initialize the object.
+       
+       obj = (DNSServiceRef) calloc( 1, sizeof( *obj ) );
+       require_action( obj, exit, err = kNoMemoryErr );
+       
+       obj->opcode  = inMessage->opcode;
+       obj->session = inMessage->session;
+       
+       err = DNSServiceCreateConnection_direct( &obj->directObj );
+       require_noerr( err, exit );
+       
+       // Success!
+       
+       inMessage->session->message.context = obj;
+       obj = NULL;
+       
+exit:
+       if( err != kNoErr )
+       {
+               err = RMxSessionSendMessage( inMessage->session, inMessage->opcode, err, "" );
+               check_noerr( err );
+       }
+       if( obj )
+       {
+               DNSServiceRefDeallocate_server( obj );
+       }
+}
+
+//===========================================================================================================================
+//     DNSServiceRegisterRecord_server
+//===========================================================================================================================
+
+DEBUG_LOCAL void       DNSServiceRegisterRecord_server( RMxMessage *inMessage )
+{
+       OSStatus                        err;
+       DNSRecordRef            obj;
+       DNSServiceRef           ref;
+       uint32_t                        id;
+       DNSServiceFlags         flags;
+       uint32_t                        interfaceIndex;
+       const char *            name;
+       uint16_t                        rrType;
+       uint16_t                        rrClass;
+       uint8_t *                       rData;
+       size_t                          rDataSize;
+       uint32_t                        ttl;
+       DNSRecordRef *          p;
+       
+       obj = NULL;
+       check( inMessage );
+       check( inMessage->session );
+       ref = (DNSServiceRef) inMessage->context;
+       require_action( ref, exit, err = kNotInitializedErr );
+       require_action( ref->opcode == kRMxOpCodeCreateConnection, exit, err = kTypeErr );
+       check( ref->directObj );
+       
+       // Extract parameters from the message.
+       
+       err = RMxUnpack( inMessage->recvData, inMessage->recvSize, "wwwshhnw", 
+               &id, &flags, &interfaceIndex, &name, NULL, &rrType, &rrClass, &rData, &rDataSize, &ttl );
+       require_noerr( err, exit );
+       
+       dlog( kDebugLevelTrace, DEBUG_NAME
+               "%s: id=%d, flags=0x%08X, ifi=%d, name=\"%s\", rrType=%d, rrClass=%d, rDataSize=%d, ttl=%d\n", 
+               __ROUTINE__, id, flags, interfaceIndex, name, rrType, rrClass, rDataSize, ttl );
+       
+       // Allocate and initialize the object and add it to the list of records.
+       
+       obj = (DNSRecordRef) calloc( 1, sizeof( *obj ) );
+       require_action( obj, exit, err = kNoMemoryErr );
+       
+       obj->id                 = id;
+       obj->owner              = ref;
+       
+       obj->next               = ref->records;
+       ref->records    = obj;
+       
+       err = DNSServiceRegisterRecord_direct( ref->directObj, &obj->directObj, flags, interfaceIndex, name, rrType, rrClass, 
+               (uint16_t) rDataSize, rData, ttl, DNSServiceRegisterRecordCallBack_server, obj );
+       require_noerr( err, exit );
+       
+       obj = NULL;
+       
+exit:
+       if( err != kNoErr )
+       {
+               err = RMxSessionSendMessage( inMessage->session, inMessage->opcode, err, "" );
+               check_noerr( err );
+       }
+       if( obj )
+       {
+               for( p = &ref->records; *p; p = &( *p )->next )
+               {
+                       if( *p == obj )
+                       {
+                               *p = obj->next;
+                               free( obj );
+                               break;
+                       }
+               }
+       }
+}
+
+//===========================================================================================================================
+//     DNSServiceRegisterRecordCallBack_server
+//===========================================================================================================================
+
+DEBUG_LOCAL void CALLBACK_COMPAT
+       DNSServiceRegisterRecordCallBack_server( 
+               DNSServiceRef           inRef,
+               DNSRecordRef            inRecordRef,
+               DNSServiceFlags         inFlags,
+               DNSServiceErrorType     inErrorCode,
+               void *                          inContext )
+{
+       DNSRecordRef            record;
+       DNSServiceRef           obj;
+       OSStatus                        err;
+       
+       DEBUG_UNUSED( inRef );
+       DEBUG_UNUSED( inRecordRef );
+       
+       record = (DNSRecordRef) inContext;
+       check( record );
+       obj = record->owner;
+       check( obj );
+       check( obj->session );
+       
+       err = RMxSessionSendMessage( obj->session, kRMxOpCodeRegisterRecord, kNoErr, "www", inFlags, inErrorCode, record->id );
+       check_noerr( err );
+}
+
+//===========================================================================================================================
+//     DNSServiceQueryRecord_server
+//===========================================================================================================================
+
+DEBUG_LOCAL void       DNSServiceQueryRecord_server( RMxMessage *inMessage )
+{
+       OSStatus                        err;
+       DNSServiceRef           obj;
+       DNSServiceFlags         flags;
+       uint32_t                        interfaceIndex;
+       const char *            name;
+       uint16_t                        rrType;
+       uint16_t                        rrClass;
+       
+       obj = NULL;
+       check( inMessage );
+       check( inMessage->session );
+       require_action( !inMessage->session->message.context, exit, err = kTypeErr );
+       
+       // Extract parameters from the message.
+       
+       err = RMxUnpack( inMessage->recvData, inMessage->recvSize, "wwshh", 
+               &flags, &interfaceIndex, &name, NULL, &rrType, &rrClass );
+       require_noerr( err, exit );
+
+       dlog( kDebugLevelTrace, DEBUG_NAME "%s: flags=0x%08X, ifi=%d, name=\"%s\", rrType=%d, rrClass=%d\n", 
+               __ROUTINE__, flags, interfaceIndex, name, rrType, rrClass );
+       
+       // Allocate and initialize the object.
+       
+       obj = (DNSServiceRef) calloc( 1, sizeof( *obj ) );
+       require_action( obj, exit, err = kNoMemoryErr );
+       
+       obj->opcode  = inMessage->opcode;
+       obj->session = inMessage->session;
+       
+       err = DNSServiceQueryRecord_direct( &obj->directObj, flags, interfaceIndex, name, rrType, rrClass, 
+               DNSServiceQueryRecordCallBack_server, obj );
+       require_noerr( err, exit );
+       
+       // Success!
+       
+       inMessage->session->message.context = obj;
+       obj = NULL;
+       
+exit:
+       if( err != kNoErr )
+       {
+               err = RMxSessionSendMessage( inMessage->session, inMessage->opcode, err, "" );
+               check_noerr( err );
+       }
+       if( obj )
+       {
+               DNSServiceRefDeallocate_server( obj );
+       }
+}
+
+//===========================================================================================================================
+//     DNSServiceQueryRecordCallBack_server
+//===========================================================================================================================
+
+DEBUG_LOCAL void CALLBACK_COMPAT
+       DNSServiceQueryRecordCallBack_server(
+               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 )
+{
+       DNSServiceRef           obj;
+       OSStatus                        err;
+       
+       DEBUG_UNUSED( inRef );
+               
+       obj = (DNSServiceRef) inContext;
+       check( obj );
+       check( obj->session );
+       
+       err = RMxSessionSendMessage( obj->session, kRMxOpCodeQueryRecord, kNoErr, "wwwshhnw", 
+               inFlags, inInterfaceIndex, inErrorCode, inName, inRRType, inRRClass, inRDataSize, inRData, inTTL );
+       check_noerr( err );
+}
+
+//===========================================================================================================================
+//     DNSServiceReconfirmRecord_server
+//===========================================================================================================================
+
+DEBUG_LOCAL void       DNSServiceReconfirmRecord_server( RMxMessage *inMessage )
+{
+       OSStatus                        err;
+       DNSServiceFlags         flags;
+       uint32_t                        interfaceIndex;
+       const char *            name;
+       uint16_t                        rrType;
+       uint16_t                        rrClass;
+       uint8_t *                       rData;
+       size_t                          rDataSize;
+       
+       check( inMessage );
+       check( inMessage->session );
+       require_action( !inMessage->session->message.context, exit, err = kTypeErr );
+       
+       // Extract parameters from the message.
+       
+       err = RMxUnpack( inMessage->recvData, inMessage->recvSize, "wwshhn", 
+               &flags, &interfaceIndex, &name, NULL, &rrType, &rrClass, &rData, &rDataSize );
+       require_noerr( err, exit );
+
+       dlog( kDebugLevelTrace, "\n" DEBUG_NAME "%s: flags=0x%08X, ifi=%d, name=\"%s\", rrType=%d, rrClass=%d, rDataSize=%d\n", 
+               __ROUTINE__, flags, interfaceIndex, name, rrType, rrClass, rDataSize );
+       
+       // Trigger the reconfirm then cause the session to quit.
+       
+       DNSServiceReconfirmRecord_direct( flags, interfaceIndex, name, rrType, rrClass, (uint16_t) rDataSize, rData );
+       require_noerr( err, exit );
+       
+exit:
+       inMessage->session->quit = true;
+       return;
+}
+
+#ifdef __cplusplus
+       }
+#endif
diff --git a/mDNSWindows/RMxServer.h b/mDNSWindows/RMxServer.h
new file mode 100644 (file)
index 0000000..4b0fb3a
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+
+$Log: RMxServer.h,v $
+Revision 1.1  2004/01/30 02:35:13  bradley
+Rendezvous Message Exchange implementation for DNS-SD IPC on Windows.
+
+*/
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @header         RMxServer.h
+       
+       @abstract       Server-side implementation of the DNS-SD IPC API.
+       
+       @discussion     
+       
+       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.
+*/
+
+#ifndef __RMx_SERVER__
+#define __RMx_SERVER__
+
+#ifdef __cplusplus
+       extern "C" {
+#endif
+
+#if 0
+#pragma mark == RMx ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @typedef        RMxServerFlags
+
+       @abstract       Flags to control how the server is stopped.
+       
+       @constant       kRMxServerFlagsNone                     No flags.
+       @constant       kRMxServerFlagsAllowRemote      Allow remote connections.
+*/
+
+typedef uint32_t               RMxServerFlags;
+
+#define        kRMxServerFlagsNone                             0
+#define        kRMxServerFlagsAllowRemote              ( 1 << 0 )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @typedef        RMxServerStopFlags
+
+       @abstract       Flags to control how the server is stopped.
+       
+       @constant       kRMxServerStopFlagsNone         No flags.
+       @constant       kRMxServerStopFlagNoWait        Do not wait for the server to stop (signal and return).
+*/
+
+typedef uint32_t               RMxServerStopFlags;
+
+#define        kRMxServerStopFlagsNone                 0
+#define        kRMxServerStopFlagsNoWait               ( 1 << 0 )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       RMxServerInitialize
+
+       @abstract       Initializes the RMx server.
+*/
+
+OSStatus       RMxServerInitialize( RMxServerFlags inFlags );
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       RMxServerFinalize
+
+       @abstract       Finalizes the RMx server.
+*/
+
+void           RMxServerFinalize( void );
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       RMxServerRun
+
+       @abstract       Runs the RMx server. Does not return unless stopped or an error occurs.
+*/
+
+OSStatus       RMxServerRun( void );
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @function       RMxServerStop
+
+       @abstract       Stops the RMx server.
+*/
+
+OSStatus       RMxServerStop( RMxServerStopFlags inFlags );
+
+#ifdef __cplusplus
+       }
+#endif
+
+#endif  // __RMx_SERVER__
index 709574f862dd390842887fc2ef1e61ad6601c151..b24527fa12d4bcf8df6f2f51567bc75ccb6f780d 100755 (executable)
@@ -1,8 +1,10 @@
 /*
- * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
     Change History (most recent first):
     
 $Log: mDNSWin32.c,v $
-Revision 1.22.2.1  2004/04/03 05:26:07  bradley
-Integrated changes from TOT to remove legacy port 53 support.
+Revision 1.40  2004/05/26 09:06:07  bradley
+Retry while building the interface list if it returns an error since the two-step process required to
+get the interface list could allow a subsequent interface change to come in that window and change the
+needed size after getting the size, but before getting the list, causing it to return an error.
+Fixed structure name typo in search domain list stuff. Fixed spelling error in global for GAA.
+
+Revision 1.39  2004/05/18 23:51:27  cheshire
+Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
+
+Revision 1.38  2004/05/13 04:57:48  ksekar
+Removed unnecessary FreeSearchList function
+
+Revision 1.37  2004/05/13 04:54:20  ksekar
+Unified list copy/free code.  Added symetric list for
+
+Revision 1.36  2004/05/12 22:03:09  ksekar
+Made GetSearchDomainList a true platform-layer call (declaration moved
+from mDNSMacOSX.h to mDNSClientAPI.h), impelemted to return "local"
+only on non-OSX platforms.  Changed call to return a copy of the list
+to avoid shared memory issues.  Added a routine to free the list.
+
+Revision 1.35  2004/04/21 02:49:12  cheshire
+To reduce future confusion, renamed 'TxAndRx' to 'McastTxRx'
+
+Revision 1.34  2004/04/15 01:00:05  bradley
+Removed support for automatically querying for A/AAAA records when resolving names. Platforms
+without .local name resolving support will need to manually query for A/AAAA records as needed.
+
+Revision 1.33  2004/04/14 23:09:29  ksekar
+Support for TSIG signed dynamic updates.
+
+Revision 1.32  2004/04/09 17:40:26  cheshire
+Remove unnecessary "Multicast" field -- it duplicates the semantics of the existing McastTxRx field
+
+Revision 1.31  2004/04/09 00:40:46  bradley
+Re-enable IPv6 support, AAAA records over IPv4, and IPv4 routable IPv6 exclusion support.
+
+Revision 1.30  2004/04/09 00:33:58  bradley
+Turn on Multicast flag for interfaces to tell mDNSCore that the interfaces are multicast capable.
+
+Revision 1.29  2004/03/15 02:07:46  bradley
+Changed interface index handling to use the upper 24 bits for IPv4 and the lower 8 bits for IPv6 to
+handle some IPv4 interface indexes that are greater than 16-bit. This is not perfect because Windows
+does not provide a consistent index for IPv4 and IPv6, but it seems to handle the known cases.
+
+Revision 1.28  2004/03/07 00:26:39  bradley
+Allow non-NULL PlatformSupport ptr when initializing so non-Apple clients can provide their own storage.
+Added count assert when building the wait list to catch underruns/overruns if the code is changed.
+
+Revision 1.27  2004/01/30 02:44:32  bradley
+Added support for IPv6 (v4 & v6, v4-only, v6-only, AAAA over v4, etc.). Added support for DNS-SD
+InterfaceID<->Interface Index mappings. Added support for loopback usage when no other interfaces
+are available. Updated unlock signaling to no longer require timenow - NextScheduledTime to be >= 0
+(it no longer is). Added unicast-capable detection to avoid using unicast when there is other mDNS
+software running on the same machine. Removed unneeded sock_XtoY routines. Added support for
+reporting HINFO records with the  Windows and mDNSResponder version information.
+
+Revision 1.26  2004/01/24 04:59:16  cheshire
+Fixes so that Posix/Linux, OS9, Windows, and VxWorks targets build again
+
+Revision 1.25  2003/11/14 20:59:09  cheshire
+Clients can't use AssignDomainName macro because mDNSPlatformMemCopy is defined in mDNSPlatformFunctions.h.
+Best solution is just to combine mDNSClientAPI.h and mDNSPlatformFunctions.h into a single file.
 
 Revision 1.24  2003/10/24 23:23:02  bradley
 Removed legacy port 53 support as it is no longer needed.
@@ -95,7 +158,7 @@ Revision 1.7  2003/03/15 04:40:38  cheshire
 Change type called "mDNSOpaqueID" to the more descriptive name "mDNSInterfaceID"
 
 Revision 1.6  2003/02/21 01:54:10  cheshire
-Bug #: 3099194 mDNSResponder needs performance improvements
+<rdar://problem/3099194> mDNSResponder needs performance improvements
 Switched to using new "mDNS_Execute" model (see "Implementer Notes.txt")
 
 Revision 1.5  2003/02/20 00:59:03  cheshire
@@ -109,36 +172,30 @@ Added APSL info
 Revision 1.3  2002/09/20 05:50:45  bradley
 Multicast DNS platform plugin for Win32
 
+       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). 
 */
 
-#if( defined( _MSC_VER ) )
-       #pragma warning( disable:4127 )         // Disable "conditional expression is constant" warning for debug macros.
-#endif
-
-#if( !defined( WIN32_LEAN_AND_MEAN ) )
-       #define WIN32_LEAN_AND_MEAN                     // Needed to avoid redefinitions by Windows interfaces.
-#endif
-
 #include       <stdarg.h>
 #include       <stddef.h>
 #include       <stdio.h>
 #include       <stdlib.h>
 #include       <string.h>
 
-#include       <windows.h>
-#include       <winsock2.h>
-#include       <Ws2tcpip.h>
+#include       "CommonServices.h"
+#include       "DebugServices.h"
 
-#if( !defined( _WIN32_WCE ) )                  // Windows CE does not have process.h.
+#include       <Iphlpapi.h>
+#if( !TARGET_OS_WINDOWS_CE )
+       #include        <mswsock.h>
        #include        <process.h>
 #endif
 
-#if( DEBUG )
-       #define mDNSlocal
-#endif
-
 #include       "mDNSClientAPI.h"
-#include       "mDNSPlatformFunctions.h"
 
 #include       "mDNSWin32.h"
 
@@ -150,213 +207,26 @@ Multicast DNS platform plugin for Win32
 //     Constants
 //===========================================================================================================================
 
-#define        DEBUG_NAME                                                              "[mDNS] "
-
-#if( !defined( MDNS_DEBUG_SIGNATURE ) )
-       #define MDNS_DEBUG_SIGNATURE                            "mDNS"
-#endif
-
-#define        kMDNSDefaultName                                                "My Computer"
-
-#define        kWinSockMajorMin                                                2
-#define        kWinSockMinorMin                                                2
-
-#define        kWaitListCancelEvent                                    ( WAIT_OBJECT_0 + 0 )
-#define        kWaitListInterfaceListChangedEvent              ( WAIT_OBJECT_0 + 1 )
-#define        kWaitListWakeupEvent                                    ( WAIT_OBJECT_0 + 2 )
-#define        kWaitListFixedItemCount                                 3
-
-#if 0
-#pragma mark == Macros - Debug ==
-#endif
-
-//===========================================================================================================================
-//     Macros - Debug
-//===========================================================================================================================
-
-#define MDNS_UNUSED( X )               (void)( X )
-
-#define kDebugLevelMask                                0x0000FFFFL
-#define kDebugLevelChatty                      100L
-#define kDebugLevelVerbose                     500L
-#define kDebugLevelTrace                       800L
-#define kDebugLevelInfo                        1000L
-#define kDebugLevelRareInfo                    2000L
-#define kDebugLevelNotice                      3000L
-#define kDebugLevelWarning                     4000L
-#define kDebugLevelAllowedError                5000L
-#define kDebugLevelAssert                      6000L
-#define kDebugLevelRequire                     7000L
-#define kDebugLevelError                       8000L
-#define kDebugLevelCritical                    9000L
-#define kDebugLevelCriticalError       kDebugLevelCritical             // DEPRECATED
-#define kDebugLevelAlert                       10000L
-#define kDebugLevelEmergency           11000L
-#define kDebugLevelTragic                      12000L
-#define kDebugLevelAny                         0x0000FFFFL
-
-#if( defined( __MWERKS__ ) || defined( __GNUC__ ) )
-       #define __ROUTINE__             __FUNCTION__
-#else
-       // Apple and Symantec compilers don't support the C99/GCC extensions yet.
-       
-       #define __ROUTINE__             NULL
-#endif
-
-#if( MDNS_DEBUGMSGS )
-       #define debug_print_assert( ASSERT_STRING, FILENAME, LINE_NUMBER, FUNCTION )                                                                            \
-               mDNSPlatformPrintAssert( MDNS_DEBUG_SIGNATURE, 0, ( ASSERT_STRING ), NULL, ( FILENAME ), ( LINE_NUMBER ), ( FUNCTION ) )
-       
-       #define debug_print_assert_err( ERR, ASSERT_STRING, ERROR_STRING, FILENAME, LINE_NUMBER, FUNCTION )                                     \
-               mDNSPlatformPrintAssert( MDNS_DEBUG_SIGNATURE, ( ERR ), ( ASSERT_STRING ), ( ERROR_STRING ),                                                    \
-                                                 ( FILENAME ), ( LINE_NUMBER ), ( FUNCTION ) )
-       
-       #define dlog            mDNSPlatformDebugLog
-#else
-       #define debug_print_assert( ASSERT_STRING, FILENAME, LINE_NUMBER, FUNCTION )
-       
-       #define debug_print_assert_err( ERR, ASSERT_STRING, ERROR_STRING, FILENAME, LINE_NUMBER, FUNCTION )
-
-       #define dlog            while( 0 )
-#endif
-
-///
-/// The following debugging macros emulate those available on Mac OS in AssertMacros.h/Debugging.h.
-/// 
-
-// checks
-
-#define        check( X )                                                                                                                                                                                                              \
-       do {                                                                                                                                                                                                                            \
-               if( !( X ) ) {                                                                                                                                                                                                  \
-                       debug_print_assert( #X, __FILE__, __LINE__, __ROUTINE__ );                                                                                                      \
-               }                                                                                                                                                                                                                               \
-       } while( 0 )
-
-#define        check_noerr( ERR )                                                                                                                                                                                              \
-       do {                                                                                                                                                                                                                            \
-               if( ( ERR ) != 0 ) {                                                                                                                                                                                    \
-                       debug_print_assert_err( ( ERR ), #ERR, NULL, __FILE__, __LINE__, __ROUTINE__ );                                                         \
-               }                                                                                                                                                                                                                               \
-       } while( 0 )
-
-#define        check_errno( ERR, ERRNO )                                                                                                                                                                               \
-       do {                                                                                                                                                                                                                            \
-               int             localErr;                                                                                                                                                                                               \
-                                                                                                                                                                                                                                               \
-               localErr = (int)( ERR );                                                                                                                                                                                \
-               if( localErr < 0 ) {                                                                                                                                                                                    \
-                       int             localErrno;                                                                                                                                                                                     \
-                                                                                                                                                                                                                                               \
-                       localErrno = ( ERRNO );                                                                                                                                                                         \
-                       localErr = ( localErrno != 0 ) ? localErrno : localErr;                                                                                                         \
-                       debug_print_assert_err( localErr, #ERR, NULL, __FILE__, __LINE__, __ROUTINE__ );                                                        \
-               }                                                                                                                                                                                                                               \
-       } while( 0 )
-
-// requires
-
-#define        require( X, LABEL )                                                                                                                                                                                             \
-       do {                                                                                                                                                                                                                            \
-               if( !( X ) ) {                                                                                                                                                                                                  \
-                       debug_print_assert( #X, __FILE__, __LINE__, __ROUTINE__ );                                                                                                      \
-                       goto LABEL;                                                                                                                                                                                                     \
-               }                                                                                                                                                                                                                               \
-       } while( 0 )
-
-#define        require_quiet( X, LABEL )                                                                                                                                                                               \
-       do {                                                                                                                                                                                                                            \
-               if( !( X ) ) {                                                                                                                                                                                                  \
-                       goto LABEL;                                                                                                                                                                                                     \
-               }                                                                                                                                                                                                                               \
-       } while( 0 )
-
-#define        require_action( X, LABEL, ACTION )                                                                                                                                                              \
-       do {                                                                                                                                                                                                                            \
-               if( !( X ) ) {                                                                                                                                                                                                  \
-                       debug_print_assert( #X, __FILE__, __LINE__, __ROUTINE__ );                                                                                                      \
-                       { ACTION; }                                                                                                                                                                                                     \
-                       goto LABEL;                                                                                                                                                                                                     \
-               }                                                                                                                                                                                                                               \
-       } while( 0 )
-
-#define        require_action_quiet( X, LABEL, ACTION )                                                                                                                                                \
-       do {                                                                                                                                                                                                                            \
-               if( !( X ) ) {                                                                                                                                                                                                  \
-                       { ACTION; }                                                                                                                                                                                                     \
-                       goto LABEL;                                                                                                                                                                                                     \
-               }                                                                                                                                                                                                                               \
-       } while( 0 )
-
-#define        require_noerr( ERR, LABEL )                                                                                                                                                                             \
-       do {                                                                                                                                                                                                                            \
-               if( ( ERR ) != 0 ) {                                                                                                                                                                                    \
-                       debug_print_assert_err( ( ERR ), #ERR, NULL, __FILE__, __LINE__, __ROUTINE__ );                                                         \
-                       goto LABEL;                                                                                                                                                                                                     \
-               }                                                                                                                                                                                                                               \
-       } while( 0 )
-
-#define        require_noerr_quiet( ERR, LABEL )                                                                                                                                                               \
-       do {                                                                                                                                                                                                                            \
-               if( ( ERR ) != 0 ) {                                                                                                                                                                                    \
-                       goto LABEL;                                                                                                                                                                                                     \
-               }                                                                                                                                                                                                                               \
-       } while( 0 )
-
-#define        require_errno( ERR, ERRNO, LABEL )                                                                                                                                                              \
-       do {                                                                                                                                                                                                                            \
-               int             localErr;                                                                                                                                                                                               \
-                                                                                                                                                                                                                                               \
-               localErr = (int)( ERR );                                                                                                                                                                                \
-               if( localErr < 0 ) {                                                                                                                                                                                    \
-                       int             localErrno;                                                                                                                                                                                     \
-                                                                                                                                                                                                                                               \
-                       localErrno = ( ERRNO );                                                                                                                                                                         \
-                       localErr = ( localErrno != 0 ) ? localErrno : localErr;                                                                                                         \
-                       debug_print_assert_err( localErr, #ERR, NULL, __FILE__, __LINE__, __ROUTINE__ );                                                        \
-                       goto LABEL;                                                                                                                                                                                                     \
-               }                                                                                                                                                                                                                               \
-       } while( 0 )
-
-#define        require_errno_action( ERR, ERRNO, LABEL, ACTION )                                                                                                                               \
-       do {                                                                                                                                                                                                                            \
-               int             localErr;                                                                                                                                                                                               \
-                                                                                                                                                                                                                                               \
-               localErr = (int)( ERR );                                                                                                                                                                                \
-               if( localErr < 0 ) {                                                                                                                                                                                    \
-                       int             localErrno;                                                                                                                                                                                     \
-                                                                                                                                                                                                                                               \
-                       localErrno = ( ERRNO );                                                                                                                                                                         \
-                       localErr = ( localErrno != 0 ) ? localErrno : localErr;                                                                                                         \
-                       debug_print_assert_err( localErr, #ERR, NULL, __FILE__, __LINE__, __ROUTINE__ );                                                        \
-                       { ACTION; }                                                                                                                                                                                                     \
-                       goto LABEL;                                                                                                                                                                                                     \
-               }                                                                                                                                                                                                                               \
-       } while( 0 )
+#define        DEBUG_NAME                                                                      "[mDNSWin32] "
 
-#if 0
-#pragma mark == Macros - General ==
-#endif
+#define        MDNS_WINDOWS_USE_IPV6_IF_ADDRS                          1
+#define        MDNS_WINDOWS_ENABLE_IPV4                                        1
+#define        MDNS_WINDOWS_ENABLE_IPV6                                        1
+#define        MDNS_WINDOWS_EXCLUDE_IPV4_ROUTABLE_IPV6         1
+#define        MDNS_WINDOWS_AAAA_OVER_IPV4                                     1
 
-//===========================================================================================================================
-//     Macros - General
-//===========================================================================================================================
+#define        kMDNSDefaultName                                                        "My Computer"
 
-#define        kInvalidSocketRef               INVALID_SOCKET
-#define        IsValidSocket( X )              ( ( X ) != INVALID_SOCKET )
-#define        close_compat( X )               closesocket( X )
-#define        errno_compat()                  WSAGetLastError()
+#define        kWinSockMajorMin                                                        2
+#define        kWinSockMinorMin                                                        2
 
-// _beginthreadex and _endthreadex are not supported on Windows CE 2.1 or later (the C runtime issues with leaking 
-// resources have apparently been resolved and they seem to have just ripped out support for the API) so map it to 
-// CreateThread on Windows CE.
+#define        kWaitListCancelEvent                                            ( WAIT_OBJECT_0 + 0 )
+#define        kWaitListInterfaceListChangedEvent                      ( WAIT_OBJECT_0 + 1 )
+#define        kWaitListWakeupEvent                                            ( WAIT_OBJECT_0 + 2 )
+#define        kWaitListFixedItemCount                                         3
 
-#if( defined( _WIN32_WCE ) )
-       #define _beginthreadex( SECURITY_PTR, STACK_SIZE, START_ADDRESS, ARG_LIST, FLAGS, THREAD_ID_PTR )               \
-               CreateThread( SECURITY_PTR, STACK_SIZE, (LPTHREAD_START_ROUTINE) START_ADDRESS, ARG_LIST, FLAGS,        \
-                                         (LPDWORD) THREAD_ID_PTR )
-       
-       #define _endthreadex( RESULT )
+#if( !TARGET_OS_WINDOWS_CE )
+       static GUID                                                                             kWSARecvMsgGUID = WSAID_WSARECVMSG;
 #endif
 
 #if 0
@@ -367,29 +237,15 @@ Multicast DNS platform plugin for Win32
 //     Prototypes
 //===========================================================================================================================
 
-#if( MDNS_DEBUGMSGS )
-       mDNSlocal void                  mDNSPlatformDebugLog( unsigned long inLevel, const char *inFormat, ... );
-       mDNSlocal void
-               mDNSPlatformPrintAssert( 
-                       const char *            inSignature, 
-                       long                            inError, 
-                       const char *            inAssertionString, 
-                       const char *            inErrorString, 
-                       const char *            inFileName, 
-                       unsigned long           inLineNumber, 
-                       const char *            inFunction );
-#endif
-
 mDNSlocal mStatus                      SetupSynchronizationObjects( mDNS * const inMDNS );
 mDNSlocal mStatus                      TearDownSynchronizationObjects( mDNS * const inMDNS );
 mDNSlocal mStatus                      SetupName( mDNS * const inMDNS );
 mDNSlocal mStatus                      SetupInterfaceList( mDNS * const inMDNS );
 mDNSlocal mStatus                      TearDownInterfaceList( mDNS * const inMDNS );
-mDNSlocal mStatus                      SetupInterface( mDNS * const inMDNS, const struct sockaddr_in *inAddress, mDNSInterfaceData **outIFD );
+mDNSlocal mStatus                      SetupInterface( mDNS * const inMDNS, const struct ifaddrs *inIFA, mDNSInterfaceData **outIFD );
 mDNSlocal mStatus                      TearDownInterface( mDNS * const inMDNS, mDNSInterfaceData *inIFD );
-mDNSlocal mStatus                      SetupSocket( mDNS * const                               inMDNS, 
-                                                                                const struct sockaddr_in *     inAddress, 
-                                                                                SocketRef *                            outSocketRef  );
+mDNSlocal mStatus                      SetupSocket( mDNS * const inMDNS, const struct sockaddr *inAddr, SocketRef *outSocketRef  );
+mDNSlocal mStatus                      SockAddrToMDNSAddr( const struct sockaddr * const inSA, mDNSAddr *outIP, mDNSIPPort *outPort );
 mDNSlocal mStatus                      SetupNotifications( mDNS * const inMDNS );
 mDNSlocal mStatus                      TearDownNotifications( mDNS * const inMDNS );
 
@@ -398,7 +254,7 @@ mDNSlocal mStatus                   TearDownThread( const mDNS * const inMDNS );
 mDNSlocal unsigned WINAPI      ProcessingThread( LPVOID inParam );
 mDNSlocal mStatus                      ProcessingThreadInitialize( mDNS * const inMDNS );
 mDNSlocal mStatus                      ProcessingThreadSetupWaitList( mDNS * const inMDNS, HANDLE **outWaitList, int *outWaitListCount );
-mDNSlocal void                         ProcessingThreadProcessPacket( mDNS *inMDNS, mDNSInterfaceData *inIFD, SocketRef inSocketRef );
+mDNSlocal void                         ProcessingThreadProcessPacket( mDNS *inMDNS, mDNSInterfaceData *inIFD, SocketRef inSock );
 mDNSlocal void                         ProcessingThreadInterfaceListChanged( mDNS *inMDNS );
 
 // Platform Accessors
@@ -417,6 +273,23 @@ struct     mDNSPlatformInterfaceInfo
 mDNSexport mStatus     mDNSPlatformInterfaceNameToID( mDNS * const inMDNS, const char *inName, mDNSInterfaceID *outID );
 mDNSexport mStatus     mDNSPlatformInterfaceIDToInfo( mDNS * const inMDNS, mDNSInterfaceID inID, mDNSPlatformInterfaceInfo *outInfo );
 
+// Utilities
+
+#if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
+       mDNSlocal int   getifaddrs_ipv6( struct ifaddrs **outAddrs );
+#endif
+
+#if( !TARGET_OS_WINDOWS_CE )
+       mDNSlocal int   getifaddrs_ipv4( struct ifaddrs **outAddrs );
+#endif
+
+#if( TARGET_OS_WINDOWS_CE )
+       mDNSlocal int   getifaddrs_ce( struct ifaddrs **outAddrs );
+#endif
+
+mDNSlocal mDNSBool     CanReceiveUnicast( void );
+mDNSlocal OSStatus     GetWindowsVersionString(  char *inBuffer, size_t inBufferSize );
+
 #ifdef __cplusplus
        }
 #endif
@@ -432,13 +305,24 @@ mDNSexport mStatus        mDNSPlatformInterfaceIDToInfo( mDNS * const inMDNS, mDNSInter
 mDNSlocal mDNS_PlatformSupport         gMDNSPlatformSupport;
 mDNSs32                                                                mDNSPlatformOneSecond = 0;
 
-#if( MDNS_DEBUGMSGS )
-       mDNSlocal unsigned long                 gDebugLevel = kDebugLevelInfo + 1;
+#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
 
 #if 0
 #pragma mark -
-#pragma mark == Platform Support APIs ==
+#pragma mark == Platform Support ==
 #endif
 
 //===========================================================================================================================
@@ -451,23 +335,40 @@ mStatus   mDNSPlatformInit( mDNS * const inMDNS )
        WSADATA         wsaData;
        int                     supported;
        
-       dlog( kDebugLevelVerbose, DEBUG_NAME "platform init\n" );
+       dlog( kDebugLevelTrace, DEBUG_NAME "platform init\n" );
        
-       // Initialize variables.
+       // Initialize variables. If the PlatformSupport pointer is not null then just assume that a non-Apple client is 
+       // calling mDNS_Init and wants to provide its own storage for the platform-specific data so do not overwrite it.
        
        memset( &gMDNSPlatformSupport, 0, sizeof( gMDNSPlatformSupport ) );
-       inMDNS->p                                                                       = &gMDNSPlatformSupport;
-       inMDNS->p->interfaceListChangedSocketRef        = kInvalidSocketRef;
-       mDNSPlatformOneSecond                                           = 1000;         // Use milliseconds as the quantum of time.
+       if( !inMDNS->p ) inMDNS->p                              = &gMDNSPlatformSupport;
+       inMDNS->p->interfaceListChangedSocket   = kInvalidSocketRef;
+       mDNSPlatformOneSecond                                   = 1000;         // Use milliseconds as the quantum of time
        
-       // Set everything up.
+       // 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->CanReceiveUnicast = CanReceiveUnicast();
+       
+       // Setup the HINFO HW/SW strings.
+       
+       err = GetWindowsVersionString( (char *) &inMDNS->HIHardware.c[ 1 ], sizeof( inMDNS->HIHardware.c ) - 2 );
+       check_noerr( err );
+       inMDNS->HIHardware.c[ 0 ] = (mDNSu8) mDNSPlatformStrLen( &inMDNS->HIHardware.c[ 1 ] );
+       dlog( kDebugLevelInfo, DEBUG_NAME "HIHardware: %#s\n", inMDNS->HIHardware.c );
+       
+       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 );
+       
+       // Set up the mDNS thread.
+       
        err = SetupSynchronizationObjects( inMDNS );
        require_noerr( err, exit );
        
@@ -483,7 +384,7 @@ exit:
        {
                mDNSPlatformClose( inMDNS );
        }
-       dlog( kDebugLevelVerbose, DEBUG_NAME "platform init done (err=%ld)\n", err );
+       dlog( kDebugLevelTrace, DEBUG_NAME "platform init done (err=%d %m)\n", err, err );
        return( err );
 }
 
@@ -495,7 +396,7 @@ void        mDNSPlatformClose( mDNS * const inMDNS )
 {
        mStatus         err;
        
-       dlog( kDebugLevelVerbose, DEBUG_NAME "platform close\n" );
+       dlog( kDebugLevelTrace, DEBUG_NAME "platform close\n" );
        check( inMDNS );
        
        // Tear everything down in reverse order to how it was set up.
@@ -508,10 +409,22 @@ void      mDNSPlatformClose( mDNS * const inMDNS )
                
        err = TearDownSynchronizationObjects( inMDNS );
        check_noerr( err );
+
+       // Free the DLL needed for IPv6 support.
        
+#if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
+       if( gIPHelperLibraryInstance )
+       {
+               gGetAdaptersAddressesFunctionPtr = NULL;
+               
+               FreeLibrary( gIPHelperLibraryInstance );
+               gIPHelperLibraryInstance = NULL;
+       }
+#endif
+
        WSACleanup();
        
-       dlog( kDebugLevelVerbose, DEBUG_NAME "platform close done (err=%ld)\n", err );
+       dlog( kDebugLevelTrace, DEBUG_NAME "platform close done\n" );
 }
 
 //===========================================================================================================================
@@ -524,51 +437,62 @@ mStatus
                const DNSMessage * const        inMsg, 
                const mDNSu8 * const            inMsgEnd, 
                mDNSInterfaceID                         inInterfaceID, 
-               mDNSIPPort                                      inSrcPort, 
                const mDNSAddr *                        inDstIP, 
                mDNSIPPort                                      inDstPort )
 {
-       mStatus                                 err;
-       mDNSInterfaceData *             ifd;
-       struct sockaddr_in              addr;
-       int                                             n;
-       
-       MDNS_UNUSED( inSrcPort );
-       dlog( kDebugLevelChatty, DEBUG_NAME "platform send UDP\n" );
+       mStatus                                         err;
+       mDNSInterfaceData *                     ifd;
+       struct sockaddr_storage         addr;
+       int                                                     n;
        
-       // Check parameters.
+       DEBUG_USE_ONLY( inMDNS );
        
+       n = (int)( inMsgEnd - ( (const mDNSu8 * const) inMsg ) );
        check( inMDNS );
        check( inMsg );
        check( inMsgEnd );
        check( inInterfaceID );
        check( inDstIP );
-       if( inDstIP->type != mDNSAddrType_IPv4 )
+       
+       ifd = (mDNSInterfaceData *) inInterfaceID;
+       require_action_quiet( ifd->interfaceInfo.McastTxRx, exit, err = mStatus_Invalid );                                      // Silent Interface
+       require_action_quiet( inDstIP->type == ifd->interfaceInfo.ip.type, exit, err = mStatus_NoError );       // Wrong Type
+       check( IsValidSocket( ifd->sock ) );
+       
+       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;
+       }
+       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.
+       }
+       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;
        }
        
-       // Send the packet.
-       
-       ifd = (mDNSInterfaceData *) inInterfaceID;
-       check( IsValidSocket( ifd->sock ) );
-       
-       addr.sin_family                 = AF_INET;
-       addr.sin_port                   = inDstPort.NotAnInteger;
-       addr.sin_addr.s_addr    = inDstIP->ip.v4.NotAnInteger;
-
-       n = (int)( inMsgEnd - ( (const mDNSu8 * const) inMsg ) );
        n = sendto( ifd->sock, (char *) inMsg, n, 0, (struct sockaddr *) &addr, sizeof( addr ) );
-       check_errno( n, errno_compat() );
+       err = translate_errno( n > 0, errno_compat(), kWriteErr );
+       require_noerr( err, exit );
        
-       ifd->sendErrorCounter           += ( n < 0 );
-       ifd->sendMulticastCounter       += ( inDstPort.NotAnInteger == MulticastDNSPort.NotAnInteger );
-       ifd->sendUnicastCounter         += ( inDstPort.NotAnInteger != MulticastDNSPort.NotAnInteger );
-       err = mStatus_NoError;
-
 exit:
-       dlog( kDebugLevelChatty, DEBUG_NAME "platform send UDP done\n" );
        return( err );
 }
 
@@ -578,6 +502,9 @@ exit:
 
 void   mDNSPlatformLock( const mDNS * const inMDNS )
 {
+       check( inMDNS );
+       check( inMDNS->p->lockInitialized );
+       
        EnterCriticalSection( &inMDNS->p->lock );
 }
 
@@ -600,32 +527,32 @@ void      mDNSPlatformUnlock( const mDNS * const inMDNS )
                BOOL            wasSet;
                
                wasSet = SetEvent( inMDNS->p->wakeupEvent );
-               check( wasSet );
+               check_translated_errno( wasSet, GetLastError(), kUnknownErr );
        }
        LeaveCriticalSection( &inMDNS->p->lock );
 }
 
 //===========================================================================================================================
-//     mDNSPlatformStrLen
+//     mDNSPlatformStrCopy
 //===========================================================================================================================
 
-mDNSu32        mDNSPlatformStrLen( const void *inSrc )
+void   mDNSPlatformStrCopy( const void *inSrc, void *inDst )
 {
        check( inSrc );
+       check( inDst );
        
-       return( (mDNSu32) strlen( (const char *) inSrc ) );
+       strcpy( (char *) inDst, (const char*) inSrc );
 }
 
 //===========================================================================================================================
-//     mDNSPlatformStrCopy
+//     mDNSPlatformStrLen
 //===========================================================================================================================
 
-void   mDNSPlatformStrCopy( const void *inSrc, void *inDst )
+mDNSu32        mDNSPlatformStrLen( const void *inSrc )
 {
        check( inSrc );
-       check( inDst );
        
-       strcpy( (char *) inDst, (const char*) inSrc );
+       return( (mDNSu32) strlen( (const char *) inSrc ) );
 }
 
 //===========================================================================================================================
@@ -713,6 +640,15 @@ mDNSs32    mDNSPlatformTimeNow( void )
        return( (mDNSs32) GetTickCount() );
 }
 
+//===========================================================================================================================
+//     mDNSPlatformUTC
+//===========================================================================================================================
+
+mDNSexport mDNSs32     mDNSPlatformUTC( void )
+{
+       return( -1 );
+}
+
 //===========================================================================================================================
 //     mDNSPlatformInterfaceNameToID
 //===========================================================================================================================
@@ -776,13 +712,153 @@ mStatus  mDNSPlatformInterfaceIDToInfo( mDNS * const inMDNS, mDNSInterfaceID inID
        // Success!
        
        outInfo->name   = ifd->name;
-       outInfo->ip     = ifd->hostSet.ip;
+       outInfo->ip     = ifd->interfaceInfo.ip;
        err                     = mStatus_NoError;
        
 exit:
        return( err );
 }
 
+//===========================================================================================================================
+//     mDNSPlatformInterfaceIDfromInterfaceIndex
+//===========================================================================================================================
+
+mDNSInterfaceID        mDNSPlatformInterfaceIDfromInterfaceIndex( const mDNS * const inMDNS, mDNSu32 inIndex )
+{
+       mDNSInterfaceID         id;
+       
+       id = mDNSNULL;
+       if( inIndex == (mDNSu32) ~0 )
+       {
+               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
+//===========================================================================================================================
+       
+mDNSu32        mDNSPlatformInterfaceIndexfromInterfaceID( const mDNS * const inMDNS, mDNSInterfaceID inID )
+{
+       mDNSu32         index;
+       
+       index = 0;
+       if( inID == mDNSInterface_LocalOnly )
+       {
+               index = (mDNSu32) ~0;
+       }
+       else if( inID )
+       {
+               mDNSInterfaceData *             ifd;
+               
+               for( ifd = inMDNS->p->interfaceList; ifd; ifd = ifd->next )
+               {
+                       if( (mDNSInterfaceID) ifd == inID )
+                       {
+                               index = ifd->scopeID;
+                               break;
+                       }
+               }
+               check( ifd );
+       }
+       return( index );
+}
+
+//===========================================================================================================================
+//     mDNSPlatformTCPConnect
+//===========================================================================================================================
+
+mStatus
+       mDNSPlatformTCPConnect( 
+               const mDNSAddr *                inDstIP, 
+               mDNSOpaque16                    inDstPort, 
+               mDNSInterfaceID                 inInterfaceID,
+               TCPConnectionCallback   inCallback, 
+               void *                                  inContext, 
+               int *                                   outSock )
+{
+       DEBUG_UNUSED( inDstIP );
+       DEBUG_UNUSED( inDstPort );
+       DEBUG_UNUSED( inInterfaceID );
+       DEBUG_UNUSED( inCallback );
+       DEBUG_UNUSED( inContext );
+       DEBUG_UNUSED( outSock );
+       
+       return( mStatus_UnsupportedErr );
+}
+
+//===========================================================================================================================
+//     mDNSPlatformTCPCloseConnection
+//===========================================================================================================================
+
+void   mDNSPlatformTCPCloseConnection( int inSock )
+{
+       DEBUG_UNUSED( inSock );
+}
+
+//===========================================================================================================================
+//     mDNSPlatformReadTCP
+//===========================================================================================================================
+
+int    mDNSPlatformReadTCP( int inSock, void *inBuffer, int inBufferSize )
+{
+       DEBUG_UNUSED( inSock );
+       DEBUG_UNUSED( inBuffer );
+       DEBUG_UNUSED( inBufferSize );
+       
+       return( -1 );
+}
+
+//===========================================================================================================================
+//     mDNSPlatformWriteTCP
+//===========================================================================================================================
+
+int    mDNSPlatformWriteTCP( int inSock, const char *inMsg, int inMsgSize )
+{
+       DEBUG_UNUSED( inSock );
+       DEBUG_UNUSED( inMsg );
+       DEBUG_UNUSED( inMsgSize );
+       
+       return( -1 );
+}
+
+
+//===========================================================================================================================
+//     mDNSPlatformGetSearchDomainList
+//===========================================================================================================================
+
+
+mDNSexport DNameListElem *mDNSPlatformGetSearchDomainList(void)
+       {
+       static DNameListElem tmp;
+       static int init = 0;
+
+       if (!init)
+               {
+               MakeDomainNameFromDNSNameString(&tmp.name, "local.");
+               tmp.next = NULL;
+               init = 1;
+               }
+       return mDNS_CopyDNameList(&tmp);
+       }
+
+
+
 #if 0
 #pragma mark -
 #endif
@@ -792,7 +868,7 @@ exit:
 //===========================================================================================================================
 
 #if( MDNS_DEBUGMSGS )
-void debugf_( const char *inFormat, ... )
+void   debugf_( const char *inFormat, ... )
 {
        char            buffer[ 512 ];
     va_list            args;
@@ -811,7 +887,7 @@ void debugf_( const char *inFormat, ... )
 //===========================================================================================================================
 
 #if( MDNS_DEBUGMSGS > 1 )
-void verbosedebugf_( const char *inFormat, ... )
+void   verbosedebugf_( const char *inFormat, ... )
 {
        char            buffer[ 512 ];
     va_list            args;
@@ -829,7 +905,7 @@ void verbosedebugf_( const char *inFormat, ... )
 //     LogMsg
 //===========================================================================================================================
 
-void LogMsg( const char *inFormat, ... )
+void   LogMsg( const char *inFormat, ... )
 {
        char            buffer[ 512 ];
     va_list            args;
@@ -842,84 +918,6 @@ void LogMsg( const char *inFormat, ... )
        dlog( kDebugLevelWarning, "%s\n", buffer );
 }
 
-#if( MDNS_DEBUGMSGS )
-//===========================================================================================================================
-//     mDNSPlatformDebugLog
-//===========================================================================================================================
-
-mDNSlocal void mDNSPlatformDebugLog( unsigned long inLevel, const char *inFormat, ... )
-{
-       if( inLevel >= gDebugLevel )
-       {
-               va_list         args;
-               
-               va_start( args, inFormat );
-               vfprintf( stderr, inFormat, args );
-               fflush( stderr );
-               va_end( args );
-       }
-}
-
-//===========================================================================================================================
-//     mDNSPlatformPrintAssert
-//===========================================================================================================================
-
-mDNSlocal void
-       mDNSPlatformPrintAssert( 
-               const char *            inSignature, 
-               long                            inError, 
-               const char *            inAssertionString, 
-               const char *            inErrorString, 
-               const char *            inFileName, 
-               unsigned long           inLineNumber, 
-               const char *            inFunction )
-{
-       char *          dataPtr;
-       char            buffer[ 512 ];
-       char            tempSignatureChar;
-               
-       if( !inSignature )
-       {
-               tempSignatureChar = '\0';
-               inSignature = &tempSignatureChar;
-       }
-       dataPtr = buffer;
-       dataPtr += sprintf( dataPtr, "\n" );
-       if( inError != 0 )
-       {
-               dataPtr += sprintf( dataPtr, "[%s] Error: %ld\n", inSignature, inError );
-       }
-       else
-       {
-               dataPtr += sprintf( dataPtr, "[%s] Assertion failed", inSignature );
-               if( inAssertionString )
-               {
-                       dataPtr += sprintf( dataPtr, ": %s", inAssertionString );
-               }
-               dataPtr += sprintf( dataPtr, "\n" );
-       }
-       if( inErrorString )
-       {
-               dataPtr += sprintf( dataPtr, "[%s]    %s\n", inSignature, inErrorString );
-       }
-       if( inFileName )
-       {
-               dataPtr += sprintf( dataPtr, "[%s]    file:     \"%s\"\n", inSignature, inFileName );
-       }       
-       if( inLineNumber )
-       {
-               dataPtr += sprintf( dataPtr, "[%s]    line:     %ld\n", inSignature, inLineNumber );
-       }
-       if( inFunction )
-       {
-               dataPtr += sprintf( dataPtr, "[%s]    function: \"%s\"\n", inSignature, inFunction );
-       }
-       dataPtr += sprintf( dataPtr, "\n" );
-       fprintf( stderr, "%s", buffer );
-       fflush( stderr );
-}
-#endif // MDNS_DEBUGMSGS
-
 #if 0
 #pragma mark -
 #pragma mark == Platform Internals  ==
@@ -932,32 +930,31 @@ mDNSlocal void
 mDNSlocal mStatus      SetupSynchronizationObjects( mDNS * const inMDNS )
 {
        mStatus         err;
-       
-       dlog( kDebugLevelVerbose, DEBUG_NAME "setting up synchronization objects\n" );
-       
+               
        InitializeCriticalSection( &inMDNS->p->lock );
        inMDNS->p->lockInitialized = mDNStrue;
        
        inMDNS->p->cancelEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
-       require_action( inMDNS->p->cancelEvent, exit, err = mStatus_NoMemoryErr );
+       err = translate_errno( inMDNS->p->cancelEvent, (mStatus) GetLastError(), kUnknownErr );
+       require_noerr( err, exit );
        
        inMDNS->p->quitEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
-       require_action( inMDNS->p->quitEvent, exit, err = mStatus_NoMemoryErr );
+       err = translate_errno( inMDNS->p->quitEvent, (mStatus) GetLastError(), kUnknownErr );
+       require_noerr( err, exit );
        
        inMDNS->p->interfaceListChangedEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
-       require_action( inMDNS->p->interfaceListChangedEvent, exit, err = mStatus_NoMemoryErr );
+       err = translate_errno( inMDNS->p->interfaceListChangedEvent, (mStatus) GetLastError(), kUnknownErr );
+       require_noerr( err, exit );
        
        inMDNS->p->wakeupEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
-       require_action( inMDNS->p->wakeupEvent, exit, err = mStatus_NoMemoryErr );
-       
-       err = mStatus_NoError;
+       err = translate_errno( inMDNS->p->wakeupEvent, (mStatus) GetLastError(), kUnknownErr );
+       require_noerr( err, exit );
        
 exit:
        if( err )
        {
                TearDownSynchronizationObjects( inMDNS );
        }
-       dlog( kDebugLevelVerbose, DEBUG_NAME "setting up synchronization objects done (err=%ld)\n", err );
        return( err );
 }
 
@@ -967,10 +964,6 @@ exit:
 
 mDNSlocal mStatus      TearDownSynchronizationObjects( mDNS * const inMDNS )
 {
-       mStatus         err;
-       
-       dlog( kDebugLevelVerbose, DEBUG_NAME "tearing down synchronization objects\n" );
-       
        if( inMDNS->p->quitEvent )
        {
                CloseHandle( inMDNS->p->quitEvent );
@@ -996,10 +989,7 @@ mDNSlocal mStatus  TearDownSynchronizationObjects( mDNS * const inMDNS )
                DeleteCriticalSection( &inMDNS->p->lock );
                inMDNS->p->lockInitialized = mDNSfalse;
        }
-       err = mStatus_NoError;
-       
-       dlog( kDebugLevelVerbose, DEBUG_NAME "tearing down synchronization objects done (err=%ld)\n", err );
-       return( err );
+       return( mStatus_NoError );
 }
 
 //===========================================================================================================================
@@ -1013,11 +1003,11 @@ mDNSlocal mStatus       SetupName( mDNS * const inMDNS )
        
        check( inMDNS );
        
-       // Get the name of this machine.
+       // Set up the nice name.
        
        tempString[ 0 ] = '\0';
        err = gethostname( tempString, sizeof( tempString ) - 1 );
-       check_errno( err, errno_compat() );
+       check_translated_errno( err == 0, errno_compat(), kNameErr );
        if( err || ( tempString[ 0 ] == '\0' ) )
        {
                // Invalidate name so fall back to a default name.
@@ -1026,10 +1016,11 @@ mDNSlocal mStatus       SetupName( mDNS * const inMDNS )
        }
        tempString[ sizeof( tempString ) - 1 ] = '\0';
        
-       // Set up the host name with mDNS.
-       
        inMDNS->nicelabel.c[ 0 ] = (mDNSu8) strlen( tempString );
        memcpy( &inMDNS->nicelabel.c[ 1 ], tempString, inMDNS->nicelabel.c[ 0 ] );
+       
+       // Set up the host name.
+       
        ConvertUTF8PstringToRFC1034HostLabel( inMDNS->nicelabel.c, &inMDNS->hostlabel );
        if( inMDNS->hostlabel.c[ 0 ] == 0 )
        {
@@ -1058,10 +1049,11 @@ mDNSlocal mStatus       SetupInterfaceList( mDNS * const inMDNS )
        mDNSInterfaceData *                     ifd;
        struct ifaddrs *                        addrs;
        struct ifaddrs *                        p;
+       struct ifaddrs *                        loopback;
        u_int                                           flagMask;
        u_int                                           flagTest;
        
-       dlog( kDebugLevelVerbose, DEBUG_NAME "setting up interface list\n" );
+       dlog( kDebugLevelTrace, DEBUG_NAME "setting up interface list\n" );
        check( inMDNS );
        check( inMDNS->p );
        
@@ -1081,34 +1073,108 @@ mDNSlocal mStatus      SetupInterfaceList( mDNS * const inMDNS )
        err = SetupNotifications( inMDNS );
        check_noerr( err );
        
-       // Set up each interface that is active, multicast-capable, and not the loopback interface or point-to-point.
+       // 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 );
        
-       flagMask = IFF_UP | IFF_MULTICAST | IFF_LOOPBACK | IFF_POINTTOPOINT;
+       loopback        = NULL;
+       next            = &inMDNS->p->interfaceList;
+       
+       flagMask = IFF_UP | IFF_MULTICAST | IFF_POINTTOPOINT;
        flagTest = IFF_UP | IFF_MULTICAST;
        
-       next = &inMDNS->p->interfaceList;
+#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( !loopback )
+                       {
+                               loopback = 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 );
+                                               
+               *next = ifd;
+               next  = &ifd->next;
+               ++inMDNS->p->interfaceCount;
+       }
+#endif
        
-       err = getifaddrs( &addrs );
-       require_noerr( err, exit );
+       // Set up IPv6 interface(s) after IPv4 is set up (see IPv4 notes above for reasoning).
        
+#if( MDNS_WINDOWS_ENABLE_IPV6 )
        for( p = addrs; p; p = p->ifa_next )
        {
-               if( ( p->ifa_flags & flagMask ) == flagTest )
+               if( !p->ifa_addr || ( p->ifa_addr->sa_family != AF_INET6 ) || ( ( p->ifa_flags & flagMask ) != flagTest ) )
+               {
+                       continue;
+               }
+               if( p->ifa_flags & IFF_LOOPBACK )
                {
-                       if( !p->ifa_addr || ( p->ifa_addr->sa_family != AF_INET ) )             // $$$ TO DO: Update for IPv6.
+                       if( !loopback )
                        {
-                               continue;
+                               loopback = p;
                        }
-                       
-                       err = SetupInterface( inMDNS, (struct sockaddr_in *) p->ifa_addr, &ifd );
-                       require_noerr( err, exit );
-                       
-                       strcpy( ifd->name, p->ifa_name );
-                       
-                       *next = ifd;
-                       next = &ifd->next;
-                       ++inMDNS->p->interfaceCount;
+                       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 );
+                                               
+               *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;
                }
+               loopback = p;
+               break;
+       }
+       
+#endif
+       
+       if( !inMDNS->p->interfaceList && loopback )
+       {
+               dlog( kDebugLevelVerbose, DEBUG_NAME "Interface %40s (0x%08X) %##a\n", 
+                       loopback->ifa_name ? loopback->ifa_name : "<null>", loopback->ifa_extra.index, loopback->ifa_addr );
+               
+               err = SetupInterface( inMDNS, loopback, &ifd );
+               require_noerr( err, exit );
+               
+               *next = ifd;
+               next  = &ifd->next;
+               ++inMDNS->p->interfaceCount;
        }
        
 exit:
@@ -1120,7 +1186,7 @@ exit:
        {
                freeifaddrs( addrs );
        }
-       dlog( kDebugLevelVerbose, DEBUG_NAME "setting up interface list done (err=%ld)\n", err );
+       dlog( kDebugLevelTrace, DEBUG_NAME "setting up interface list done (err=%d %m)\n", err, err );
        return( err );
 }
 
@@ -1133,7 +1199,7 @@ mDNSlocal mStatus TearDownInterfaceList( mDNS * const inMDNS )
        mStatus                                 err;
        mDNSInterfaceData *             ifd;
        
-       dlog( kDebugLevelVerbose, DEBUG_NAME "tearing down interface list\n" );
+       dlog( kDebugLevelTrace, DEBUG_NAME "tearing down interface list\n" );
        check( inMDNS );
        check( inMDNS->p );
        
@@ -1153,7 +1219,7 @@ mDNSlocal mStatus TearDownInterfaceList( mDNS * const inMDNS )
        }
        inMDNS->p->interfaceCount = 0;
        
-       dlog( kDebugLevelVerbose, DEBUG_NAME "tearing down interface list done\n" );
+       dlog( kDebugLevelTrace, DEBUG_NAME "tearing down interface list done\n" );
        return( mStatus_NoError );
 }
 
@@ -1161,54 +1227,137 @@ mDNSlocal mStatus      TearDownInterfaceList( mDNS * const inMDNS )
 //     SetupInterface
 //===========================================================================================================================
 
-mDNSlocal mStatus      SetupInterface( mDNS * const inMDNS, const struct sockaddr_in *inAddress, mDNSInterfaceData **outIFD )
+mDNSlocal mStatus      SetupInterface( mDNS * const inMDNS, const struct ifaddrs *inIFA, mDNSInterfaceData **outIFD )
 {
        mStatus                                 err;
        mDNSInterfaceData *             ifd;
-       SocketRef                               socketRef;
+       SocketRef                               sock;
        
-       dlog( kDebugLevelVerbose, DEBUG_NAME "setting up interface\n" );
+       ifd = NULL;
+       dlog( kDebugLevelTrace, DEBUG_NAME "setting up interface\n" );
        check( inMDNS );
        check( inMDNS->p );
-       check( inAddress );
+       check( inIFA );
+       check( inIFA->ifa_addr );
        check( outIFD );
        
-       // Allocate memory for the info item.
+       // Allocate memory for the interface and initialize it.
        
        ifd = (mDNSInterfaceData *) calloc( 1, sizeof( *ifd ) );
        require_action( ifd, exit, err = mStatus_NoMemoryErr );
-       ifd->sock = kInvalidSocketRef;
+       ifd->sock               = kInvalidSocketRef;
+       ifd->index              = inIFA->ifa_extra.index;
+       ifd->scopeID    = inIFA->ifa_extra.index;
        
-       // Set up a multicast DNS (port 5353) socket for this interface.
+       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';
+
+       // 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.
        
-       err = SetupSocket( inMDNS, inAddress, &socketRef );
-       require_noerr( err, exit );
-       ifd->sock = socketRef;
+       ifd->interfaceInfo.McastTxRx            = mDNStrue;
        
-       // Set up the read pending event and associate it so we can block until data is available for this socket.
+#if( MDNS_WINDOWS_EXCLUDE_IPV4_ROUTABLE_IPV6 )
+       if( inIFA->ifa_addr->sa_family != AF_INET )
+       {
+               const mDNSInterfaceData *               p;
+               
+               for( p = inMDNS->p->interfaceList; p; p = p->next )
+               {
+                       if( ( p->interfaceInfo.ip.type == mDNSAddrType_IPv4 ) &&
+                               ( ( p->interfaceInfo.ip.ip.v4.b[ 0 ] != 169 ) && ( p->interfaceInfo.ip.ip.v4.b[ 1 ] != 254 ) ) &&
+                               ( strcmp( p->name, inIFA->ifa_name ) == 0 ) )
+                       {
+                               ifd->interfaceInfo.McastTxRx = mDNSfalse;
+                               break;
+                       }
+               }
+       }
+#endif
+
+       // If this is an IPv6 interface, search for its IPv4 equivalent and use that InterfaceID. This causes the IPv4
+       // interface to send both A and AAAA records so we can publish IPv6 support without doubling the packet rate.
+       // Note: this search only works because we register all IPv4 interfaces before IPv6 interfaces.
        
-       ifd->readPendingEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
-       require_action( ifd->readPendingEvent, exit, err = mStatus_NoMemoryErr );
+       ifd->interfaceInfo.InterfaceID = (mDNSInterfaceID) ifd;
        
-       err = WSAEventSelect( ifd->sock, ifd->readPendingEvent, FD_READ );
-       require_noerr( err, exit );
+#if( MDNS_WINDOWS_AAAA_OVER_IPV4 )
+       if( inIFA->ifa_addr->sa_family != AF_INET )
+       {
+               mDNSInterfaceData *             ipv4IFD;
                
+               for( ipv4IFD = inMDNS->p->interfaceList; ipv4IFD; ipv4IFD = ipv4IFD->next )
+               {
+                       if( strcmp( ipv4IFD->name, ifd->name ) == 0 )
+                       {
+                               ipv4IFD->scopeID                                = ifd->scopeID;
+                               ifd->interfaceInfo.McastTxRx    = mDNSfalse;
+                               ifd->interfaceInfo.InterfaceID  = (mDNSInterfaceID) ipv4IFD;
+                               break;
+                       }
+               }
+       }
+#endif
+       
+       // Set up a socket for this interface (if needed).
+       
+       if( ifd->interfaceInfo.McastTxRx )
+       {
+               err = SetupSocket( inMDNS, inIFA->ifa_addr, &sock );
+               require_noerr( err, exit );
+               ifd->sock = sock;
+               ifd->defaultAddr = ( inIFA->ifa_addr->sa_family == AF_INET6 ) ? AllDNSLinkGroup_v6 : AllDNSLinkGroup_v4;
+               
+               // Get a ptr to the WSARecvMsg function, if supported. Otherwise, we'll fallback to recvfrom.
+
+               #if( !TARGET_OS_WINDOWS_CE )
+               {
+                       DWORD           size;
+
+                       err = WSAIoctl( sock, SIO_GET_EXTENSION_FUNCTION_POINTER, &kWSARecvMsgGUID, sizeof( kWSARecvMsgGUID ),
+                               &ifd->wsaRecvMsgFunctionPtr, sizeof( ifd->wsaRecvMsgFunctionPtr ), &size, NULL, NULL );
+                       if( err != 0 )
+                       {
+                               ifd->wsaRecvMsgFunctionPtr = NULL;
+                       }
+               }
+               #endif
+
+               // Set up the read pending event and associate it so we can block until data is available for this socket.
+               
+               ifd->readPendingEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
+               err = translate_errno( ifd->readPendingEvent, (mStatus) GetLastError(), kUnknownErr );
+               require_noerr( err, exit );
+               
+               err = WSAEventSelect( ifd->sock, ifd->readPendingEvent, FD_READ );
+               require_noerr( err, exit );
+       }
+       else
+       {
+               // Create a placeholder event so WaitForMultipleObjects Handle slot for this interface is valid.
+               
+               ifd->readPendingEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
+               err = translate_errno( ifd->readPendingEvent, (mStatus) GetLastError(), kUnknownErr );
+               require_noerr( err, exit );
+       }
+       
        // Register this interface with mDNS.
        
-       ifd->hostSet.InterfaceID                        = (mDNSInterfaceID) ifd;
-       ifd->hostSet.ip.type                            = mDNSAddrType_IPv4;
-       ifd->hostSet.ip.ip.v4.NotAnInteger      = inAddress->sin_addr.s_addr;
-       ifd->hostSet.Advertise                  = inMDNS->AdvertiseLocalAddresses;
+       err = SockAddrToMDNSAddr( inIFA->ifa_addr, &ifd->interfaceInfo.ip, NULL );
+       require_noerr( err, exit );
+       
+       ifd->interfaceInfo.Advertise = inMDNS->AdvertiseLocalAddresses;
        
-       err = mDNS_RegisterInterface( inMDNS, &ifd->hostSet );
+       err = mDNS_RegisterInterface( inMDNS, &ifd->interfaceInfo );
        require_noerr( err, exit );
        ifd->hostRegistered = mDNStrue;
        
-       dlog( kDebugLevelInfo, DEBUG_NAME "Registered IP address: %u.%u.%u.%u\n", 
-                 ifd->hostSet.ip.ip.v4.b[ 0 ], 
-                 ifd->hostSet.ip.ip.v4.b[ 1 ], 
-                 ifd->hostSet.ip.ip.v4.b[ 2 ], 
-                 ifd->hostSet.ip.ip.v4.b[ 3 ] );
+       dlog( kDebugLevelInfo, DEBUG_NAME "Registered interface %##a with mDNS\n", inIFA->ifa_addr );
        
        // Success!
        
@@ -1220,7 +1369,7 @@ exit:
        {
                TearDownInterface( inMDNS, ifd );
        }
-       dlog( kDebugLevelVerbose, DEBUG_NAME "setting up interface done (err=%ld)\n", err );
+       dlog( kDebugLevelTrace, DEBUG_NAME "setting up interface done (err=%d %m)\n", err, err );
        return( err );
 }
 
@@ -1230,23 +1379,19 @@ exit:
 
 mDNSlocal mStatus      TearDownInterface( mDNS * const inMDNS, mDNSInterfaceData *inIFD )
 {
-       SocketRef               socketRef;
+       SocketRef               sock;
        
        check( inMDNS );
        check( inIFD );
        
        // Deregister this interface with mDNS.
        
-       dlog( kDebugLevelInfo, DEBUG_NAME "Deregistering IP address: %u.%u.%u.%u\n", 
-                 inIFD->hostSet.ip.ip.v4.b[ 0 ],
-                 inIFD->hostSet.ip.ip.v4.b[ 1 ],
-                 inIFD->hostSet.ip.ip.v4.b[ 2 ],
-                 inIFD->hostSet.ip.ip.v4.b[ 3 ] );
+       dlog( kDebugLevelInfo, DEBUG_NAME "Deregistering interface %#a with mDNS\n", &inIFD->interfaceInfo.ip );
        
        if( inIFD->hostRegistered )
        {
                inIFD->hostRegistered = mDNSfalse;
-               mDNS_DeregisterInterface( inMDNS, &inIFD->hostSet );
+               mDNS_DeregisterInterface( inMDNS, &inIFD->interfaceInfo );
        }
        
        // Tear down the multicast socket.
@@ -1257,12 +1402,11 @@ mDNSlocal mStatus       TearDownInterface( mDNS * const inMDNS, mDNSInterfaceData *inI
                inIFD->readPendingEvent = 0;
        }
        
-       socketRef = inIFD->sock;
+       sock = inIFD->sock;
        inIFD->sock = kInvalidSocketRef;
-       if( IsValidSocket( socketRef ) )
+       if( IsValidSocket( sock ) )
        {
-               dlog( kDebugLevelVerbose, DEBUG_NAME "tearing down socket %d\n", socketRef );
-               close_compat( socketRef );
+               close_compat( sock );
        }
                
        // Free the memory used by the interface info.
@@ -1275,84 +1419,223 @@ mDNSlocal mStatus      TearDownInterface( mDNS * const inMDNS, mDNSInterfaceData *inI
 //     SetupSocket
 //===========================================================================================================================
 
-mDNSlocal mStatus
-       SetupSocket( 
-               mDNS * const                            inMDNS, 
-               const struct sockaddr_in *      inAddress, 
-               SocketRef *                                     outSocketRef  )
+mDNSlocal mStatus      SetupSocket( mDNS * const inMDNS, const struct sockaddr *inAddr, SocketRef *outSocketRef  )
 {
-       mStatus                                 err;
-       SocketRef                               socketRef;
-       int                                             option;
-       struct ip_mreq                  mreq;
-       struct sockaddr_in              addr;
-       mDNSv4Addr                              ip;
+       mStatus                 err;
+       SocketRef               sock;
+       int                             option;
        
-       MDNS_UNUSED( inMDNS );
+       DEBUG_UNUSED( inMDNS );
        
-       dlog( kDebugLevelVerbose, DEBUG_NAME "setting up socket done\n" );
+       dlog( kDebugLevelTrace, DEBUG_NAME "setting up socket %##a\n", inAddr );
        check( inMDNS );
        check( outSocketRef );
        
-       // Set up a UDP socket. 
-       
-       socketRef = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
-       require_action( IsValidSocket( socketRef ), exit, err = mStatus_NoMemoryErr );
+       // 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.
        
        option = 1;
-       err = setsockopt( socketRef, SOL_SOCKET, SO_REUSEADDR, (char *) &option, sizeof( option ) );
-       check_errno( err, errno_compat() );
-       
-       // Bind to the mutlicast DNS port 5353.
-       
-       ip.NotAnInteger                 = inAddress->sin_addr.s_addr;
-       memset( &addr, 0, 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_compat() );
+       err = setsockopt( sock, SOL_SOCKET, SO_REUSEADDR, (char *) &option, sizeof( option ) );
+       check_translated_errno( err == 0, errno_compat(), kOptionErr );
        
-       // Join the all-DNS multicast group so we receive Multicast DNS packets.
-       
-       mreq.imr_multiaddr.s_addr       = AllDNSLinkGroup.NotAnInteger;
-       mreq.imr_interface.s_addr       = ip.NotAnInteger;
-       err = setsockopt( socketRef, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mreq, sizeof( mreq ) );
-       check_errno( err, errno_compat() );
-                               
-       // 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_compat() );
-       
-       // Set the TTL of outgoing unicast packets to 255 (helps against spoofing).
+       if( inAddr->sa_family == AF_INET )
+       {
+               mDNSv4Addr                              ipv4;
+               struct sockaddr_in              sa4;
+               struct ip_mreq                  mreqv4;
                
-       option = 255;
-       err = setsockopt( socketRef, IPPROTO_IP, IP_TTL, (char *) &option, sizeof( option ) );
-       check_errno( err, errno_compat() );
-       
-       // Set the TTL of outgoing multicast packets to 255 (helps against spoofing).
-       
-       option = 255;
-       err = setsockopt( socketRef, IPPROTO_IP, IP_MULTICAST_TTL, (char *) &option, sizeof( option ) );
-       check_errno( err, errno_compat() );
+               // Bind to the multicast DNS port 5353.
                
-       // Success!
+               ipv4.NotAnInteger       = ( (const struct sockaddr_in *) inAddr )->sin_addr.s_addr;
+               memset( &sa4, 0, sizeof( sa4 ) );
+               sa4.sin_family          = AF_INET;
+               sa4.sin_port            = MulticastDNSPort.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 );
+               
+               // Join the all-DNS multicast group so we receive Multicast DNS packets.
+               
+               mreqv4.imr_multiaddr.s_addr = AllDNSLinkGroup.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 );
+               
+               // 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 );
+               
+               // 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 );
+       }
+       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 to the multicast DNS port 5353.
+               
+               memset( &sa6, 0, sizeof( sa6 ) );
+               sa6.sin6_family         = AF_INET6;
+               sa6.sin6_port           = MulticastDNSPort.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 );
+               
+               // Turn on option to receive TTL so we can check for spoofing.
+               
+               option = 1;
+               err = setsockopt( sock, IPPROTO_IPV6, IPV6_HOPLIMIT, (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
+               
+               // Join the all-DNS multicast group so we receive Multicast DNS packets.
+               
+               mreqv6.ipv6mr_multiaddr = *( (struct in6_addr *) &AllDNSLinkGroupv6 );
+               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 );
+               
+               // 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 );
+               
+               // 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 );
+       }
+       else
+       {
+               dlog( kDebugLevelError, DEBUG_NAME "%s: unsupport socket family (%d)\n", __ROUTINE__, inAddr->sa_family );
+               err = kUnsupportedErr;
+               goto exit;
+       }
        
-       dlog( kDebugLevelVerbose, DEBUG_NAME "setting up socket done (%u.%u.%u.%u, %d)\n", 
-                 ip.b[ 0 ], ip.b[ 1 ], ip.b[ 2 ], ip.b[ 3 ], socketRef );
+       // Success!
        
-       *outSocketRef = socketRef;
-       socketRef = kInvalidSocketRef;
+       *outSocketRef = sock;
+       sock = kInvalidSocketRef;
        err = mStatus_NoError;
        
 exit:
-       if( IsValidSocket( socketRef ) )
+       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
        {
-               close_compat( socketRef );
+               dlog( kDebugLevelError, DEBUG_NAME "%s: invalid sa_family %d", __ROUTINE__, inSA->sa_family );
+               err = mStatus_BadParamErr;
        }
        return( err );
 }
@@ -1364,7 +1647,7 @@ exit:
 mDNSlocal mStatus      SetupNotifications( mDNS * const inMDNS )
 {
        mStatus                         err;
-       SocketRef                       socketRef;
+       SocketRef                       sock;
        unsigned long           param;
        int                                     inBuffer;
        int                                     outBuffer;
@@ -1372,27 +1655,30 @@ mDNSlocal mStatus       SetupNotifications( mDNS * const inMDNS )
        
        // Register to listen for address list changes.
        
-       socketRef = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
-       require_action( IsValidSocket( socketRef ), exit, err = mStatus_NoMemoryErr );
-       inMDNS->p->interfaceListChangedSocketRef = socketRef;
+       sock = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
+       err = translate_errno( IsValidSocket( sock ), errno_compat(), kUnknownErr );
+       require_noerr( err, exit );
+       inMDNS->p->interfaceListChangedSocket = sock;
        
        // Make the socket non-blocking so the WSAIoctl returns immediately with WSAEWOULDBLOCK. It will set the event 
        // when a change to the interface list is detected.
        
        param = 1;
-       err = ioctlsocket( socketRef, FIONBIO, &param );
-       require_errno( err, errno_compat(), exit );
+       err = ioctlsocket( sock, FIONBIO, &param );
+       err = translate_errno( err == 0, errno_compat(), kUnknownErr );
+       require_noerr( err, exit );
        
        inBuffer        = 0;
        outBuffer       = 0;
-       err = WSAIoctl( socketRef, SIO_ADDRESS_LIST_CHANGE, &inBuffer, 0, &outBuffer, 0, &outSize, NULL, NULL );
+       err = WSAIoctl( sock, SIO_ADDRESS_LIST_CHANGE, &inBuffer, 0, &outBuffer, 0, &outSize, NULL, NULL );
        if( err < 0 )
        {
                check( errno_compat() == WSAEWOULDBLOCK );
        }
        
-       err = WSAEventSelect( socketRef, inMDNS->p->interfaceListChangedEvent, FD_ADDRESS_LIST_CHANGE );
-       require_errno( err, errno_compat(), exit );
+       err = WSAEventSelect( sock, inMDNS->p->interfaceListChangedEvent, FD_ADDRESS_LIST_CHANGE );
+       err = translate_errno( err == 0, errno_compat(), kUnknownErr );
+       require_noerr( err, exit );
 
 exit:
        if( err )
@@ -1408,13 +1694,10 @@ exit:
 
 mDNSlocal mStatus      TearDownNotifications( mDNS * const inMDNS )
 {
-       SocketRef               socketRef;
-       
-       socketRef = inMDNS->p->interfaceListChangedSocketRef;
-       inMDNS->p->interfaceListChangedSocketRef = kInvalidSocketRef;
-       if( IsValidSocket( socketRef ) )
+       if( IsValidSocket( inMDNS->p->interfaceListChangedSocket ) )
        {
-               close_compat( socketRef );
+               close_compat( inMDNS->p->interfaceListChangedSocket );
+               inMDNS->p->interfaceListChangedSocket = kInvalidSocketRef;
        }
        return( mStatus_NoError );
 }
@@ -1434,23 +1717,27 @@ mDNSlocal mStatus       SetupThread( mDNS * const inMDNS )
        unsigned                threadID;
        DWORD                   result;
        
-       dlog( kDebugLevelVerbose, DEBUG_NAME "setting up thread\n" );
+       dlog( kDebugLevelTrace, DEBUG_NAME "setting up thread\n" );
        
        // To avoid a race condition with the thread ID needed by the unlocking code, we need to make sure the
        // thread has fully initialized. To do this, we create the thread then wait for it to signal it is ready.
        
        inMDNS->p->initEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
-       require_action( inMDNS->p->initEvent, exit, err = mStatus_NoMemoryErr );
+       err = translate_errno( inMDNS->p->initEvent, (mStatus) GetLastError(), kUnknownErr );
+       require_noerr( err, exit );
+
        inMDNS->p->initStatus = mStatus_Invalid;
        
        // Create thread with _beginthreadex() instead of CreateThread() to avoid memory leaks when using static run-time 
        // libraries. See <http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/createthread.asp>.
        
-       threadHandle = (HANDLE) _beginthreadex( NULL, 0, ProcessingThread, inMDNS, 0, &threadID );
-       require_action( threadHandle, exit, err = mStatus_NoMemoryErr );
-       
+       threadHandle = (HANDLE) _beginthreadex_compat( NULL, 0, ProcessingThread, inMDNS, 0, &threadID );
+       err = translate_errno( threadHandle, (mStatus) GetLastError(), kUnknownErr );
+       require_noerr( err, exit );
+               
        result = WaitForSingleObject( inMDNS->p->initEvent, INFINITE );
-       require_action( result == WAIT_OBJECT_0, exit, err = mStatus_UnknownErr );
+       err = translate_errno( result == WAIT_OBJECT_0, (mStatus) GetLastError(), kUnknownErr );
+       require_noerr( err, exit );
        err = inMDNS->p->initStatus;
        require_noerr( err, exit );
        
@@ -1460,7 +1747,7 @@ exit:
                CloseHandle( inMDNS->p->initEvent );
                inMDNS->p->initEvent = 0;
        }
-       dlog( kDebugLevelVerbose, DEBUG_NAME "setting up thread done (err=%ld)\n", err );
+       dlog( kDebugLevelTrace, DEBUG_NAME "setting up thread done (err=%d %m)\n", err, err );
        return( err );
 }
 
@@ -1470,22 +1757,21 @@ exit:
 
 mDNSlocal mStatus      TearDownThread( const mDNS * const inMDNS )
 {
-       DWORD           result;
-       
        // Signal the cancel event to cause the thread to exit. Then wait for the quit event to be signal indicating it did 
        // exit. If the quit event is not signal in 5 seconds, just give up and close anyway sinec the thread is probably hung.
        
        if( inMDNS->p->cancelEvent )
        {
                BOOL            wasSet;
+               DWORD           result;
                
                wasSet = SetEvent( inMDNS->p->cancelEvent );
-               check( wasSet );
+               check_translated_errno( wasSet, GetLastError(), kUnknownErr );
                
                if( inMDNS->p->quitEvent )
                {
                        result = WaitForSingleObject( inMDNS->p->quitEvent, 5 * 1000 );
-                       check( result == WAIT_OBJECT_0 );
+                       check_translated_errno( result == WAIT_OBJECT_0, GetLastError(), kUnknownErr );
                }
        }
        return( mStatus_NoError );
@@ -1533,7 +1819,7 @@ mDNSlocal unsigned WINAPI ProcessingThread( LPVOID inParam )
                        else                                                                            interval = (interval * 1000) / mDNSPlatformOneSecond;
                        
                        // Wait until something occurs (e.g. cancel, incoming packet, or timeout).
-                       
+                                               
                        result = WaitForMultipleObjects( (DWORD) waitListCount, waitList, FALSE, (DWORD) interval );
                        if( result == WAIT_TIMEOUT )
                        {
@@ -1561,7 +1847,7 @@ mDNSlocal unsigned WINAPI ProcessingThread( LPVOID inParam )
                        {
                                // Wakeup event due to an mDNS API call. Loop back to call mDNS_Execute.
                                
-                               dlog( kDebugLevelChatty - 1, DEBUG_NAME "wakeup\n" );
+                               dlog( kDebugLevelChatty - 1, DEBUG_NAME "wakeup for mDNS_Execute\n" );
                                continue;
                        }
                        else
@@ -1596,7 +1882,7 @@ mDNSlocal unsigned WINAPI ProcessingThread( LPVOID inParam )
                                {
                                        // Unexpected wait result.
                                
-                                       dlog( kDebugLevelAllowedError, DEBUG_NAME "unexpected wait result (result=0x%08X)\n", result );
+                                       dlog( kDebugLevelWarning, DEBUG_NAME "%s: unexpected wait result (result=0x%08X)\n", __ROUTINE__, result );
                                }
                        }
                }
@@ -1615,12 +1901,12 @@ mDNSlocal unsigned WINAPI       ProcessingThread( LPVOID inParam )
 
 exit:
        wasSet = SetEvent( m->p->quitEvent );
-       check( wasSet );
-
+       check_translated_errno( wasSet, GetLastError(), kUnknownErr );
+       
        // Call _endthreadex() explicitly instead of just exiting normally to avoid memory leaks when using static run-time
        // libraries. See <http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/createthread.asp>.
        
-       _endthreadex( 0 );
+       _endthreadex_compat( 0 );
        return( 0 );
 }
 
@@ -1644,9 +1930,9 @@ exit:
                TearDownInterfaceList( inMDNS );
        }
        inMDNS->p->initStatus = err;
-       wasSet = SetEvent( inMDNS->p->initEvent );
-       check( wasSet );
        
+       wasSet = SetEvent( inMDNS->p->initEvent );
+       check_translated_errno( wasSet, GetLastError(), kUnknownErr );
        return( err );
 }
 
@@ -1662,7 +1948,7 @@ mDNSlocal mStatus ProcessingThreadSetupWaitList( mDNS * const inMDNS, HANDLE **o
        HANDLE *                                waitItemPtr;
        mDNSInterfaceData *             ifd;
        
-       dlog( kDebugLevelVerbose, DEBUG_NAME "thread setting up wait list\n" );
+       dlog( kDebugLevelTrace, DEBUG_NAME "thread setting up wait list\n" );
        check( inMDNS );
        check( inMDNS->p );
        check( outWaitList );
@@ -1687,6 +1973,7 @@ mDNSlocal mStatus ProcessingThreadSetupWaitList( mDNS * const inMDNS, HANDLE **o
        {
                *waitItemPtr++ = ifd->readPendingEvent;
        }
+       check( (int)( waitItemPtr - waitList ) == waitListCount );
        
        *outWaitList            = waitList;
        *outWaitListCount       = waitListCount;
@@ -1698,7 +1985,7 @@ exit:
        {
                free( waitList );
        }
-       dlog( kDebugLevelVerbose, DEBUG_NAME "thread setting up wait list done (err=%ld)\n", err );
+       dlog( kDebugLevelTrace, DEBUG_NAME "thread setting up wait list done (err=%d %m)\n", err, err );
        return( err );
 }
 
@@ -1706,58 +1993,111 @@ exit:
 //     ProcessingThreadProcessPacket
 //===========================================================================================================================
 
-mDNSlocal void ProcessingThreadProcessPacket( mDNS *inMDNS, mDNSInterfaceData *inIFD, SocketRef inSocketRef )
+mDNSlocal void ProcessingThreadProcessPacket( mDNS *inMDNS, mDNSInterfaceData *inIFD, SocketRef inSock )
 {
-       int                                             n;
-       DNSMessage                              packet;
-       struct sockaddr_in              addr;
-       int                                             addrSize;
-       mDNSu8 *                                packetEndPtr;
-       mDNSAddr                                srcAddr;
-       mDNSIPPort                              srcPort;
-       mDNSAddr                                dstAddr;
-       mDNSIPPort                              dstPort;
+       OSStatus                                        err;
+       mDNSAddr                                        srcAddr;
+       mDNSIPPort                                      srcPort;
+       mDNSAddr                                        dstAddr;
+       mDNSIPPort                                      dstPort;
+       mDNSu8                                          ttl;
+       struct sockaddr_storage         addr;
+       DNSMessage                                      packet;
+       mDNSu8 *                                        end;
+       int                                                     n;
        
-       // Receive the packet.
+       check( inMDNS );
+       check( inIFD );
+       check( IsValidSocket( inSock ) );
        
-       addrSize = sizeof( addr );
-       n = recvfrom( inSocketRef, (char *) &packet, sizeof( packet ), 0, (struct sockaddr *) &addr, &addrSize );
-       check( n >= 0 );
-       if( n >= 0 )
+       // Set up the default in case the packet info options are not supported or reported correctly.
+       
+       dstAddr = inIFD->defaultAddr;
+       dstPort = MulticastDNSPort;
+       ttl             = 255;
+
+#if( !TARGET_OS_WINDOWS_CE )
+       if( inIFD->wsaRecvMsgFunctionPtr )
        {
-               // Set up the src/dst/interface info.
+               WSAMSG                          msg;
+               WSABUF                          buf;
+               uint8_t                         controlBuffer[ 128 ];
+               DWORD                           size;
+               LPWSACMSGHDR            header;
                
-               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;
-               dstPort                                         = MulticastDNSPort;
+               // Set up the buffer and read the packet.
                
-               dlog( kDebugLevelChatty, DEBUG_NAME "packet received\n" );
-               dlog( kDebugLevelChatty, DEBUG_NAME "    size      = %d\n", n );
-               dlog( kDebugLevelChatty, DEBUG_NAME "    src       = %u.%u.%u.%u:%u\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:%u\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 = %u.%u.%u.%u\n", 
-                         inIFD->hostSet.ip.ip.v4.b[ 0 ], inIFD->hostSet.ip.ip.v4.b[ 1 ], 
-                         inIFD->hostSet.ip.ip.v4.b[ 2 ], inIFD->hostSet.ip.ip.v4.b[ 3 ] );
-       
-               dlog( kDebugLevelChatty, DEBUG_NAME "--\n" );
+               msg.name                        = (LPSOCKADDR) &addr;
+               msg.namelen                     = (INT) sizeof( addr );
+               buf.buf                         = (char *) &packet;
+               buf.len                         = (u_long) sizeof( packet );
+               msg.lpBuffers           = &buf;
+               msg.dwBufferCount       = 1;
+               msg.Control.buf         = (char *) controlBuffer;
+               msg.Control.len         = (u_long) sizeof( controlBuffer );
+               msg.dwFlags                     = 0;
+                               
+               err = inIFD->wsaRecvMsgFunctionPtr( inSock, &msg, &size, NULL, NULL );
+               err = translate_errno( err == 0, (OSStatus) GetLastError(), kUnknownErr );
+               require_noerr( err, exit );
+               n = (int) size;
+               
+               // Parse the control information. Reject packets received on the wrong interface.
                
-               // Dispatch the packet to mDNS.
+               for( header = WSA_CMSG_FIRSTHDR( &msg ); header; header = WSA_CMSG_NXTHDR( &msg, header ) )
+               {
+                       if( ( header->cmsg_level == IPPROTO_IP ) && ( header->cmsg_type == IP_PKTINFO ) )
+                       {
+                               IN_PKTINFO *            ipv4PacketInfo;
+                               
+                               ipv4PacketInfo = (IN_PKTINFO *) WSA_CMSG_DATA( header );
+                               require_action( ipv4PacketInfo->ipi_ifindex == ( inIFD->index >> 8 ), exit, err = kMismatchErr );
+                               
+                               dstAddr.type                            = mDNSAddrType_IPv4;
+                               dstAddr.ip.v4.NotAnInteger      = ipv4PacketInfo->ipi_addr.s_addr;
+                       }
+                       else if( ( header->cmsg_level == IPPROTO_IPV6 ) && ( header->cmsg_type == IPV6_PKTINFO ) )
+                       {
+                               IN6_PKTINFO *           ipv6PacketInfo;
+                               
+                               ipv6PacketInfo = (IN6_PKTINFO *) WSA_CMSG_DATA( header );
+                               require_action( ipv6PacketInfo->ipi6_ifindex == inIFD->index, exit, err = kMismatchErr );
+                               
+                               dstAddr.type    = mDNSAddrType_IPv6;
+                               dstAddr.ip.v6   = *( (mDNSv6Addr *) &ipv6PacketInfo->ipi6_addr );
+                       }
+                       else if( ( header->cmsg_level == IPPROTO_IPV6 ) && ( header->cmsg_type == IPV6_HOPLIMIT ) )
+                       {
+                               ttl = (mDNSu8) *( (int *) WSA_CMSG_DATA( header ) );
+                       }
+               }
+       }
+       else
+#endif
+       {
+               int             addrSize;
                
-               packetEndPtr = ( (mDNSu8 *) &packet ) + n;
-               mDNSCoreReceive( inMDNS, &packet, packetEndPtr, &srcAddr, srcPort, &dstAddr, dstPort, inIFD->hostSet.InterfaceID, 255 );
+               addrSize = sizeof( addr );
+               n = recvfrom( inSock, (char *) &packet, sizeof( packet ), 0, (struct sockaddr *) &addr, &addrSize );
+               err = translate_errno( n > 0, errno_compat(), kUnknownErr );
+               require_noerr( err, exit );
        }
+       SockAddrToMDNSAddr( (struct sockaddr *) &addr, &srcAddr, &srcPort );
+       
+       // Dispatch the packet to mDNS.
        
-       // Update counters.
+       dlog( kDebugLevelChatty, DEBUG_NAME "packet received\n" );
+       dlog( kDebugLevelChatty, DEBUG_NAME "    size      = %d\n", n );
+       dlog( kDebugLevelChatty, DEBUG_NAME "    src       = %#a:%u\n", &srcAddr, ntohs( srcPort.NotAnInteger ) );
+       dlog( kDebugLevelChatty, DEBUG_NAME "    dst       = %#a:%u\n", &dstAddr, ntohs( dstPort.NotAnInteger ) );
+       dlog( kDebugLevelChatty, DEBUG_NAME "    interface = %#a (index=0x%08X)\n", &inIFD->interfaceInfo.ip, (int) inIFD->index );
+       dlog( kDebugLevelChatty, DEBUG_NAME "\n" );
        
-       inIFD->recvCounter              += 1;
-       inIFD->recvErrorCounter += ( n < 0 );
+       end = ( (mDNSu8 *) &packet ) + n;
+       mDNSCoreReceive( inMDNS, &packet, end, &srcAddr, srcPort, &dstAddr, dstPort, inIFD->interfaceInfo.InterfaceID, ttl );
+       
+exit:
+       return;
 }
 
 //===========================================================================================================================
@@ -1768,7 +2108,7 @@ mDNSlocal void    ProcessingThreadInterfaceListChanged( mDNS *inMDNS )
 {
        mStatus         err;
        
-       dlog( kDebugLevelInfo, DEBUG_NAME "interface list changed event\n" );
+       dlog( kDebugLevelInfo, DEBUG_NAME "interface list changed\n" );
        check( inMDNS );
        
        mDNSPlatformLock( inMDNS );
@@ -1800,97 +2140,201 @@ mDNSlocal void ProcessingThreadInterfaceListChanged( mDNS *inMDNS )
 #pragma mark == Utilities ==
 #endif
 
-#if( defined( _WIN32_WCE ) )
 //===========================================================================================================================
 //     getifaddrs
 //===========================================================================================================================
 
 int    getifaddrs( struct ifaddrs **outAddrs )
 {
-       int                                                     err;
-       SocketRef                                       sock;
-       DWORD                                           size;
-       void *                                          buffer;
-       SOCKET_ADDRESS_LIST *           addressList;
-       struct ifaddrs *                        head;
-       struct ifaddrs **                       next;
-       struct ifaddrs *                        ifa;
-       int                                                     n;
-       int                                                     i;
-
-       sock    = kInvalidSocketRef;
-       buffer  = NULL;
-       head    = NULL;
-       next    = &head;
-       
-       // Open a temporary socket because one is needed to use WSAIoctl (we'll close it before exiting this function).
-       
-       sock = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
-       require_action( IsValidSocket( sock ), exit, err = mStatus_NoMemoryErr );
+       int             err;
        
-       // Call WSAIoctl with SIO_ADDRESS_LIST_QUERY and pass a null buffer. This call will fail, but the size needed to 
-       // for the request will be filled in. Once we know the size, allocate a buffer to hold the entire list.
-       //
-       // NOTE: Due to a bug in Windows CE, the size returned by WSAIoctl is not enough so double it as a workaround.
+#if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS && !TARGET_OS_WINDOWS_CE )
        
-       size = 0;
-       WSAIoctl( sock, SIO_ADDRESS_LIST_QUERY, NULL, 0, NULL, 0, &size, NULL, NULL );
-       require_action( size > 0, exit, err = -1 );
-       size *= 2;
+       // 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.
        
-       buffer = calloc( 1, size );
-       require_action( buffer, exit, err = -1 );
+       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;
+                       }
+               }
+       }
        
-       // We now know the size of the list and have a buffer to hold so call WSAIoctl again to get it.
+       // Use the new IPv6-capable routine if supported. Otherwise, fall back to the old and compatible IPv4-only code.
        
-       err = WSAIoctl( sock, SIO_ADDRESS_LIST_QUERY, NULL, 0, buffer, size, &size, NULL, NULL );
+       if( gGetAdaptersAddressesFunctionPtr )
+       {
+               err = getifaddrs_ipv6( outAddrs );
+               require_noerr( err, exit );
+       }
+       else
+       {
+               err = getifaddrs_ipv4( outAddrs );
+               require_noerr( err, exit );
+       }
+       
+#elif( !TARGET_OS_WINDOWS_CE )
+
+       err = getifaddrs_ipv4( outAddrs );
        require_noerr( err, exit );
-       addressList = (SOCKET_ADDRESS_LIST *) buffer;
+
+#else
+
+       err = getifaddrs_ce( 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;
        
-       // Process the raw interface list and build a linked list of interfaces.
-       //
-       // NOTE: Due to a bug in Windows CE, the iAddressCount field is always 0 so use 1 in that case.
+       check( gGetAdaptersAddressesFunctionPtr );
        
-       n = addressList->iAddressCount;
-       if( n == 0 )
-       {
-               n = 1;
-       }
-       for( i = 0; i < n; ++i )
+       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_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME;
+       i = 0;
+       for( ;; )
        {
-               ifa = (struct ifaddrs *) calloc( 1, sizeof( struct ifaddrs ) );
-               require_action( ifa, exit, err = WSAENOBUFS );
+               iaaListSize = 0;
+               err = gGetAdaptersAddressesFunctionPtr( AF_UNSPEC, flags, NULL, NULL, &iaaListSize );
+               check( err == ERROR_BUFFER_OVERFLOW );
+               check( iaaListSize >= sizeof( IP_ADAPTER_ADDRESSES ) );
                
-               *next = ifa;
-               next  = &ifa->ifa_next;
+               iaaList = (IP_ADAPTER_ADDRESSES *) malloc( iaaListSize );
+               require_action( iaaList, exit, err = ERROR_NOT_ENOUGH_MEMORY );
                
-               // Fetch the name. $$$ TO DO: Get the real name of the interface.
+               err = gGetAdaptersAddressesFunctionPtr( AF_UNSPEC, flags, NULL, iaaList, &iaaListSize );
+               if( err == ERROR_SUCCESS ) break;
                
-               ifa->ifa_name = (char *) malloc( 16 );
-               require_action( ifa->ifa_name, exit, err = WSAENOBUFS );
-               sprintf( ifa->ifa_name, "%d", i + 1 );
+               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 )
+       {
+               IP_ADAPTER_UNICAST_ADDRESS *            addr;
+
+               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 );
+               }
                
-               // Fetch flags. Note: SIO_ADDRESS_LIST_QUERY does not report flags so just fake IFF_UP and IFF_MULTICAST.
+               // Skip psuedo and tunnel interfaces.
                
-               ifa->ifa_flags = IFF_UP | IFF_MULTICAST;
+               if( ( iaa->Ipv6IfIndex == 1 ) || ( iaa->IfType == IF_TYPE_TUNNEL ) )
+               {
+                       continue;
+               }
                
-               // Fetch addresses.
+               // Add each address as a separate interface to emulate the way getifaddrs works.
                
-               switch( addressList->Address[ i ].lpSockaddr->sa_family )
-               {
-                       case AF_INET:
+               for( addr = iaa->FirstUnicastAddress; addr; addr = addr->Next )
+               {                       
+                       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;
+                       }
+                       if( !( iaa->Flags & IP_ADAPTER_NO_MULTICAST ) )
+                       {
+                               ifa->ifa_flags |= IFF_MULTICAST;
+                       }
+                       
+                       // Get the interface index. Windows does not have a uniform scheme for IPv4 and IPv6 interface indexes
+                       // so the following is a hack to put IPv4 interface indexes in the upper 16-bits and IPv6 interface indexes
+                       // in the lower 16-bits. This allows the IPv6 interface index to be usable as an IPv6 scope ID directly.
+                       
+                       switch( addr->Address.lpSockaddr->sa_family )
                        {
-                               struct sockaddr_in *            sinptr4;
+                               case AF_INET:
+                                       ifa->ifa_extra.index = iaa->IfIndex << 8;
+                                       break;
+                                       
+                               case AF_INET6:
+                                       ifa->ifa_extra.index = iaa->Ipv6IfIndex;
+                                       break;
                                
-                               sinptr4 = (struct sockaddr_in *) addressList->Address[ i ].lpSockaddr;
-                               ifa->ifa_addr = (struct sockaddr *) calloc( 1, sizeof( *sinptr4 ) );
-                               require_action( ifa->ifa_addr, exit, err = WSAENOBUFS );
-                               memcpy( ifa->ifa_addr, sinptr4, sizeof( *sinptr4 ) );
-                               break;
+                               default:
+                                       break;
                        }
                        
-                       default:
-                               break;
+                       // Get addresses.
+                       
+                       switch( addr->Address.lpSockaddr->sa_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;
+                       }
                }
        }
        
@@ -1901,47 +2345,40 @@ int     getifaddrs( struct ifaddrs **outAddrs )
                *outAddrs = head;
                head = NULL;
        }
-       err = 0;
+       err = ERROR_SUCCESS;
        
 exit:
        if( head )
        {
                freeifaddrs( head );
        }
-       if( buffer )
-       {
-               free( buffer );
-       }
-       if( sock != INVALID_SOCKET )
+       if( iaaList )
        {
-               closesocket( sock );
+               free( iaaList );
        }
-       return( err );
+       return( (int) err );
 }
-#endif // defined( _WIN32_WCE ) )
+#endif // MDNS_WINDOWS_USE_IPV6_IF_ADDRS
 
-#if( !defined( _WIN32_WCE ) )
+#if( !TARGET_OS_WINDOWS_CE )
 //===========================================================================================================================
-//     getifaddrs
+//     getifaddrs_ipv4
 //===========================================================================================================================
 
-int    getifaddrs( struct ifaddrs **outAddrs )
+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;
-       struct sockaddr_in *                    sinptr4;
-       struct sockaddr_in6_old *               sinptr6;
-       struct sockaddr *                               sa;
+       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;
@@ -1953,8 +2390,9 @@ int       getifaddrs( struct ifaddrs **outAddrs )
        // 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 );
-       require_action( sock != INVALID_SOCKET, exit, err = WSAEMFILE );
-       
+       err = translate_errno( IsValidSocket( sock ), errno_compat(), kUnknownErr );
+       require_noerr( err, exit );
+               
        n = 0;
        size = 16 * sizeof( INTERFACE_INFO );
        for( ;; )
@@ -1978,11 +2416,15 @@ int     getifaddrs( struct ifaddrs **outAddrs )
        check( ( actualSize % sizeof( INTERFACE_INFO ) ) == 0 );
        n = (int)( actualSize / sizeof( INTERFACE_INFO ) );
        
-       // Process the raw interface list and build a linked list of interfaces.
+       // Process the raw interface list and build a linked list of IPv4 interfaces.
        
        for( i = 0; i < n; ++i )
        {
                ifInfo = &buffer[ i ];
+               if( ifInfo->iiAddress.Address.sa_family != AF_INET )
+               {
+                       continue;
+               }
                
                ifa = (struct ifaddrs *) calloc( 1, sizeof( struct ifaddrs ) );
                require_action( ifa, exit, err = WSAENOBUFS );
@@ -1990,55 +2432,157 @@ int    getifaddrs( struct ifaddrs **outAddrs )
                *next = ifa;
                next  = &ifa->ifa_next;
                
-               // Fetch the name. $$$ TO DO: Get the real name of the interface.
+               // Get the name.
                
                ifa->ifa_name = (char *) malloc( 16 );
                require_action( ifa->ifa_name, exit, err = WSAENOBUFS );
                sprintf( ifa->ifa_name, "%d", i + 1 );
                
-               // Fetch interface flags.
+               // Get interface flags.
                
                ifa->ifa_flags = (u_int) ifInfo->iiFlags;
                
-               // Fetch addresses.
+               // Get addresses.
                
                switch( ifInfo->iiAddress.Address.sa_family )
                {
                        case AF_INET:
-                               sinptr4 = &ifInfo->iiAddress.AddressIn;
-                               ifa->ifa_addr = (struct sockaddr *) calloc( 1, sizeof( *sinptr4 ) );
-                               require_action( ifa->ifa_addr, exit, err = WSAENOBUFS );
-                               memcpy( ifa->ifa_addr, sinptr4, sizeof( *sinptr4 ) );
-                       
-                               if( ifInfo->iiNetmask.Address.sa_family == AF_INET )
-                               {
-                                       sinptr4 = &ifInfo->iiNetmask.AddressIn;
-                                       ifa->ifa_netmask = (struct sockaddr *) calloc( 1, sizeof( *sinptr4 ) );
-                                       require_action( ifa->ifa_netmask, exit, err = WSAENOBUFS );
-                                       memcpy( ifa->ifa_netmask, sinptr4, sizeof( *sinptr4 ) );
-                               }
+                       {
+                               struct sockaddr_in *            sa4;
                                
-                               if( ifInfo->iiBroadcastAddress.Address.sa_family == AF_INET )
-                               {
-                                       sinptr4 = &ifInfo->iiBroadcastAddress.AddressIn;
-                                       ifa->ifa_broadaddr = (struct sockaddr *) calloc( 1, sizeof( *sinptr4 ) );
-                                       require_action( ifa->ifa_broadaddr, exit, err = WSAENOBUFS );
-                                       memcpy( ifa->ifa_broadaddr, sinptr4, sizeof( *sinptr4 ) );
-                               }
+                               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 ) );
                                break;
+                       }
                        
-                       case AF_INET6:
-                               sinptr6 = &ifInfo->iiAddress.AddressIn6;
-                               ifa->ifa_addr = (struct sockaddr *) calloc( 1, sizeof( *sinptr6 ) );
+                       default:
+                               break;
+               }
+               
+               // 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 );
+}
+#endif // !TARGET_OS_WINDOWS_CE )
+
+#if( TARGET_OS_WINDOWS_CE )
+//===========================================================================================================================
+//     getifaddrs_ce
+//===========================================================================================================================
+
+mDNSlocal int  getifaddrs_ce( struct ifaddrs **outAddrs )
+{
+       int                                                     err;
+       SocketRef                                       sock;
+       DWORD                                           size;
+       void *                                          buffer;
+       SOCKET_ADDRESS_LIST *           addressList;
+       struct ifaddrs *                        head;
+       struct ifaddrs **                       next;
+       struct ifaddrs *                        ifa;
+       int                                                     n;
+       int                                                     i;
+
+       sock    = kInvalidSocketRef;
+       buffer  = NULL;
+       head    = NULL;
+       next    = &head;
+       
+       // Open a temporary socket because one is needed to use WSAIoctl (we'll close it before exiting this function).
+       
+       sock = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
+       err = translate_errno( IsValidSocket( sock ), errno_compat(), kUnknownErr );
+       require_noerr( err, exit );
+               
+       // Call WSAIoctl with SIO_ADDRESS_LIST_QUERY and pass a null buffer. This call will fail, but the size needed to 
+       // for the request will be filled in. Once we know the size, allocate a buffer to hold the entire list.
+       //
+       // NOTE: Due to a bug in Windows CE, the size returned by WSAIoctl is not enough so double it as a workaround.
+       
+       size = 0;
+       WSAIoctl( sock, SIO_ADDRESS_LIST_QUERY, NULL, 0, NULL, 0, &size, NULL, NULL );
+       require_action( size > 0, exit, err = -1 );
+       size *= 2;
+       
+       buffer = calloc( 1, size );
+       require_action( buffer, exit, err = -1 );
+       
+       // We now know the size of the list and have a buffer to hold so call WSAIoctl again to get it.
+       
+       err = WSAIoctl( sock, SIO_ADDRESS_LIST_QUERY, NULL, 0, buffer, size, &size, NULL, NULL );
+       require_noerr( err, exit );
+       addressList = (SOCKET_ADDRESS_LIST *) buffer;
+       
+       // Process the raw interface list and build a linked list of interfaces.
+       //
+       // NOTE: Due to a bug in Windows CE, the iAddressCount field is always 0 so use 1 in that case.
+       
+       n = addressList->iAddressCount;
+       if( n == 0 )
+       {
+               n = 1;
+       }
+       for( i = 0; i < n; ++i )
+       {
+               ifa = (struct ifaddrs *) calloc( 1, sizeof( struct ifaddrs ) );
+               require_action( ifa, exit, err = WSAENOBUFS );
+               
+               *next = ifa;
+               next  = &ifa->ifa_next;
+               
+               // Get the name.
+               
+               ifa->ifa_name = (char *) malloc( 16 );
+               require_action( ifa->ifa_name, exit, err = WSAENOBUFS );
+               sprintf( ifa->ifa_name, "%d", i + 1 );
+               
+               // Get flags. Note: SIO_ADDRESS_LIST_QUERY does not report flags so just fake IFF_UP and IFF_MULTICAST.
+               
+               ifa->ifa_flags = IFF_UP | IFF_MULTICAST;
+               
+               // Get addresses.
+               
+               switch( addressList->Address[ i ].lpSockaddr->sa_family )
+               {
+                       case AF_INET:
+                       {
+                               struct sockaddr_in *            sa4;
+                               
+                               sa4 = (struct sockaddr_in *) addressList->Address[ i ].lpSockaddr;
+                               ifa->ifa_addr = (struct sockaddr *) calloc( 1, sizeof( *sa4 ) );
                                require_action( ifa->ifa_addr, exit, err = WSAENOBUFS );
-                               memcpy( ifa->ifa_addr, sinptr6, sizeof( *sinptr6 ) );
+                               memcpy( ifa->ifa_addr, sa4, sizeof( *sa4 ) );
                                break;
+                       }
                        
                        default:
-                               sa = &ifInfo->iiAddress.Address;
-                               ifa->ifa_addr = (struct sockaddr *) calloc( 1, sizeof( *sa ) );
-                               require_action( ifa->ifa_addr, exit, err = WSAENOBUFS );
-                               memcpy( ifa->ifa_addr, sa, sizeof( *sa ) );
                                break;
                }
        }
@@ -2067,20 +2611,20 @@ exit:
        }
        return( err );
 }
-#endif // !defined( _WIN32_WCE ) )
+#endif // TARGET_OS_WINDOWS_CE )
 
 //===========================================================================================================================
 //     freeifaddrs
 //===========================================================================================================================
 
-void   freeifaddrs( struct ifaddrs *inAddrs )
+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 = inAddrs; p; p = q )
+       for( p = inIFAs; p; p = q )
        {
                q = p->ifa_next;
                
@@ -2118,89 +2662,132 @@ void   freeifaddrs( struct ifaddrs *inAddrs )
        }
 }
 
-#if( !defined( _WIN32_WCE ) )
 //===========================================================================================================================
-//     sock_pton
+//     CanReceiveUnicast
 //===========================================================================================================================
 
-int    sock_pton( const char *inString, int inFamily, void *outAddr, size_t inAddrSize, size_t *outAddrSize )
+mDNSlocal mDNSBool     CanReceiveUnicast( void )
 {
-       int             err;
-       int             size;
-       
-       if( inAddrSize == 0 )
-       {
-               if( inFamily == AF_INET )
-               {
-                       inAddrSize = sizeof( struct sockaddr_in );
-               }
-               else if( inFamily == AF_INET6 )
-               {
-                       inAddrSize = sizeof( struct sockaddr_in6 );
-               }
-               else
-               {
-                       err = WSAEAFNOSUPPORT;
-                       goto exit;
-               }
-       }
-       size = (int) inAddrSize;
+       mDNSBool                                ok;
+       SocketRef                               sock;
+       struct sockaddr_in              addr;
        
-       err = WSAStringToAddressA( (char *) inString, inFamily, NULL, (LPSOCKADDR) outAddr, &size );
-       if( err != 0 ) goto exit;
+       // Try to bind to the port without the SO_REUSEADDR option to test if someone else has already bound to it.
        
-       if( outAddrSize )
+       sock = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
+       check_translated_errno( IsValidSocket( sock ), errno_compat(), kUnknownErr );
+       ok = IsValidSocket( sock );
+       if( ok )
        {
-               *outAddrSize = (size_t) size;
+               memset( &addr, 0, 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 );
        }
        
-exit:
-       return( err );
+       dlog( kDebugLevelInfo, DEBUG_NAME "Unicast UDP responses %s\n", ok ? "okay" : "*not allowed*" );
+       return( ok );
 }
 
 //===========================================================================================================================
-//     sock_ntop
+//     GetWindowsVersionString
 //===========================================================================================================================
 
-char * sock_ntop( const void *inAddr, size_t inAddrSize, char *inBuffer, size_t inBufferSize )
+mDNSlocal OSStatus     GetWindowsVersionString( char *inBuffer, size_t inBufferSize )
 {
-       DWORD           size;
-       int                     err;
-       DWORD           stringSize;
+#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( inAddrSize == 0 )
+       if( ( platformID == VER_PLATFORM_WIN32_WINDOWS ) && ( majorVersion == 4 ) )
        {
-               const struct sockaddr *         addr;
-               
-               addr = (const struct sockaddr *) inAddr;
-               if( addr->sa_family == AF_INET )
+               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 ) ) )
                {
-                       size = sizeof( struct sockaddr_in );
+                       versionString   = "Windows 98 SP1";
                }
-               else if( addr->sa_family == AF_INET6 )
+               else if( ( minorVersion == 10 ) && ( buildNumber >= 2183 ) )
                {
-                       size = sizeof( struct sockaddr_in6 );
+                       versionString   = "Windows 98 SE";
                }
-               else
+               else if( minorVersion == 90 )
                {
-                       WSASetLastError( WSAEAFNOSUPPORT );
-                       inBuffer = NULL;
-                       goto exit;
+                       versionString   = "Windows ME";
                }
        }
-       else
+       else if( platformID == VER_PLATFORM_WIN32_NT )
        {
-               size = (DWORD) inAddrSize;
+               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";
+               }
        }
-       
-       stringSize = (DWORD) inBufferSize;
-       err = WSAAddressToStringA( (LPSOCKADDR) inAddr, size, NULL, inBuffer, &stringSize );
-       if( err )
+       else if( platformID == VER_PLATFORM_WIN32_CE )
        {
-               inBuffer = NULL;
+               versionString           = "Windows CE";
        }
        
 exit:
-       return( inBuffer );
+       if( inBuffer && ( inBufferSize > 0 ) )
+       {
+               inBufferSize -= 1;
+               strncpy( inBuffer, versionString, inBufferSize );
+               inBuffer[ inBufferSize ] = '\0';
+       }
+       return( err );
 }
-#endif // !defined( _WIN32_WCE )
index 499f6a6ee634a84eb0277cc8e2cb6fec2f940e6f..946fd7e702350bd3b2cc8c5990bad1269891df04 100755 (executable)
@@ -1,8 +1,10 @@
 /*
- * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
     Change History (most recent first):
     
 $Log: mDNSWin32.h,v $
-Revision 1.9.2.1  2004/04/03 05:26:08  bradley
-Integrated changes from TOT to remove legacy port 53 support.
+Revision 1.11  2004/01/30 02:44:32  bradley
+Added support for IPv6 (v4 & v6, v4-only, v6-only, AAAA over v4, etc.). Added support for DNS-SD
+InterfaceID<->Interface Index mappings. Added support for loopback usage when no other interfaces
+are available. Updated unlock signaling to no longer require timenow - NextScheduledTime to be >= 0
+(it no longer is). Added unicast-capable detection to avoid using unicast when there is other mDNS
+software running on the same machine. Removed unneeded sock_XtoY routines. Added support for
+reporting HINFO records with the  Windows and mDNSResponder version information.
 
 Revision 1.10  2003/10/24 23:23:02  bradley
 Removed legacy port 53 support as it is no longer needed.
@@ -67,13 +74,11 @@ Multicast DNS platform plugin for Win32
 #ifndef        __MDNS_WIN32__
 #define        __MDNS_WIN32__
 
-#if( !defined( WIN32_LEAN_AND_MEAN ) )
-       #define WIN32_LEAN_AND_MEAN             // Needed to avoid redefinitions by Windows interfaces.
-#endif
+#include       "CommonServices.h"
 
-#include       <windows.h>
-#include       <winsock2.h>
-#include       <Ws2tcpip.h>
+#if( !defined( _WIN32_WCE ) )
+       #include        <mswsock.h>
+#endif
 
 #include       "mDNSClientAPI.h"
 
@@ -81,14 +86,6 @@ Multicast DNS platform plugin for Win32
        extern "C" {
 #endif
 
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @typedef        SocketRef
-
-       @abstract       Socket file descriptor alias for improved readability.
-*/
-
-typedef SOCKET         SocketRef;
-
 //---------------------------------------------------------------------------------------------------------------------------
 /*!    @struct         mDNSInterfaceData
 
@@ -99,18 +96,17 @@ typedef struct      mDNSInterfaceData       mDNSInterfaceData;
 struct mDNSInterfaceData
 {
        mDNSInterfaceData *                     next;
-       char                                            name[ 256 ];
+       char                                            name[ 128 ];
+       uint32_t                                        index;
+       uint32_t                                        scopeID;
        SocketRef                                       sock;
+#if( !defined( _WIN32_WCE ) )
+       LPFN_WSARECVMSG                         wsaRecvMsgFunctionPtr;
+#endif
        HANDLE                                          readPendingEvent;
-       NetworkInterfaceInfo            hostSet;
+       NetworkInterfaceInfo            interfaceInfo;
+       mDNSAddr                                        defaultAddr;
        mDNSBool                                        hostRegistered;
-       
-       int                                                     sendMulticastCounter;
-       int                                                     sendUnicastCounter;
-       int                                                     sendErrorCounter;
-       
-       int                                                     recvCounter;
-       int                                                     recvErrorCounter;
 };
 
 //---------------------------------------------------------------------------------------------------------------------------
@@ -129,8 +125,7 @@ struct      mDNS_PlatformSupport_struct
        HANDLE                                          wakeupEvent;
        HANDLE                                          initEvent;
        mStatus                                         initStatus;
-       
-       SocketRef                                       interfaceListChangedSocketRef;
+       SocketRef                                       interfaceListChangedSocket;
        int                                                     interfaceCount;
        mDNSInterfaceData *                     interfaceList;
        DWORD                                           threadID;
@@ -152,6 +147,12 @@ struct ifaddrs
        struct sockaddr *       ifa_broadaddr;
        struct sockaddr *       ifa_dstaddr;
        void *                          ifa_data;
+       
+       struct
+       {
+               uint32_t                index;
+       
+       }       ifa_extra;
 };
 
 //---------------------------------------------------------------------------------------------------------------------------
@@ -170,26 +171,6 @@ int        getifaddrs( struct ifaddrs **outAddrs );
 
 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