From 7f0064bd55e3fa98568d2c359429ff8a38b23a6c Mon Sep 17 00:00:00 2001
From: Apple <opensource@apple.com>
Date: Wed, 15 Dec 2004 21:58:48 +0000
Subject: [PATCH] mDNSResponder-87.tar.gz

---
 Clients/DNS-SD.xcode/project.pbxproj          |   14 +-
 Clients/DNSServiceBrowser.NET/App.ico         |  Bin 0 -> 1078 bytes
 Clients/DNSServiceBrowser.NET/AssemblyInfo.cs |   89 +
 .../DNSServiceBrowser.NET.csproj              |  117 +
 .../DNSServiceBrowser.cs                      |  745 ++++
 .../DNSServiceBrowser.resx                    |  102 +
 Clients/DNSServiceBrowser.m                   |    2 -
 ...on-Info.plist => DNSServiceReg-Info.plist} |    2 +-
 ...SServiceRegistration.m => DNSServiceReg.m} |    4 +-
 .../classes.nib                               |    0
 .../info.nib                                  |    0
 .../objects.nib                               |  Bin
 Clients/ExplorerPlugin/About.cpp              |   63 +
 Clients/ExplorerPlugin/About.h                |   27 +
 .../ExplorerPlugin/ClassFactory.cpp           |   10 +-
 .../ExplorerPlugin/ClassFactory.h             |   10 +-
 .../ExplorerPlugin/ExplorerBar.cpp            |  107 +-
 .../ExplorerPlugin/ExplorerBar.h              |   19 +-
 .../ExplorerPlugin/ExplorerBarWindow.cpp      |  373 +-
 .../ExplorerPlugin/ExplorerBarWindow.h        |   55 +-
 .../ExplorerPlugin/ExplorerPlugin.cpp         |   71 +-
 .../ExplorerPlugin/ExplorerPlugin.def         |    8 +-
 .../ExplorerPlugin/ExplorerPlugin.h           |   10 +-
 .../ExplorerPlugin/ExplorerPlugin.rc          |   70 +-
 .../ExplorerPlugin/ExplorerPlugin.vcproj      |  185 +-
 .../ExplorerPlugin/LoginDialog.cpp            |   10 +-
 .../ExplorerPlugin/LoginDialog.h              |   10 +-
 .../ExplorerPlugin/ReadMe.txt                 |    2 +-
 .../ExplorerPlugin/Resource.h                 |   13 +-
 .../ExplorerPlugin/StdAfx.cpp                 |   10 +-
 .../ExplorerPlugin/StdAfx.h                   |   10 +-
 Clients/ExplorerPlugin/res/about.bmp          |  Bin 0 -> 137944 bytes
 Clients/ExplorerPlugin/res/button-2k.ico      |  Bin 0 -> 10342 bytes
 Clients/ExplorerPlugin/res/button-xp.ico      |  Bin 0 -> 7574 bytes
 Clients/ExplorerPlugin/res/cold.ico           |  Bin 0 -> 10342 bytes
 Clients/ExplorerPlugin/res/hot.ico            |  Bin 0 -> 10342 bytes
 Clients/ExplorerPlugin/res/logo.bmp           |  Bin 0 -> 822 bytes
 Clients/Java/BrowserApp.java                  |   74 +-
 Clients/Java/BrowserApp.manifest              |    2 +
 Clients/Java/DNSSDUnitTest.java               |   24 +-
 Clients/Java/SimpleChat.java                  |   78 +-
 Clients/Java/SimpleChat.manifest              |    2 +
 Clients/Java/SwingBrowseListener.java         |   64 +-
 Clients/Java/SwingDomainListener.java         |   64 +-
 Clients/Java/SwingQueryListener.java          |   64 +-
 Clients/Java/SwingResolveListener.java        |   64 +-
 Clients/Java/nmakefile                        |  106 +
 Clients/Makefile                              |   14 +-
 Clients/PrinterSetupWizard/About.cpp          |   31 +
 Clients/PrinterSetupWizard/About.h            |   21 +
 Clients/PrinterSetupWizard/FirstPage.cpp      |   93 +
 Clients/PrinterSetupWizard/FirstPage.h        |   63 +
 Clients/PrinterSetupWizard/FourthPage.cpp     |  143 +
 Clients/PrinterSetupWizard/FourthPage.h       |   71 +
 .../PrinterSetupWizard/PrinterSetupWizard.ncb |    1 +
 .../PrinterSetupWizard/PrinterSetupWizard.rc  |  346 ++
 .../PrinterSetupWizard.vcproj                 |  269 ++
 .../PrinterSetupWizardApp.cpp                 |  117 +
 .../PrinterSetupWizardApp.h                   |   47 +-
 .../PrinterSetupWizardSheet.cpp               | 1085 +++++
 .../PrinterSetupWizardSheet.h                 |  207 +
 Clients/PrinterSetupWizard/ReadMe.txt         |   94 +
 Clients/PrinterSetupWizard/SecondPage.cpp     |  347 ++
 Clients/PrinterSetupWizard/SecondPage.h       |   95 +
 Clients/PrinterSetupWizard/ThirdPage.cpp      | 1224 ++++++
 Clients/PrinterSetupWizard/ThirdPage.h        |  133 +
 Clients/PrinterSetupWizard/UtilTypes.h        |  144 +
 Clients/PrinterSetupWizard/res/Info.ico       |  Bin 0 -> 23558 bytes
 .../PrinterSetupWizard/res/NetworkPrinter.ico |  Bin 0 -> 77214 bytes
 Clients/PrinterSetupWizard/res/Print.ico      |  Bin 0 -> 77214 bytes
 .../res/PrinterSetupWizard.ico                |  Bin 0 -> 77214 bytes
 .../res/PrinterSetupWizard.manifest           |   22 +
 .../res/PrinterSetupWizard.rc2                |   13 +
 Clients/PrinterSetupWizard/res/Thumbs.db      |  Bin 0 -> 6144 bytes
 Clients/PrinterSetupWizard/res/about.bmp      |  Bin 0 -> 254802 bytes
 .../PrinterSetupWizard/res/banner_icon.bmp    |  Bin 0 -> 7308 bytes
 Clients/PrinterSetupWizard/res/watermark.bmp  |  Bin 0 -> 162908 bytes
 Clients/PrinterSetupWizard/resource.h         |   74 +
 Clients/PrinterSetupWizard/stdafx.cpp         |   34 +
 Clients/PrinterSetupWizard/stdafx.h           |   71 +
 Clients/SimpleChat.NET/App.ico                |  Bin 0 -> 1078 bytes
 Clients/SimpleChat.NET/AssemblyInfo.cs        |   90 +
 Clients/SimpleChat.NET/SimpleChat.NET.csproj  |  116 +
 Clients/SimpleChat.NET/SimpleChat.cs          |  757 ++++
 Clients/SimpleChat.NET/SimpleChat.resx        |  102 +
 Clients/dns-sd.c                              |  492 ++-
 Makefile                                      |    2 +-
 README.txt                                    |   23 +
 mDNSCore/DNSCommon.c                          |  538 ++-
 mDNSCore/DNSCommon.h                          |  139 +-
 mDNSCore/DNSDigest.c                          |   71 +-
 mDNSCore/mDNS.c                               | 2073 ++++++----
 mDNSCore/mDNSDebug.h                          |   10 +-
 .../{mDNSClientAPI.h => mDNSEmbeddedAPI.h}    |  923 ++++-
 mDNSCore/uDNS.c                               | 3532 ++++++++++++-----
 mDNSCore/uDNS.h                               |   95 +-
 mDNSMacOS9/CarbonResource.r                   |    2 -
 mDNSMacOS9/Mac OS Test Responder.c            |   16 +-
 mDNSMacOS9/Mac OS Test Searcher.c             |   24 +-
 mDNSMacOS9/Responder.c                        |    2 -
 mDNSMacOS9/Searcher.c                         |    2 -
 mDNSMacOS9/SubTypeTester.c                    |  248 ++
 mDNSMacOS9/mDNS.mcp                           |  Bin 967336 -> 1002330 bytes
 mDNSMacOS9/mDNSLibrary.c                      |   10 +-
 mDNSMacOS9/mDNSLibraryLoader.c                |    2 -
 mDNSMacOS9/mDNSLibraryResources.r             |   51 +-
 mDNSMacOS9/mDNSMacOS9.c                       |   84 +-
 mDNSMacOS9/mDNSMacOS9.h                       |    2 -
 mDNSMacOS9/mDNSPrefix.h                       |   13 +-
 mDNSMacOSX/DNSServiceDiscoveryDefines.h       |    6 +-
 mDNSMacOSX/DNSServiceDiscoveryReply.defs      |    2 -
 mDNSMacOSX/DNSServiceDiscoveryRequest.defs    |    5 +-
 mDNSMacOSX/LegacyNATTraversal.c               | 3010 ++++++++++++++
 mDNSMacOSX/SamplemDNSClient.c                 |   37 +-
 mDNSMacOSX/daemon.c                           | 1347 ++++---
 mDNSMacOSX/{CFSocket.c => mDNSMacOSX.c}       | 1946 ++++++---
 mDNSMacOSX/mDNSMacOSX.h                       |   62 +-
 .../{CFSocketPuma.c => mDNSMacOSXPuma.c}      |   11 +-
 .../mDNSResponder.pbproj/project.pbxproj      |  514 ++-
 mDNSPosix/Client.c                            |   25 +-
 mDNSPosix/ExampleClientApp.c                  |   23 +-
 mDNSPosix/ExampleClientApp.h                  |    8 +-
 mDNSPosix/Identify.c                          |   80 +-
 mDNSPosix/Makefile                            |  275 +-
 mDNSPosix/NetMonitor.c                        |   90 +-
 mDNSPosix/PosixDaemon.c                       |  351 +-
 mDNSPosix/ProxyResponder.c                    |   87 +-
 mDNSPosix/ReadMe.txt                          |   32 +-
 mDNSPosix/Responder.c                         |  314 +-
 mDNSPosix/Services.txt                        |    9 +-
 mDNSPosix/dnsextd.c                           | 1983 +++++++++
 mDNSPosix/libnss_mdns.8                       |  149 +
 mDNSPosix/mDNSPosix.c                         |  184 +-
 mDNSPosix/mDNSPosix.h                         |   10 +-
 mDNSPosix/mDNSUNP.c                           |  129 +-
 mDNSPosix/mDNSUNP.h                           |   22 +-
 mDNSPosix/mdnsd.sh                            |   14 +-
 mDNSPosix/nss_ReadMe.txt                      |  125 +
 mDNSPosix/nss_mdns.c                          | 2732 +++++++++++++
 mDNSPosix/nss_mdns.conf                       |    7 +
 mDNSPosix/nss_mdns.conf.5                     |  136 +
 mDNSShared/GenLinkedList.c                    |    2 -
 mDNSShared/GenLinkedList.h                    |    2 -
 mDNSShared/Java/BaseListener.java             |    2 -
 mDNSShared/Java/BrowseListener.java           |    2 -
 mDNSShared/Java/DNSRecord.java                |   27 +-
 mDNSShared/Java/DNSSD.java                    |   65 +-
 mDNSShared/Java/DNSSDException.java           |    2 -
 mDNSShared/Java/DNSSDRegistration.java        |   51 +-
 mDNSShared/Java/DNSSDService.java             |    2 -
 mDNSShared/Java/DomainListener.java           |    2 -
 mDNSShared/Java/JNISupport.c                  |  278 +-
 mDNSShared/Java/QueryListener.java            |    2 -
 mDNSShared/Java/RegisterListener.java         |    2 -
 mDNSShared/Java/ResolveListener.java          |    2 -
 mDNSShared/Java/TXTRecord.java                |  102 +-
 mDNSShared/PlatformCommon.c                   |  131 +
 mDNSShared/PlatformCommon.h                   |   36 +
 mDNSShared/dns-sd.1                           |  208 +
 mDNSShared/dns_sd.h                           |  566 ++-
 mDNSShared/dnsextd.8                          |   80 +
 mDNSShared/dnssd_clientlib.c                  |   70 +-
 mDNSShared/dnssd_clientshim.c                 |   40 +-
 mDNSShared/dnssd_clientstub.c                 |  948 +++--
 mDNSShared/dnssd_ipc.c                        |  209 +-
 mDNSShared/dnssd_ipc.h                        |  202 +-
 mDNSShared/mDNS.1                             |   69 +-
 mDNSShared/mDNSDebug.c                        |   42 +-
 mDNSShared/mDNSResponder.8                    |    6 +
 mDNSShared/uds_daemon.c                       | 2308 +++++++----
 mDNSShared/uds_daemon.h                       |   61 +-
 mDNSVxWorks/mDNSVxWorks.c                     |  107 +-
 mDNSVxWorks/mDNSVxWorks.h                     |   10 +-
 .../Applications/DNSServiceTest/ToolWin32.mcp |  Bin 284642 -> 0 bytes
 .../ExplorerPlugin/ExplorerPlugin.sln         |   21 -
 mDNSWindows/Applications/NSPTool/Tool.mcp     |  Bin 306146 -> 0 bytes
 .../Applications/SystemService/Service.c      |  829 ----
 .../Applications/SystemService/Service.mcp    |  Bin 299890 -> 0 bytes
 .../SystemService/Service2002.sln             |   21 -
 .../SystemService/Service2002.vcproj          |  196 -
 .../Applications/SystemServiceTest/Tool.mcp   |  Bin 398728 -> 0 bytes
 .../SystemServiceTest/Tool2002.sln            |   21 -
 mDNSWindows/Applications/mdnsNSP/NSP.c        | 1367 -------
 mDNSWindows/Applications/mdnsNSP/NSP.def      |   36 -
 mDNSWindows/Applications/mdnsNSP/NSP.mcp      |  Bin 198118 -> 0 bytes
 mDNSWindows/Applications/mdnsNSP/ReadMe.txt   |   15 -
 mDNSWindows/CommonServices.h                  |    2 -
 mDNSWindows/DLL.NET/AssemblyInfo.cpp          |  100 +
 mDNSWindows/DLL.NET/PString.h                 |   86 +
 .../Resource.h => DLL.NET/Stdafx.cpp}         |   69 +-
 mDNSWindows/DLL.NET/Stdafx.h                  |   40 +
 mDNSWindows/DLL.NET/dnssd_NET.cpp             | 1276 ++++++
 mDNSWindows/DLL.NET/dnssd_NET.h               | 1424 +++++++
 mDNSWindows/DLL.NET/dnssd_NET.ico             |  Bin 0 -> 1078 bytes
 mDNSWindows/DLL.NET/dnssd_NET.rc              |  113 +
 mDNSWindows/DLL.NET/dnssd_NET.vcproj          |  154 +
 mDNSWindows/DLL.NET/resource.h                |    3 +
 mDNSWindows/DLL/dll.aps                       |  Bin 0 -> 18692 bytes
 mDNSWindows/DLL/dll.rc                        |  102 +
 mDNSWindows/{Applications => }/DLL/dllmain.c  |    7 +-
 mDNSWindows/{Applications => }/DLL/dnssd.def  |   23 +-
 mDNSWindows/DLL/dnssd.vcproj                  |  178 +
 mDNSWindows/DLL/resource.h                    |   27 +
 mDNSWindows/DNSSD.c                           | 1720 --------
 mDNSWindows/DNSSD.h                           | 1689 --------
 mDNSWindows/DNSSDDirect.c                     | 1863 ---------
 mDNSWindows/DNSSDDirect.h                     |  285 --
 .../Windows/ApplicationVS2002.sln             |    0
 .../Windows/ApplicationVS2002.vcproj          |    4 +-
 .../Windows/ApplicationVS2003.sln             |    0
 .../Windows/ApplicationVS2003.vcproj          |    4 +-
 .../Windows/Resources/Application.ico         |  Bin
 .../Windows/Resources/Application.rc          |   18 +-
 .../Windows/Resources/Application.rc2         |   10 +-
 .../Windows/Resources/Resource.h              |    0
 .../Windows/Sources/AboutDialog.cpp           |   12 +-
 .../Windows/Sources/AboutDialog.h             |   12 +-
 .../Windows/Sources/Application.cpp           |   12 +-
 .../Windows/Sources/Application.h             |   12 +-
 .../Windows/Sources/ChooserDialog.cpp         |   12 +-
 .../Windows/Sources/ChooserDialog.h           |   12 +-
 .../Windows/Sources/LoginDialog.cpp           |    5 +-
 .../Windows/Sources/LoginDialog.h             |    5 +-
 .../Windows/Sources/StdAfx.cpp                |   12 +-
 .../Windows/Sources/StdAfx.h                  |   12 +-
 .../WindowsCE/Application.vcc                 |    0
 .../WindowsCE/Application.vcp                 |    0
 .../WindowsCE/Application.vcw                 |    0
 .../WindowsCE/Resources/Application.ico       |  Bin
 .../WindowsCE/Resources/Application.rc        |    6 +-
 .../WindowsCE/Resources/Application.rc2       |    0
 .../WindowsCE/Resources/newres.h              |    0
 .../WindowsCE/Resources/resource.h            |    0
 .../WindowsCE/Sources/Application.cpp         |   10 +-
 .../WindowsCE/Sources/Application.h           |   10 +-
 .../WindowsCE/Sources/BrowserDialog.cpp       |   10 +-
 .../WindowsCE/Sources/BrowserDialog.h         |   10 +-
 .../WindowsCE/Sources/StdAfx.cpp              |   10 +-
 .../WindowsCE/Sources/StdAfx.h                |   10 +-
 .../{Applications => }/DNSServiceTest/Tool.c  |   61 +-
 .../DNSServiceTest/ToolPrefixWindows.h        |    5 +-
 .../DNSServiceTest/ToolPrefixWindowsDebug.h   |    5 +-
 mDNSWindows/DNSServiceTest/ToolWin32.mcp      |  Bin 0 -> 127071 bytes
 .../DNSServiceTest/ToolWin32VS2002.sln        |    0
 .../DNSServiceTest/ToolWin32VS2002.vcproj     |    2 +-
 .../DNSServiceTest/ToolWin32VS2003.sln        |    0
 .../DNSServiceTest/ToolWin32VS2003.vcproj     |    2 +-
 mDNSWindows/DNSServices/DNSServiceDiscovery.c |   12 +-
 mDNSWindows/DNSServices/DNSServiceDiscovery.h |    2 -
 mDNSWindows/DNSServices/DNSServices.c         |   38 +-
 mDNSWindows/DNSServices/DNSServices.h         |    9 +-
 mDNSWindows/DebugServices.c                   |   18 +-
 mDNSWindows/DebugServices.h                   |    2 -
 mDNSWindows/Installer.vct                     |  Bin 40028 -> 0 bytes
 mDNSWindows/Installer/Main.ism                |  Bin 0 -> 195584 bytes
 mDNSWindows/Installer/SDK.ism                 |  Bin 0 -> 189952 bytes
 .../Service.rc => Java/jdns_sd.rc}            |   67 +-
 mDNSWindows/{Applications => }/Java/makefile  |   27 +-
 mDNSWindows/NSPTool/NSPTool.aps               |  Bin 0 -> 34296 bytes
 .../NSPTool/Tool.c => NSPTool/NSPTool.c}      |   43 +-
 mDNSWindows/NSPTool/NSPTool.rc                |  102 +
 .../dnssd.vcproj => NSPTool/NSPTool.vcproj}   |  299 +-
 .../{Applications => }/NSPTool/Prefix.h       |    5 +-
 mDNSWindows/NSPTool/resource.h                |   27 +
 mDNSWindows/README.txt                        |   10 +-
 mDNSWindows/RMxClient.c                       | 1302 ------
 mDNSWindows/RMxClient.h                       |  307 --
 mDNSWindows/RMxCommon.c                       | 1501 -------
 mDNSWindows/RMxCommon.h                       |  662 ---
 mDNSWindows/RMxServer.c                       | 1656 --------
 mDNSWindows/RMxServer.h                       |  119 -
 .../SystemService/EventLogMessages.bin        |  Bin
 mDNSWindows/SystemService/Firewall.cpp        |  330 ++
 mDNSWindows/SystemService/Firewall.h          |   59 +
 .../{Applications => }/SystemService/Prefix.h |    5 +-
 mDNSWindows/SystemService/Service.aps         |  Bin 0 -> 3388 bytes
 mDNSWindows/SystemService/Service.c           | 1892 +++++++++
 mDNSWindows/SystemService/Service.mcp         |  Bin 0 -> 126095 bytes
 mDNSWindows/SystemService/Service.rc          |  113 +
 mDNSWindows/SystemService/Service.vcproj      |  199 +
 mDNSWindows/SystemService/resource.h          |   17 +
 mDNSWindows/SystemService/resrc1.h            |   15 +
 .../SystemServiceTest/Prefix.h                |    5 +-
 .../SystemServiceTest/Tool.c                  |   10 +-
 .../Tool.mcp}                                 |  Bin 198118 -> 210145 bytes
 .../SystemServiceTest/Tool2002.vcproj         |    0
 mDNSWindows/WinServices.cpp                   |   80 +
 mDNSWindows/WinServices.h                     |   47 +
 mDNSWindows/WinVersRes.h                      |   90 +
 mDNSWindows/mDNSWin32.c                       |  467 ++-
 mDNSWindows/mDNSWin32.h                       |   78 +-
 mDNSWindows/mdnsNSP/ReadMe.txt                |   15 +
 mDNSWindows/mdnsNSP/mdnsNSP.aps               |  Bin 0 -> 34332 bytes
 .../{Applications => }/mdnsNSP/mdnsNSP.c      |  127 +-
 .../{Applications => }/mdnsNSP/mdnsNSP.def    |   12 +-
 mDNSWindows/mdnsNSP/mdnsNSP.rc                |  104 +
 mDNSWindows/mdnsNSP/mdnsNSP.vcproj            |  160 +
 mDNSWindows/mdnsNSP/resource.h                |   27 +
 298 files changed, 37799 insertions(+), 20430 deletions(-)
 create mode 100755 Clients/DNSServiceBrowser.NET/App.ico
 create mode 100755 Clients/DNSServiceBrowser.NET/AssemblyInfo.cs
 create mode 100755 Clients/DNSServiceBrowser.NET/DNSServiceBrowser.NET.csproj
 create mode 100755 Clients/DNSServiceBrowser.NET/DNSServiceBrowser.cs
 create mode 100755 Clients/DNSServiceBrowser.NET/DNSServiceBrowser.resx
 rename Clients/{DNSServiceRegistration-Info.plist => DNSServiceReg-Info.plist} (95%)
 rename Clients/{DNSServiceRegistration.m => DNSServiceReg.m} (99%)
 rename Clients/{DNSServiceRegistration.nib => DNSServiceReg.nib}/classes.nib (100%)
 rename Clients/{DNSServiceRegistration.nib => DNSServiceReg.nib}/info.nib (100%)
 rename Clients/{DNSServiceRegistration.nib => DNSServiceReg.nib}/objects.nib (100%)
 create mode 100644 Clients/ExplorerPlugin/About.cpp
 create mode 100644 Clients/ExplorerPlugin/About.h
 rename {mDNSWindows/Applications => Clients}/ExplorerPlugin/ClassFactory.cpp (95%)
 rename {mDNSWindows/Applications => Clients}/ExplorerPlugin/ClassFactory.h (88%)
 rename {mDNSWindows/Applications => Clients}/ExplorerPlugin/ExplorerBar.cpp (84%)
 rename {mDNSWindows/Applications => Clients}/ExplorerPlugin/ExplorerBar.h (83%)
 rename {mDNSWindows/Applications => Clients}/ExplorerPlugin/ExplorerBarWindow.cpp (73%)
 rename {mDNSWindows/Applications => Clients}/ExplorerPlugin/ExplorerBarWindow.h (83%)
 rename {mDNSWindows/Applications => Clients}/ExplorerPlugin/ExplorerPlugin.cpp (83%)
 rename {mDNSWindows/Applications => Clients}/ExplorerPlugin/ExplorerPlugin.def (82%)
 rename {mDNSWindows/Applications => Clients}/ExplorerPlugin/ExplorerPlugin.h (86%)
 rename {mDNSWindows/Applications => Clients}/ExplorerPlugin/ExplorerPlugin.rc (66%)
 rename {mDNSWindows/Applications => Clients}/ExplorerPlugin/ExplorerPlugin.vcproj (58%)
 rename {mDNSWindows/Applications => Clients}/ExplorerPlugin/LoginDialog.cpp (93%)
 rename {mDNSWindows/Applications => Clients}/ExplorerPlugin/LoginDialog.h (88%)
 rename {mDNSWindows/Applications => Clients}/ExplorerPlugin/ReadMe.txt (82%)
 rename {mDNSWindows/Applications => Clients}/ExplorerPlugin/Resource.h (57%)
 rename {mDNSWindows/Applications => Clients}/ExplorerPlugin/StdAfx.cpp (81%)
 rename {mDNSWindows/Applications => Clients}/ExplorerPlugin/StdAfx.h (86%)
 create mode 100644 Clients/ExplorerPlugin/res/about.bmp
 create mode 100755 Clients/ExplorerPlugin/res/button-2k.ico
 create mode 100755 Clients/ExplorerPlugin/res/button-xp.ico
 create mode 100644 Clients/ExplorerPlugin/res/cold.ico
 create mode 100644 Clients/ExplorerPlugin/res/hot.ico
 create mode 100644 Clients/ExplorerPlugin/res/logo.bmp
 create mode 100644 Clients/Java/BrowserApp.manifest
 create mode 100644 Clients/Java/SimpleChat.manifest
 create mode 100644 Clients/Java/nmakefile
 create mode 100644 Clients/PrinterSetupWizard/About.cpp
 create mode 100644 Clients/PrinterSetupWizard/About.h
 create mode 100644 Clients/PrinterSetupWizard/FirstPage.cpp
 create mode 100644 Clients/PrinterSetupWizard/FirstPage.h
 create mode 100644 Clients/PrinterSetupWizard/FourthPage.cpp
 create mode 100644 Clients/PrinterSetupWizard/FourthPage.h
 create mode 100644 Clients/PrinterSetupWizard/PrinterSetupWizard.ncb
 create mode 100644 Clients/PrinterSetupWizard/PrinterSetupWizard.rc
 create mode 100644 Clients/PrinterSetupWizard/PrinterSetupWizard.vcproj
 create mode 100644 Clients/PrinterSetupWizard/PrinterSetupWizardApp.cpp
 rename mDNSWindows/Applications/mdnsNSP/Prefix.h => Clients/PrinterSetupWizard/PrinterSetupWizardApp.h (62%)
 create mode 100644 Clients/PrinterSetupWizard/PrinterSetupWizardSheet.cpp
 create mode 100644 Clients/PrinterSetupWizard/PrinterSetupWizardSheet.h
 create mode 100644 Clients/PrinterSetupWizard/ReadMe.txt
 create mode 100644 Clients/PrinterSetupWizard/SecondPage.cpp
 create mode 100644 Clients/PrinterSetupWizard/SecondPage.h
 create mode 100644 Clients/PrinterSetupWizard/ThirdPage.cpp
 create mode 100644 Clients/PrinterSetupWizard/ThirdPage.h
 create mode 100644 Clients/PrinterSetupWizard/UtilTypes.h
 create mode 100644 Clients/PrinterSetupWizard/res/Info.ico
 create mode 100644 Clients/PrinterSetupWizard/res/NetworkPrinter.ico
 create mode 100644 Clients/PrinterSetupWizard/res/Print.ico
 create mode 100644 Clients/PrinterSetupWizard/res/PrinterSetupWizard.ico
 create mode 100644 Clients/PrinterSetupWizard/res/PrinterSetupWizard.manifest
 create mode 100644 Clients/PrinterSetupWizard/res/PrinterSetupWizard.rc2
 create mode 100644 Clients/PrinterSetupWizard/res/Thumbs.db
 create mode 100644 Clients/PrinterSetupWizard/res/about.bmp
 create mode 100644 Clients/PrinterSetupWizard/res/banner_icon.bmp
 create mode 100644 Clients/PrinterSetupWizard/res/watermark.bmp
 create mode 100644 Clients/PrinterSetupWizard/resource.h
 create mode 100644 Clients/PrinterSetupWizard/stdafx.cpp
 create mode 100644 Clients/PrinterSetupWizard/stdafx.h
 create mode 100755 Clients/SimpleChat.NET/App.ico
 create mode 100755 Clients/SimpleChat.NET/AssemblyInfo.cs
 create mode 100755 Clients/SimpleChat.NET/SimpleChat.NET.csproj
 create mode 100755 Clients/SimpleChat.NET/SimpleChat.cs
 create mode 100755 Clients/SimpleChat.NET/SimpleChat.resx
 rename mDNSCore/{mDNSClientAPI.h => mDNSEmbeddedAPI.h} (72%)
 create mode 100644 mDNSMacOS9/SubTypeTester.c
 create mode 100644 mDNSMacOSX/LegacyNATTraversal.c
 rename mDNSMacOSX/{CFSocket.c => mDNSMacOSX.c} (53%)
 rename mDNSMacOSX/{CFSocketPuma.c => mDNSMacOSXPuma.c} (96%)
 create mode 100644 mDNSPosix/dnsextd.c
 create mode 100755 mDNSPosix/libnss_mdns.8
 create mode 100755 mDNSPosix/nss_ReadMe.txt
 create mode 100755 mDNSPosix/nss_mdns.c
 create mode 100755 mDNSPosix/nss_mdns.conf
 create mode 100755 mDNSPosix/nss_mdns.conf.5
 create mode 100644 mDNSShared/PlatformCommon.c
 create mode 100644 mDNSShared/PlatformCommon.h
 create mode 100644 mDNSShared/dns-sd.1
 create mode 100644 mDNSShared/dnsextd.8
 delete mode 100644 mDNSWindows/Applications/DNSServiceTest/ToolWin32.mcp
 delete mode 100644 mDNSWindows/Applications/ExplorerPlugin/ExplorerPlugin.sln
 delete mode 100644 mDNSWindows/Applications/NSPTool/Tool.mcp
 delete mode 100644 mDNSWindows/Applications/SystemService/Service.c
 delete mode 100644 mDNSWindows/Applications/SystemService/Service.mcp
 delete mode 100644 mDNSWindows/Applications/SystemService/Service2002.sln
 delete mode 100644 mDNSWindows/Applications/SystemService/Service2002.vcproj
 delete mode 100644 mDNSWindows/Applications/SystemServiceTest/Tool.mcp
 delete mode 100644 mDNSWindows/Applications/SystemServiceTest/Tool2002.sln
 delete mode 100644 mDNSWindows/Applications/mdnsNSP/NSP.c
 delete mode 100644 mDNSWindows/Applications/mdnsNSP/NSP.def
 delete mode 100644 mDNSWindows/Applications/mdnsNSP/NSP.mcp
 delete mode 100644 mDNSWindows/Applications/mdnsNSP/ReadMe.txt
 create mode 100755 mDNSWindows/DLL.NET/AssemblyInfo.cpp
 create mode 100755 mDNSWindows/DLL.NET/PString.h
 rename mDNSWindows/{Applications/SystemService/Resource.h => DLL.NET/Stdafx.cpp} (76%)
 mode change 100644 => 100755
 create mode 100755 mDNSWindows/DLL.NET/Stdafx.h
 create mode 100755 mDNSWindows/DLL.NET/dnssd_NET.cpp
 create mode 100755 mDNSWindows/DLL.NET/dnssd_NET.h
 create mode 100755 mDNSWindows/DLL.NET/dnssd_NET.ico
 create mode 100755 mDNSWindows/DLL.NET/dnssd_NET.rc
 create mode 100755 mDNSWindows/DLL.NET/dnssd_NET.vcproj
 create mode 100755 mDNSWindows/DLL.NET/resource.h
 create mode 100644 mDNSWindows/DLL/dll.aps
 create mode 100644 mDNSWindows/DLL/dll.rc
 rename mDNSWindows/{Applications => }/DLL/dllmain.c (91%)
 rename mDNSWindows/{Applications => }/DLL/dnssd.def (79%)
 create mode 100644 mDNSWindows/DLL/dnssd.vcproj
 create mode 100644 mDNSWindows/DLL/resource.h
 delete mode 100644 mDNSWindows/DNSSD.c
 delete mode 100644 mDNSWindows/DNSSD.h
 delete mode 100644 mDNSWindows/DNSSDDirect.c
 delete mode 100644 mDNSWindows/DNSSDDirect.h
 rename mDNSWindows/{Applications => }/DNSServiceBrowser/Windows/ApplicationVS2002.sln (100%)
 rename mDNSWindows/{Applications => }/DNSServiceBrowser/Windows/ApplicationVS2002.vcproj (98%)
 rename mDNSWindows/{Applications => }/DNSServiceBrowser/Windows/ApplicationVS2003.sln (100%)
 rename mDNSWindows/{Applications => }/DNSServiceBrowser/Windows/ApplicationVS2003.vcproj (98%)
 rename mDNSWindows/{Applications => }/DNSServiceBrowser/Windows/Resources/Application.ico (100%)
 rename mDNSWindows/{Applications => }/DNSServiceBrowser/Windows/Resources/Application.rc (95%)
 rename mDNSWindows/{Applications => }/DNSServiceBrowser/Windows/Resources/Application.rc2 (86%)
 rename mDNSWindows/{Applications => }/DNSServiceBrowser/Windows/Resources/Resource.h (100%)
 rename mDNSWindows/{Applications => }/DNSServiceBrowser/Windows/Sources/AboutDialog.cpp (93%)
 rename mDNSWindows/{Applications => }/DNSServiceBrowser/Windows/Sources/AboutDialog.h (92%)
 rename mDNSWindows/{Applications => }/DNSServiceBrowser/Windows/Sources/Application.cpp (94%)
 rename mDNSWindows/{Applications => }/DNSServiceBrowser/Windows/Sources/Application.h (92%)
 rename mDNSWindows/{Applications => }/DNSServiceBrowser/Windows/Sources/ChooserDialog.cpp (99%)
 rename mDNSWindows/{Applications => }/DNSServiceBrowser/Windows/Sources/ChooserDialog.h (95%)
 rename mDNSWindows/{Applications => }/DNSServiceBrowser/Windows/Sources/LoginDialog.cpp (98%)
 rename mDNSWindows/{Applications => }/DNSServiceBrowser/Windows/Sources/LoginDialog.h (96%)
 rename mDNSWindows/{Applications => }/DNSServiceBrowser/Windows/Sources/StdAfx.cpp (86%)
 rename mDNSWindows/{Applications => }/DNSServiceBrowser/Windows/Sources/StdAfx.h (91%)
 rename mDNSWindows/{Applications => }/DNSServiceBrowser/WindowsCE/Application.vcc (100%)
 rename mDNSWindows/{Applications => }/DNSServiceBrowser/WindowsCE/Application.vcp (100%)
 rename mDNSWindows/{Applications => }/DNSServiceBrowser/WindowsCE/Application.vcw (100%)
 rename mDNSWindows/{Applications => }/DNSServiceBrowser/WindowsCE/Resources/Application.ico (100%)
 rename mDNSWindows/{Applications => }/DNSServiceBrowser/WindowsCE/Resources/Application.rc (96%)
 rename mDNSWindows/{Applications => }/DNSServiceBrowser/WindowsCE/Resources/Application.rc2 (100%)
 rename mDNSWindows/{Applications => }/DNSServiceBrowser/WindowsCE/Resources/newres.h (100%)
 rename mDNSWindows/{Applications => }/DNSServiceBrowser/WindowsCE/Resources/resource.h (100%)
 rename mDNSWindows/{Applications => }/DNSServiceBrowser/WindowsCE/Sources/Application.cpp (94%)
 rename mDNSWindows/{Applications => }/DNSServiceBrowser/WindowsCE/Sources/Application.h (92%)
 rename mDNSWindows/{Applications => }/DNSServiceBrowser/WindowsCE/Sources/BrowserDialog.cpp (98%)
 rename mDNSWindows/{Applications => }/DNSServiceBrowser/WindowsCE/Sources/BrowserDialog.h (94%)
 rename mDNSWindows/{Applications => }/DNSServiceBrowser/WindowsCE/Sources/StdAfx.cpp (86%)
 rename mDNSWindows/{Applications => }/DNSServiceBrowser/WindowsCE/Sources/StdAfx.h (91%)
 rename mDNSWindows/{Applications => }/DNSServiceTest/Tool.c (95%)
 rename mDNSWindows/{Applications => }/DNSServiceTest/ToolPrefixWindows.h (95%)
 rename mDNSWindows/{Applications => }/DNSServiceTest/ToolPrefixWindowsDebug.h (95%)
 create mode 100644 mDNSWindows/DNSServiceTest/ToolWin32.mcp
 rename mDNSWindows/{Applications => }/DNSServiceTest/ToolWin32VS2002.sln (100%)
 rename mDNSWindows/{Applications => }/DNSServiceTest/ToolWin32VS2002.vcproj (99%)
 rename mDNSWindows/{Applications => }/DNSServiceTest/ToolWin32VS2003.sln (100%)
 rename mDNSWindows/{Applications => }/DNSServiceTest/ToolWin32VS2003.vcproj (99%)
 delete mode 100644 mDNSWindows/Installer.vct
 create mode 100644 mDNSWindows/Installer/Main.ism
 create mode 100644 mDNSWindows/Installer/SDK.ism
 rename mDNSWindows/{Applications/SystemService/Service.rc => Java/jdns_sd.rc} (51%)
 rename mDNSWindows/{Applications => }/Java/makefile (87%)
 mode change 100755 => 100644
 create mode 100644 mDNSWindows/NSPTool/NSPTool.aps
 rename mDNSWindows/{Applications/NSPTool/Tool.c => NSPTool/NSPTool.c} (94%)
 create mode 100644 mDNSWindows/NSPTool/NSPTool.rc
 rename mDNSWindows/{Applications/DLL/dnssd.vcproj => NSPTool/NSPTool.vcproj} (50%)
 rename mDNSWindows/{Applications => }/NSPTool/Prefix.h (94%)
 create mode 100644 mDNSWindows/NSPTool/resource.h
 delete mode 100644 mDNSWindows/RMxClient.c
 delete mode 100644 mDNSWindows/RMxClient.h
 delete mode 100644 mDNSWindows/RMxCommon.c
 delete mode 100644 mDNSWindows/RMxCommon.h
 delete mode 100644 mDNSWindows/RMxServer.c
 delete mode 100644 mDNSWindows/RMxServer.h
 rename mDNSWindows/{Applications => }/SystemService/EventLogMessages.bin (100%)
 create mode 100755 mDNSWindows/SystemService/Firewall.cpp
 create mode 100755 mDNSWindows/SystemService/Firewall.h
 rename mDNSWindows/{Applications => }/SystemService/Prefix.h (95%)
 create mode 100644 mDNSWindows/SystemService/Service.aps
 create mode 100644 mDNSWindows/SystemService/Service.c
 create mode 100644 mDNSWindows/SystemService/Service.mcp
 create mode 100644 mDNSWindows/SystemService/Service.rc
 create mode 100644 mDNSWindows/SystemService/Service.vcproj
 create mode 100644 mDNSWindows/SystemService/resource.h
 create mode 100644 mDNSWindows/SystemService/resrc1.h
 rename mDNSWindows/{Applications => }/SystemServiceTest/Prefix.h (94%)
 rename mDNSWindows/{Applications => }/SystemServiceTest/Tool.c (99%)
 rename mDNSWindows/{Applications/mdnsNSP/mdnsNSP.mcp => SystemServiceTest/Tool.mcp} (50%)
 rename mDNSWindows/{Applications => }/SystemServiceTest/Tool2002.vcproj (100%)
 create mode 100644 mDNSWindows/WinServices.cpp
 create mode 100644 mDNSWindows/WinServices.h
 create mode 100644 mDNSWindows/WinVersRes.h
 create mode 100644 mDNSWindows/mdnsNSP/ReadMe.txt
 create mode 100644 mDNSWindows/mdnsNSP/mdnsNSP.aps
 rename mDNSWindows/{Applications => }/mdnsNSP/mdnsNSP.c (90%)
 rename mDNSWindows/{Applications => }/mdnsNSP/mdnsNSP.def (77%)
 create mode 100644 mDNSWindows/mdnsNSP/mdnsNSP.rc
 create mode 100644 mDNSWindows/mdnsNSP/mdnsNSP.vcproj
 create mode 100644 mDNSWindows/mdnsNSP/resource.h

diff --git a/Clients/DNS-SD.xcode/project.pbxproj b/Clients/DNS-SD.xcode/project.pbxproj
index 46805b9..574ad8b 100644
--- a/Clients/DNS-SD.xcode/project.pbxproj
+++ b/Clients/DNS-SD.xcode/project.pbxproj
@@ -151,7 +151,7 @@
 				GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO;
 				GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
 				GCC_WARN_UNKNOWN_PRAGMAS = NO;
-				HEADER_SEARCH_PATHS = "";
+				HEADER_SEARCH_PATHS = ../mDNSShared;
 				INSTALL_PATH = "$(HOME)/bin";
 				LIBRARY_SEARCH_PATHS = "";
 				OTHER_CFLAGS = "";
@@ -282,6 +282,7 @@
 				GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/AppKit.framework/Headers/AppKit.h";
 				GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
 				GCC_WARN_UNKNOWN_PRAGMAS = NO;
+				HEADER_SEARCH_PATHS = ../mDNSShared;
 				INFOPLIST_FILE = "DNSServiceBrowser-Info.plist";
 				INSTALL_PATH = "$(USER_APPS_DIR)";
 				OTHER_CFLAGS = "";
@@ -396,7 +397,8 @@
 				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";
+				HEADER_SEARCH_PATHS = ../mDNSShared;
+				INFOPLIST_FILE = "DNSServiceReg-Info.plist";
 				INSTALL_PATH = "$(USER_APPS_DIR)";
 				OTHER_CFLAGS = "";
 				OTHER_LDFLAGS = "-framework Foundation -framework AppKit";
@@ -436,7 +438,7 @@
 	<key>CFBundleVersion</key>
 	<string>1.0.0d1</string>
 	<key>NSMainNibFile</key>
-	<string>DNSServiceRegistration</string>
+	<string>DNSServiceReg</string>
 	<key>NSPrincipalClass</key>
 	<string>NSApplication</string>
 </dict>
@@ -457,7 +459,7 @@
 			isa = PBXContainerItemProxy;
 			proxyType = 1;
 			remoteGlobalIDString = FF1E351206711B5C003DD5BC;
-			remoteInfo = DNSServiceRegistration;
+			remoteInfo = DNSServiceReg;
 		};
 		FF1E351806711B6A003DD5BC = {
 			isa = PBXTargetDependency;
@@ -468,7 +470,7 @@
 			fileEncoding = 4;
 			isa = PBXFileReference;
 			lastKnownFileType = sourcecode.c.objc;
-			path = DNSServiceRegistration.m;
+			path = DNSServiceReg.m;
 			refType = 4;
 			sourceTree = "<group>";
 		};
@@ -481,7 +483,7 @@
 		FF1E352506711BD6003DD5BC = {
 			isa = PBXFileReference;
 			lastKnownFileType = wrapper.nib;
-			path = DNSServiceRegistration.nib;
+			path = DNSServiceReg.nib;
 			refType = 4;
 			sourceTree = "<group>";
 		};
diff --git a/Clients/DNSServiceBrowser.NET/App.ico b/Clients/DNSServiceBrowser.NET/App.ico
new file mode 100755
index 0000000000000000000000000000000000000000..3a5525fd794f7a7c5c8e6187f470ea3af38cd2b6
GIT binary patch
literal 1078
zcmeHHJr05}7=1t!Hp3A*8IHkVf+j?-!eHY14Gtcw1Eb*_9>Bq^zETJ@GKj{_2j4$w
zo9}xCh!8{T3=X##Skq>ikMjsvB|y%crWBM2iW(4pI}c%z6%lW!=~4v77#3{z!dmB1
z__&l)-{KUYR+|8|;wB^R|9ET$J@(@=#rd^=)qs85?vAy(PSF5CyNkus435LVkZ$rj
zNw|JG-P7^hF<(;#o*Vk}5R#e|^13tBbQkeF?djULtvqyxd3<cQetc!+$5J+aVZ&1f
Qa92%&%o_p!1^%7_Ps0Y#2><{9

literal 0
HcmV?d00001

diff --git a/Clients/DNSServiceBrowser.NET/AssemblyInfo.cs b/Clients/DNSServiceBrowser.NET/AssemblyInfo.cs
new file mode 100755
index 0000000..793362b
--- /dev/null
+++ b/Clients/DNSServiceBrowser.NET/AssemblyInfo.cs
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+    
+$Log: AssemblyInfo.cs,v $
+Revision 1.1  2004/07/19 07:54:24  shersche
+Initial revision
+
+
+*/
+
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+//
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+//
+[assembly: AssemblyTitle("")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("")]
+[assembly: AssemblyCopyright("")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]		
+
+//
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Revision and Build Numbers 
+// by using the '*' as shown below:
+
+[assembly: AssemblyVersion("1.0.*")]
+
+//
+// In order to sign your assembly you must specify a key to use. Refer to the 
+// Microsoft .NET Framework documentation for more information on assembly signing.
+//
+// Use the attributes below to control which key is used for signing. 
+//
+// Notes: 
+//   (*) If no key is specified, the assembly is not signed.
+//   (*) KeyName refers to a key that has been installed in the Crypto Service
+//       Provider (CSP) on your machine. KeyFile refers to a file which contains
+//       a key.
+//   (*) If the KeyFile and the KeyName values are both specified, the 
+//       following processing occurs:
+//       (1) If the KeyName can be found in the CSP, that key is used.
+//       (2) If the KeyName does not exist and the KeyFile does exist, the key 
+//           in the KeyFile is installed into the CSP and used.
+//   (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility.
+//       When specifying the KeyFile, the location of the KeyFile should be
+//       relative to the project output directory which is
+//       %Project Directory%\obj\<configuration>. For example, if your KeyFile is
+//       located in the project directory, you would specify the AssemblyKeyFile 
+//       attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")]
+//   (*) Delay Signing is an advanced option - see the Microsoft .NET Framework
+//       documentation for more information on this.
+//
+[assembly: AssemblyDelaySign(false)]
+[assembly: AssemblyKeyFile("")]
+[assembly: AssemblyKeyName("")]
diff --git a/Clients/DNSServiceBrowser.NET/DNSServiceBrowser.NET.csproj b/Clients/DNSServiceBrowser.NET/DNSServiceBrowser.NET.csproj
new file mode 100755
index 0000000..d43cf10
--- /dev/null
+++ b/Clients/DNSServiceBrowser.NET/DNSServiceBrowser.NET.csproj
@@ -0,0 +1,117 @@
+<VisualStudioProject>
+    <CSHARP
+        ProjectType = "Local"
+        ProductVersion = "7.0.9466"
+        SchemaVersion = "1.0"
+        ProjectGuid = "{DE8DB97E-37A3-43ED-9A5E-CCC5F6DE9CB4}"
+    >
+        <Build>
+            <Settings
+                ApplicationIcon = ""
+                AssemblyKeyContainerName = ""
+                AssemblyName = "DNSServiceBrowser_NET"
+                AssemblyOriginatorKeyFile = ""
+                DefaultClientScript = "JScript"
+                DefaultHTMLPageLayout = "Grid"
+                DefaultTargetSchema = "IE50"
+                DelaySign = "false"
+                OutputType = "WinExe"
+                RootNamespace = "DNSServiceBrowser_NET"
+                StartupObject = ""
+            >
+                <Config
+                    Name = "Debug"
+                    AllowUnsafeBlocks = "false"
+                    BaseAddress = "285212672"
+                    CheckForOverflowUnderflow = "false"
+                    ConfigurationOverrideFile = ""
+                    DefineConstants = "DEBUG;TRACE"
+                    DocumentationFile = ""
+                    DebugSymbols = "true"
+                    FileAlignment = "4096"
+                    IncrementalBuild = "true"
+                    Optimize = "false"
+                    OutputPath = "bin\Debug\"
+                    RegisterForComInterop = "false"
+                    RemoveIntegerChecks = "false"
+                    TreatWarningsAsErrors = "false"
+                    WarningLevel = "4"
+                />
+                <Config
+                    Name = "Release"
+                    AllowUnsafeBlocks = "false"
+                    BaseAddress = "285212672"
+                    CheckForOverflowUnderflow = "false"
+                    ConfigurationOverrideFile = ""
+                    DefineConstants = "TRACE"
+                    DocumentationFile = ""
+                    DebugSymbols = "false"
+                    FileAlignment = "4096"
+                    IncrementalBuild = "false"
+                    Optimize = "true"
+                    OutputPath = "bin\Release\"
+                    RegisterForComInterop = "false"
+                    RemoveIntegerChecks = "false"
+                    TreatWarningsAsErrors = "false"
+                    WarningLevel = "4"
+                />
+            </Settings>
+            <References>
+                <Reference
+                    Name = "System"
+                    AssemblyName = "System"
+                    HintPath = "..\..\..\..\..\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.dll"
+                />
+                <Reference
+                    Name = "System.Data"
+                    AssemblyName = "System.Data"
+                    HintPath = "..\..\..\..\..\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.Data.dll"
+                />
+                <Reference
+                    Name = "System.Drawing"
+                    AssemblyName = "System.Drawing"
+                    HintPath = "..\..\..\..\..\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.Drawing.dll"
+                />
+                <Reference
+                    Name = "System.Windows.Forms"
+                    AssemblyName = "System.Windows.Forms"
+                    HintPath = "..\..\..\..\..\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.Windows.Forms.dll"
+                />
+                <Reference
+                    Name = "System.XML"
+                    AssemblyName = "System.Xml"
+                    HintPath = "..\..\..\..\..\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.XML.dll"
+                />
+                <Reference
+                    Name = "dnssd.NET"
+                    AssemblyName = "dnssd.NET"
+                    HintPath = "..\..\mDNSWindows\DLL.NET\Release\dnssd.NET.dll"
+                />
+            </References>
+        </Build>
+        <Files>
+            <Include>
+                <File
+                    RelPath = "App.ico"
+                    BuildAction = "Content"
+                />
+                <File
+                    RelPath = "AssemblyInfo.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "DNSServiceBrowser.cs"
+                    SubType = "Form"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "DNSServiceBrowser.resx"
+                    DependentUpon = "DNSServiceBrowser.cs"
+                    BuildAction = "EmbeddedResource"
+                />
+            </Include>
+        </Files>
+    </CSHARP>
+</VisualStudioProject>
+
diff --git a/Clients/DNSServiceBrowser.NET/DNSServiceBrowser.cs b/Clients/DNSServiceBrowser.NET/DNSServiceBrowser.cs
new file mode 100755
index 0000000..75bbc93
--- /dev/null
+++ b/Clients/DNSServiceBrowser.NET/DNSServiceBrowser.cs
@@ -0,0 +1,745 @@
+/*
+ * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+    
+$Log: DNSServiceBrowser.cs,v $
+Revision 1.5  2004/09/21 16:26:58  shersche
+Check to make sure browse list selected item is not null before resolving
+Submitted by: prepin@gmail.com
+
+Revision 1.4  2004/09/13 19:38:17  shersche
+Changed code to reflect namespace and type changes to dnssd.NET library
+
+Revision 1.3  2004/09/11 00:38:14  shersche
+DNSService APIs now assume port in host format. Check for null text record in resolve callback.
+
+Revision 1.2  2004/07/22 23:15:25  shersche
+Fix service names for teleport, tftp, and bootps
+
+Revision 1.1  2004/07/19 07:54:24  shersche
+Initial revision
+
+
+
+*/
+
+using System;
+using System.Drawing;
+using System.Collections;
+using System.ComponentModel;
+using System.Windows.Forms;
+using System.Data;
+using System.Text;
+using Apple.DNSSD;
+
+namespace DNSServiceBrowser_NET
+{
+	/// <summary>
+	/// Summary description for Form1.
+	/// </summary>
+	public class Form1 : System.Windows.Forms.Form
+	{
+		private System.Windows.Forms.ComboBox typeBox;
+		private System.Windows.Forms.ListBox browseList;
+		private ServiceRef browser = null;
+		private ServiceRef resolver = null;
+		/// <summary>
+		/// Required designer variable.
+		/// </summary>
+		private System.ComponentModel.Container components = null;
+
+
+		//
+		// These delegates are invoked as a result of DNSService
+		// operation.
+		//
+		delegate void AddServiceCallback(BrowseData data);
+		delegate void RemoveServiceCallback(BrowseData data);
+		delegate void ResolveServiceCallback(ResolveData data);
+
+		AddServiceCallback		addServiceCallback;
+		RemoveServiceCallback	removeServiceCallback;
+		private System.Windows.Forms.Label label1;
+		private System.Windows.Forms.Label label2;
+		private System.Windows.Forms.Label label3;
+		private System.Windows.Forms.Label label4;
+		private System.Windows.Forms.TextBox nameField;
+		private System.Windows.Forms.TextBox typeField;
+		private System.Windows.Forms.TextBox domainField;
+		private System.Windows.Forms.TextBox hostField;
+		private System.Windows.Forms.TextBox portField;
+		private System.Windows.Forms.Label label5;
+		private System.Windows.Forms.ListBox serviceTextField;
+		ResolveServiceCallback	resolveServiceCallback;
+
+		public Form1()
+		{
+			//
+			// Required for Windows Form Designer support
+			//
+			InitializeComponent();
+
+			addServiceCallback		= new AddServiceCallback(OnAddService);
+			removeServiceCallback	= new RemoveServiceCallback(OnRemoveService);
+			resolveServiceCallback	= new ResolveServiceCallback(OnResolveService);
+
+			this.Load += new System.EventHandler(this.Form1_Load);
+		}
+
+		private void Form1_Load(object sender, EventArgs e) 
+		{
+			typeBox.SelectedItem = "_spike._tcp";
+		}
+
+		/// <summary>
+		/// Clean up any resources being used.
+		/// </summary>
+		protected override void Dispose( bool disposing )
+		{
+			if( disposing )
+			{
+				if (components != null) 
+				{
+					components.Dispose();
+				}
+
+				if (browser != null)
+				{
+					browser.Dispose();
+				}
+			}
+			base.Dispose( disposing );
+		}
+
+		#region Windows Form Designer generated code
+		/// <summary>
+		/// Required method for Designer support - do not modify
+		/// the contents of this method with the code editor.
+		/// </summary>
+		private void InitializeComponent()
+		{
+			this.browseList = new System.Windows.Forms.ListBox();
+			this.typeBox = new System.Windows.Forms.ComboBox();
+			this.label1 = new System.Windows.Forms.Label();
+			this.label2 = new System.Windows.Forms.Label();
+			this.label3 = new System.Windows.Forms.Label();
+			this.label4 = new System.Windows.Forms.Label();
+			this.nameField = new System.Windows.Forms.TextBox();
+			this.typeField = new System.Windows.Forms.TextBox();
+			this.domainField = new System.Windows.Forms.TextBox();
+			this.hostField = new System.Windows.Forms.TextBox();
+			this.portField = new System.Windows.Forms.TextBox();
+			this.label5 = new System.Windows.Forms.Label();
+			this.serviceTextField = new System.Windows.Forms.ListBox();
+			this.SuspendLayout();
+			// 
+			// browseList
+			// 
+			this.browseList.Location = new System.Drawing.Point(8, 48);
+			this.browseList.Name = "browseList";
+			this.browseList.Size = new System.Drawing.Size(488, 147);
+			this.browseList.TabIndex = 0;
+			this.browseList.SelectedIndexChanged += new System.EventHandler(this.listBox1_SelectedIndexChanged);
+			// 
+			// typeBox
+			// 
+			this.typeBox.Items.AddRange(new object[]
+			{
+				"_accessone._tcp",
+				"_accountedge._tcp",
+				"_actionitems._tcp",
+				"_addressbook._tcp",
+				"_aecoretech._tcp",
+				"_afpovertcp._tcp",
+				"_airport._tcp",
+				"_animolmd._tcp",
+				"_animobserver._tcp",
+				"_apple-sasl._tcp",
+				"_aquamon._tcp",
+				"_async._tcp",
+				"_auth._tcp",
+				"_beep._tcp",
+				"_bfagent._tcp",
+				"_bootps._udp",
+				"_bousg._tcp",
+				"_bsqdea._tcp",
+				"_cheat._tcp",
+				"_chess._tcp",
+				"_clipboard._tcp",
+				"_collection._tcp",
+				"_contactserver._tcp",
+				"_cvspserver._tcp",
+				"_cytv._tcp",
+				"_daap._tcp",
+				"_difi._tcp",
+				"_distcc._tcp",
+				"_dossier._tcp",
+				"_dpap._tcp",
+				"_earphoria._tcp",
+				"_ebms._tcp",
+				"_ebreg._tcp",
+				"_ecbyesfsgksc._tcp",
+				"_eheap._tcp",
+				"_embrace._tcp",
+				"_eppc._tcp",
+				"_eventserver._tcp",
+				"_exec._tcp",
+				"_facespan._tcp",
+				"_faxstfx._tcp",
+				"_fish._tcp",
+				"_fjork._tcp",
+				"_fmpro-internal._tcp",
+				"_ftp._tcp",
+				"_ftpcroco._tcp",
+				"_gbs-smp._tcp",
+				"_gbs-stp._tcp",
+				"_grillezvous._tcp",
+				"_h323._tcp",
+				"_http._tcp",
+				"_hotwayd._tcp",
+				"_hydra._tcp",
+				"_ica-networking._tcp",
+				"_ichalkboard._tcp",
+				"_ichat._tcp",
+				"_iconquer._tcp",
+				"_ifolder._tcp",
+				"_ilynx._tcp",
+				"_imap._tcp",
+				"_imidi._tcp",
+				"_ipbroadcaster._tcp",
+				"_ipp._tcp",
+				"_isparx._tcp",
+				"_ispq-vc._tcp",
+				"_ishare._tcp",
+				"_isticky._tcp",
+				"_istorm._tcp",
+				"_iwork._tcp",
+				"_lan2p._tcp",
+				"_ldap._tcp",
+				"_liaison._tcp",
+				"_login._tcp",
+				"_lontalk._tcp",
+				"_lonworks._tcp",
+				"_macfoh-remote._tcp",
+				"_macminder._tcp",
+				"_moneyworks._tcp",
+				"_mp3sushi._tcp",
+				"_mttp._tcp",
+				"_ncbroadcast._tcp",
+				"_ncdirect._tcp",
+				"_ncsyncserver._tcp",
+				"_net-assistant._tcp",
+				"_newton-dock._tcp",
+				"_nfs._udp",
+				"_nssocketport._tcp",
+				"_odabsharing._tcp",
+				"_omni-bookmark._tcp",
+				"_openbase._tcp",
+				"_p2pchat._udp",
+				"_pdl-datastream._tcp",
+				"_poch._tcp",
+				"_pop3._tcp",
+				"_postgresql._tcp",
+				"_presence._tcp",
+				"_printer._tcp",
+				"_ptp._tcp",
+				"_quinn._tcp",
+				"_raop._tcp",
+				"_rce._tcp",
+				"_realplayfavs._tcp",
+				"_rendezvouspong._tcp",
+				"_riousbprint._tcp",
+				"_rfb._tcp",
+				"_rtsp._tcp",
+				"_safarimenu._tcp",
+				"_sallingclicker._tcp",
+				"_scone._tcp",
+				"_sdsharing._tcp",
+				"_see._tcp",
+				"_seeCard._tcp",
+				"_serendipd._tcp",
+				"_servermgr._tcp",
+				"_shell._tcp",
+				"_shout._tcp",
+				"_shoutcast._tcp",
+				"_soap._tcp",
+				"_spike._tcp",
+				"_spincrisis._tcp",
+				"_spl-itunes._tcp",
+				"_spr-itunes._tcp",
+				"_ssh._tcp",
+				"_ssscreenshare._tcp",
+				"_strateges._tcp",
+				"_sge-exec._tcp",
+				"_sge-qmaster._tcp",
+				"_stickynotes._tcp",
+				"_sxqdea._tcp",
+				"_sybase-tds._tcp",
+				"_teamlist._tcp",
+				"_teleport._udp",
+				"_telnet._tcp",
+				"_tftp._udp",
+				"_ticonnectmgr._tcp",
+				"_tinavigator._tcp",
+				"_tryst._tcp",
+				"_upnp._tcp",
+				"_utest._tcp",
+				"_vue4rendercow._tcp",
+				"_webdav._tcp",
+				"_whamb._tcp",
+				"_wired._tcp",
+				"_workstation._tcp",
+				"_wormhole._tcp",
+				"_workgroup._tcp",
+				"_ws._tcp",
+				"_xserveraid._tcp",
+				"_xsync._tcp",
+				"_xtshapro._tcp"
+			});
+
+			this.typeBox.Location = new System.Drawing.Point(8, 16);
+			this.typeBox.Name = "typeBox";
+			this.typeBox.Size = new System.Drawing.Size(192, 21);
+			this.typeBox.Sorted = true;
+			this.typeBox.TabIndex = 3;
+			this.typeBox.SelectedIndexChanged += new System.EventHandler(this.typeBox_SelectedIndexChanged);
+			// 
+			// label1
+			// 
+			this.label1.Location = new System.Drawing.Point(8, 208);
+			this.label1.Name = "label1";
+			this.label1.Size = new System.Drawing.Size(48, 16);
+			this.label1.TabIndex = 4;
+			this.label1.Text = "Name:";
+			this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
+			// 
+			// label2
+			// 
+			this.label2.Location = new System.Drawing.Point(8, 240);
+			this.label2.Name = "label2";
+			this.label2.Size = new System.Drawing.Size(48, 16);
+			this.label2.TabIndex = 5;
+			this.label2.Text = "Type:";
+			this.label2.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
+			// 
+			// label3
+			// 
+			this.label3.Location = new System.Drawing.Point(8, 272);
+			this.label3.Name = "label3";
+			this.label3.Size = new System.Drawing.Size(48, 16);
+			this.label3.TabIndex = 6;
+			this.label3.Text = "Domain:";
+			this.label3.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
+			// 
+			// label4
+			// 
+			this.label4.Location = new System.Drawing.Point(8, 304);
+			this.label4.Name = "label4";
+			this.label4.Size = new System.Drawing.Size(48, 16);
+			this.label4.TabIndex = 7;
+			this.label4.Text = "Host:";
+			this.label4.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
+			// 
+			// nameField
+			// 
+			this.nameField.Location = new System.Drawing.Point(56, 208);
+			this.nameField.Name = "nameField";
+			this.nameField.ReadOnly = true;
+			this.nameField.Size = new System.Drawing.Size(168, 20);
+			this.nameField.TabIndex = 8;
+			this.nameField.Text = "";
+			// 
+			// typeField
+			// 
+			this.typeField.Location = new System.Drawing.Point(56, 240);
+			this.typeField.Name = "typeField";
+			this.typeField.ReadOnly = true;
+			this.typeField.Size = new System.Drawing.Size(168, 20);
+			this.typeField.TabIndex = 9;
+			this.typeField.Text = "";
+			// 
+			// domainField
+			// 
+			this.domainField.Location = new System.Drawing.Point(56, 272);
+			this.domainField.Name = "domainField";
+			this.domainField.ReadOnly = true;
+			this.domainField.Size = new System.Drawing.Size(168, 20);
+			this.domainField.TabIndex = 10;
+			this.domainField.Text = "";
+			// 
+			// hostField
+			// 
+			this.hostField.Location = new System.Drawing.Point(56, 304);
+			this.hostField.Name = "hostField";
+			this.hostField.ReadOnly = true;
+			this.hostField.Size = new System.Drawing.Size(168, 20);
+			this.hostField.TabIndex = 11;
+			this.hostField.Text = "";
+
+			// 
+			// portField
+			// 
+			this.portField.Location = new System.Drawing.Point(56, 336);
+			this.portField.Name = "portField";
+			this.portField.ReadOnly = true;
+			this.portField.Size = new System.Drawing.Size(168, 20);
+			this.portField.TabIndex = 12;
+			this.portField.Text = "";
+			// 
+			// label5
+			// 
+			this.label5.Location = new System.Drawing.Point(8, 336);
+			this.label5.Name = "label5";
+			this.label5.Size = new System.Drawing.Size(48, 16);
+			this.label5.TabIndex = 14;
+			this.label5.Text = "Port:";
+			this.label5.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
+			// 
+			// serviceTextField
+			// 
+			this.serviceTextField.HorizontalScrollbar = true;
+			this.serviceTextField.Location = new System.Drawing.Point(264, 208);
+			this.serviceTextField.Name = "serviceTextField";
+			this.serviceTextField.Size = new System.Drawing.Size(232, 147);
+			this.serviceTextField.TabIndex = 16;
+			// 
+			// Form1
+			// 
+			this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
+			this.ClientSize = new System.Drawing.Size(512, 365);
+			this.Controls.AddRange(new System.Windows.Forms.Control[] {
+																		  this.serviceTextField,
+																		  this.label5,
+																		  this.portField,
+																		  this.hostField,
+																		  this.domainField,
+																		  this.typeField,
+																		  this.nameField,
+																		  this.label4,
+																		  this.label3,
+																		  this.label2,
+																		  this.label1,
+																		  this.typeBox,
+																		  this.browseList});
+			this.Name = "Form1";
+			this.Text = "DNSServices Browser";
+			this.ResumeLayout(false);
+
+		}
+		#endregion
+
+		/// <summary>
+		/// The main entry point for the application.
+		/// </summary>
+		[STAThread]
+		static void Main() 
+		{
+			Application.Run(new Form1());
+		}
+		//
+		// BrowseData
+		//
+		// This class is used to store data associated
+		// with a DNSService.Browse() operation
+		//
+		public class BrowseData
+		{
+			public int		InterfaceIndex;
+			public String	Name;
+			public String	Type;
+			public String	Domain;
+
+			public override String
+			ToString()
+			{
+				return Name;
+			}
+
+			public override bool
+			Equals(object other)
+			{
+				bool result = false;
+
+				if (other != null)
+				{
+					if ((object) this == other)
+					{
+						result = true;
+					}
+					else if (other is BrowseData)
+					{
+						BrowseData otherBrowseData = (BrowseData) other;
+
+						result = (this.Name == otherBrowseData.Name);
+					}
+				}
+
+				return result;
+			}
+
+			public override int
+			GetHashCode()
+			{
+				return Name.GetHashCode();
+			}
+		};
+
+
+		//
+		// ResolveData
+		//
+		// This class is used to store data associated
+		// with a DNSService.Resolve() operation
+		//
+		public class ResolveData
+		{
+			public int		InterfaceIndex;
+			public String	FullName;
+			public String	HostName;
+			public int		Port;
+			public Byte[]	TxtRecord;
+
+			public override String
+				ToString()
+			{
+				return FullName;
+			}
+		};
+
+		//
+		// Populate()
+		//
+		// Populate this form with data associated with a 
+		// DNSService.Resolve() call
+		//
+		public void
+		Populate(BrowseData browseData, ResolveData resolveData)
+		{
+			nameField.Text	= browseData.Name;
+			typeField.Text	= browseData.Type;
+			domainField.Text	= browseData.Domain;
+			hostField.Text	= resolveData.HostName;
+			portField.Text	= resolveData.Port.ToString();
+
+			serviceTextField.Items.Clear();
+		
+			if (resolveData.TxtRecord != null)
+			{
+				for (int idx = 0; idx < TextRecord.GetCount(resolveData.TxtRecord); idx++)
+				{
+					String	key;
+					Byte[]	bytes;
+				
+					bytes	= TextRecord.GetItemAtIndex(resolveData.TxtRecord, idx, out key);
+
+					if (key.Length > 0)
+					{
+						String	val = "";
+
+						if (bytes != null)
+						{
+							val = Encoding.ASCII.GetString(bytes, 0, bytes.Length);
+						}
+
+						serviceTextField.Items.Add(key + "=" + val);
+					}
+				}
+			}
+		}
+
+		//
+		// called when the type field changes
+		//
+		private void typeBox_SelectedIndexChanged(object sender, System.EventArgs e)
+		{
+			browseList.Items.Clear();
+
+			if (browser != null)
+			{
+				browser.Dispose();
+			}
+
+			nameField.Text = "";
+			typeField.Text = "";
+			domainField.Text = "";
+			hostField.Text = "";
+			portField.Text = "";
+			serviceTextField.Items.Clear();
+
+			try
+			{
+				browser = DNSService.Browse(0, 0, typeBox.SelectedItem.ToString(), null, new DNSService.BrowseReply(OnBrowseReply));
+			}
+			catch
+			{
+				MessageBox.Show("Browse Failed", "Error");
+				Application.Exit();
+			}
+		}
+
+		private void listBox1_SelectedIndexChanged(object sender, System.EventArgs e)
+		{
+			if (resolver != null)
+			{
+				resolver.Dispose();
+			}
+
+            if (browseList.SelectedItem != null)
+            {
+                try
+                {
+                    BrowseData data = (BrowseData) browseList.SelectedItem;
+
+                    resolver = DNSService.Resolve(0, 0, data.Name, data.Type, data.Domain, new DNSService.ResolveReply(OnResolveReply));
+                }
+                catch
+                {
+                    MessageBox.Show("Resolve Failed", "Error");
+                    Application.Exit();
+                }
+            }
+		}
+
+		//
+		// OnAddService
+		//
+		// This method is "Invoked" by OnBrowseReply.  This call
+		// executes in the context of the main thread
+		//
+		private void OnAddService
+								(
+								BrowseData	data
+								)
+		{
+			browseList.Items.Add(data);
+			browseList.Invalidate();
+		}
+
+		//
+		// OnRemoveService
+		//
+		// This method is "Invoked" by OnBrowseReply.  This call
+		// executes in the context of the main thread
+		//
+		private void OnRemoveService
+								(
+								BrowseData	data
+								)
+		{
+			browseList.Items.Remove(data);
+			browseList.Invalidate();
+		}
+
+		//
+		// OnResolveService
+		//
+		// This method is "Invoked" by OnResolveReply.  This call
+		// executes in the context of the main thread
+		//
+		private void OnResolveService
+								(
+								ResolveData	data
+								)
+		{
+			resolver.Dispose();
+			resolver = null;
+
+			Populate((BrowseData) browseList.SelectedItem, data);
+		}
+
+		//
+		// OnBrowseReply
+		//
+		// This call is invoked by the DNSService core.  It is
+		// executed in the context of a worker thread, not the
+		// main (GUI) thread.  We create a BrowseData object
+		// and invoked the appropriate method in the GUI thread
+		// so we can update the UI
+		//
+		private void OnBrowseReply
+								(
+								ServiceRef		sdRef,
+								ServiceFlags	flags,
+								int				interfaceIndex,
+								ErrorCode		errorCode,
+								String			name,
+								String			type,
+								String			domain
+								)
+		{
+			if (errorCode == ErrorCode.NoError)
+			{
+				BrowseData data = new BrowseData();
+
+				data.InterfaceIndex = interfaceIndex;
+				data.Name = name;
+				data.Type = type;
+				data.Domain = domain;
+	
+				if ((flags & ServiceFlags.Add) != 0)
+				{
+					Invoke(addServiceCallback, new Object[]{data});
+					
+				}
+				else if ((flags == 0) || ((flags & ServiceFlags.MoreComing) != 0))
+				{
+					Invoke(removeServiceCallback, new Object[]{data});
+				}
+			}
+			else
+			{
+				MessageBox.Show("OnBrowseReply returned an error code: " + errorCode, "Error");
+			}
+		}
+
+		private void OnResolveReply
+								(
+								ServiceRef		sdRef,  
+								ServiceFlags	flags,
+								int				interfaceIndex,
+								ErrorCode		errorCode,
+								String			fullName,
+								String			hostName,
+								int				port,
+								Byte[]			txtRecord
+								)
+		{
+			if (errorCode == ErrorCode.NoError)
+			{
+				ResolveData data = new ResolveData();
+
+				data.InterfaceIndex = interfaceIndex;
+				data.FullName		= fullName;
+				data.HostName		= hostName;
+				data.Port			= port;
+				data.TxtRecord		= txtRecord;
+	
+				Invoke(resolveServiceCallback, new Object[]{data});
+			}
+			else
+			{
+				MessageBox.Show("OnResolveReply returned an error code: " + errorCode, "Error");
+			}
+		}
+	}
+}
diff --git a/Clients/DNSServiceBrowser.NET/DNSServiceBrowser.resx b/Clients/DNSServiceBrowser.NET/DNSServiceBrowser.resx
new file mode 100755
index 0000000..e5b5a11
--- /dev/null
+++ b/Clients/DNSServiceBrowser.NET/DNSServiceBrowser.resx
@@ -0,0 +1,102 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+            Microsoft ResX Schema 
+        
+            Version 1.3
+                
+            The primary goals of this format is to allow a simple XML format 
+            that is mostly human readable. The generation and parsing of the 
+            various data types are done through the TypeConverter classes 
+            associated with the data types.
+        
+            Example:
+        
+                ... ado.net/XML headers & schema ...
+                <resheader name="resmimetype">text/microsoft-resx</resheader>
+                <resheader name="version">1.3</resheader>
+                <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+                <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+                <data name="Name1">this is my long string</data>
+                <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+                <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+                    [base64 mime encoded serialized .NET Framework object]
+                </data>
+                <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+                    [base64 mime encoded string representing a byte array form of the .NET Framework object]
+                </data>
+        
+            There are any number of "resheader" rows that contain simple 
+            name/value pairs.
+            
+            Each data row contains a name, and value. The row also contains a 
+            type or mimetype. Type corresponds to a .NET class that support 
+            text/value conversion through the TypeConverter architecture. 
+            Classes that don't support this are serialized and stored with the 
+            mimetype set.
+                     
+            The mimetype is used for serialized objects, and tells the 
+            ResXResourceReader how to depersist the object. This is currently not 
+            extensible. For a given mimetype the value must be set accordingly:
+        
+            Note - application/x-microsoft.net.object.binary.base64 is the format 
+                   that the ResXResourceWriter will generate, however the reader can 
+                   read any of the formats listed below.
+        
+            mimetype: application/x-microsoft.net.object.binary.base64
+            value   : The object must be serialized with 
+                    : System.Serialization.Formatters.Binary.BinaryFormatter
+                    : and then encoded with base64 encoding.
+        
+            mimetype: application/x-microsoft.net.object.soap.base64
+            value   : The object must be serialized with 
+                    : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+                    : and then encoded with base64 encoding.
+            mimetype: application/x-microsoft.net.object.bytearray.base64
+            value   : The object must be serialized into a byte array 
+                    : using a System.ComponentModel.TypeConverter
+                    : and then encoded with base64 encoding.
+        -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>1.3</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <data name="$this.Name">
+    <value>Form1</value>
+  </data>
+</root>
\ No newline at end of file
diff --git a/Clients/DNSServiceBrowser.m b/Clients/DNSServiceBrowser.m
index f2a38c8..30db5a8 100755
--- a/Clients/DNSServiceBrowser.m
+++ b/Clients/DNSServiceBrowser.m
@@ -3,8 +3,6 @@
  *
  * @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/Clients/DNSServiceRegistration-Info.plist b/Clients/DNSServiceReg-Info.plist
similarity index 95%
rename from Clients/DNSServiceRegistration-Info.plist
rename to Clients/DNSServiceReg-Info.plist
index fafaa99..2569968 100644
--- a/Clients/DNSServiceRegistration-Info.plist
+++ b/Clients/DNSServiceReg-Info.plist
@@ -23,7 +23,7 @@
 	<key>CFBundleVersion</key>
 	<string>1.0.0d1</string>
 	<key>NSMainNibFile</key>
-	<string>DNSServiceRegistration</string>
+	<string>DNSServiceReg</string>
 	<key>NSPrincipalClass</key>
 	<string>NSApplication</string>
 </dict>
diff --git a/Clients/DNSServiceRegistration.m b/Clients/DNSServiceReg.m
similarity index 99%
rename from Clients/DNSServiceRegistration.m
rename to Clients/DNSServiceReg.m
index 3b50a07..c4a3ee7 100644
--- a/Clients/DNSServiceRegistration.m
+++ b/Clients/DNSServiceReg.m
@@ -3,8 +3,6 @@
  *
  * @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
@@ -24,7 +22,7 @@
 
     Change History (most recent first):
 
-$Log: DNSServiceRegistration.m,v $
+$Log: DNSServiceReg.m,v $
 Revision 1.15  2004/06/05 02:01:08  cheshire
 Move DNSServiceRegistration from mDNSMacOSX directory to Clients directory
 
diff --git a/Clients/DNSServiceRegistration.nib/classes.nib b/Clients/DNSServiceReg.nib/classes.nib
similarity index 100%
rename from Clients/DNSServiceRegistration.nib/classes.nib
rename to Clients/DNSServiceReg.nib/classes.nib
diff --git a/Clients/DNSServiceRegistration.nib/info.nib b/Clients/DNSServiceReg.nib/info.nib
similarity index 100%
rename from Clients/DNSServiceRegistration.nib/info.nib
rename to Clients/DNSServiceReg.nib/info.nib
diff --git a/Clients/DNSServiceRegistration.nib/objects.nib b/Clients/DNSServiceReg.nib/objects.nib
similarity index 100%
rename from Clients/DNSServiceRegistration.nib/objects.nib
rename to Clients/DNSServiceReg.nib/objects.nib
diff --git a/Clients/ExplorerPlugin/About.cpp b/Clients/ExplorerPlugin/About.cpp
new file mode 100644
index 0000000..37d3281
--- /dev/null
+++ b/Clients/ExplorerPlugin/About.cpp
@@ -0,0 +1,63 @@
+// About.cpp : implementation file
+//
+
+#include "stdafx.h"
+#include "ExplorerPlugin.h"
+#include "About.h"
+
+
+// CAbout dialog
+
+IMPLEMENT_DYNAMIC(CAbout, CDialog)
+CAbout::CAbout(CWnd* pParent /*=NULL*/)
+	: CDialog(CAbout::IDD, pParent)
+{
+	// Initialize brush with the desired background color
+	m_bkBrush.CreateSolidBrush(RGB(255, 255, 255));
+}
+
+CAbout::~CAbout()
+{
+}
+
+void CAbout::DoDataExchange(CDataExchange* pDX)
+{
+	CDialog::DoDataExchange(pDX);
+	DDX_Control(pDX, IDC_COMPONENT, m_componentCtrl);
+	DDX_Control(pDX, IDC_LEGAL, m_legalCtrl);
+}
+
+
+BEGIN_MESSAGE_MAP(CAbout, CDialog)
+ON_WM_CTLCOLOR()
+END_MESSAGE_MAP()
+
+
+// CAbout message handlers
+HBRUSH CAbout::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
+{ 
+	switch (nCtlColor)
+	{
+		case CTLCOLOR_STATIC:
+	
+			if ( pWnd->GetDlgCtrlID() == IDC_COMPONENT )
+			{
+				pDC->SetTextColor(RGB(64, 64, 64));
+			}
+			else
+			{
+				pDC->SetTextColor(RGB(0, 0, 0));
+			}
+
+			pDC->SetBkColor(RGB(255, 255, 255));
+			return (HBRUSH)(m_bkBrush.GetSafeHandle());
+
+		case CTLCOLOR_DLG:
+	
+			return (HBRUSH)(m_bkBrush.GetSafeHandle());
+
+		default:
+	
+			return CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
+	}
+}
diff --git a/Clients/ExplorerPlugin/About.h b/Clients/ExplorerPlugin/About.h
new file mode 100644
index 0000000..f4d0d7e
--- /dev/null
+++ b/Clients/ExplorerPlugin/About.h
@@ -0,0 +1,27 @@
+#pragma once
+
+#include "Resource.h"
+#include "afxwin.h"
+
+// CAbout dialog
+
+class CAbout : public CDialog
+{
+	DECLARE_DYNAMIC(CAbout)
+
+public:
+	CAbout(CWnd* pParent = NULL);   // standard constructor
+	virtual ~CAbout();
+
+// Dialog Data
+	enum { IDD = IDD_ABOUT };
+
+protected:
+	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
+	virtual HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor);
+	DECLARE_MESSAGE_MAP()
+public:
+	CStatic m_componentCtrl;
+	CStatic m_legalCtrl;
+	CBrush	m_bkBrush;
+};
diff --git a/mDNSWindows/Applications/ExplorerPlugin/ClassFactory.cpp b/Clients/ExplorerPlugin/ClassFactory.cpp
similarity index 95%
rename from mDNSWindows/Applications/ExplorerPlugin/ClassFactory.cpp
rename to Clients/ExplorerPlugin/ClassFactory.cpp
index 44c9fb2..b4e06c6 100644
--- a/mDNSWindows/Applications/ExplorerPlugin/ClassFactory.cpp
+++ b/Clients/ExplorerPlugin/ClassFactory.cpp
@@ -3,8 +3,6 @@
  *
  * @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
@@ -25,8 +23,14 @@
     Change History (most recent first):
     
 $Log: ClassFactory.cpp,v $
+Revision 1.2  2004/07/13 21:24:21  rpantos
+Fix for <rdar://problem/3701120>.
+
+Revision 1.1  2004/06/18 04:34:59  rpantos
+Move to Clients from mDNSWindows
+
 Revision 1.1  2004/01/30 03:01:56  bradley
-Explorer Plugin to browse for Rendezvous-enabled Web and FTP servers from within Internet Explorer.
+Explorer Plugin to browse for DNS-SD advertised Web and FTP servers from within Internet Explorer.
 
 */
 
diff --git a/mDNSWindows/Applications/ExplorerPlugin/ClassFactory.h b/Clients/ExplorerPlugin/ClassFactory.h
similarity index 88%
rename from mDNSWindows/Applications/ExplorerPlugin/ClassFactory.h
rename to Clients/ExplorerPlugin/ClassFactory.h
index 2361129..76e4b5e 100644
--- a/mDNSWindows/Applications/ExplorerPlugin/ClassFactory.h
+++ b/Clients/ExplorerPlugin/ClassFactory.h
@@ -3,8 +3,6 @@
  *
  * @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
@@ -25,8 +23,14 @@
     Change History (most recent first):
     
 $Log: ClassFactory.h,v $
+Revision 1.2  2004/07/13 21:24:21  rpantos
+Fix for <rdar://problem/3701120>.
+
+Revision 1.1  2004/06/18 04:34:59  rpantos
+Move to Clients from mDNSWindows
+
 Revision 1.1  2004/01/30 03:01:56  bradley
-Explorer Plugin to browse for Rendezvous-enabled Web and FTP servers from within Internet Explorer.
+Explorer Plugin to browse for DNS-SD advertised Web and FTP servers from within Internet Explorer.
 
 */
 
diff --git a/mDNSWindows/Applications/ExplorerPlugin/ExplorerBar.cpp b/Clients/ExplorerPlugin/ExplorerBar.cpp
similarity index 84%
rename from mDNSWindows/Applications/ExplorerPlugin/ExplorerBar.cpp
rename to Clients/ExplorerPlugin/ExplorerBar.cpp
index 4052d77..1c71c9b 100644
--- a/mDNSWindows/Applications/ExplorerPlugin/ExplorerBar.cpp
+++ b/Clients/ExplorerPlugin/ExplorerBar.cpp
@@ -3,8 +3,6 @@
  *
  * @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
@@ -25,8 +23,17 @@
     Change History (most recent first):
     
 $Log: ExplorerBar.cpp,v $
+Revision 1.3  2004/07/26 05:44:08  shersche
+remove extraneous debug statement
+
+Revision 1.2  2004/07/13 21:24:21  rpantos
+Fix for <rdar://problem/3701120>.
+
+Revision 1.1  2004/06/18 04:34:59  rpantos
+Move to Clients from mDNSWindows
+
 Revision 1.1  2004/01/30 03:01:56  bradley
-Explorer Plugin to browse for Rendezvous-enabled Web and FTP servers from within Internet Explorer.
+Explorer Plugin to browse for DNS-SD advertised Web and FTP servers from within Internet Explorer.
 
 */
 
@@ -41,6 +48,7 @@ Explorer Plugin to browse for Rendezvous-enabled Web and FTP servers from within
 
 #include	"ExplorerBar.h"
 
+#include	"About.h"
 // MFC Debugging
 
 #ifdef _DEBUG
@@ -52,7 +60,7 @@ static char THIS_FILE[] = __FILE__;
 //===========================================================================================================================
 //	Constants
 //===========================================================================================================================
-
+#define LENGTHOF(a) (sizeof(a) == sizeof(&*a)) ? 0 : (sizeof(a) / sizeof(*a))
 #define MIN_SIZE_X		10
 #define MIN_SIZE_Y		10
 
@@ -134,6 +142,10 @@ STDMETHODIMP	ExplorerBar::QueryInterface( REFIID inID, LPVOID *outResult )
 	{
 		*outResult = (IPersistStream *) this;
 	}
+	else if( IsEqualIID( inID, IID_IContextMenu ) )     // IContextMenu
+	{
+		*outResult = (IContextMenu *) this;
+	}
 	else
 	{
 		*outResult = NULL;
@@ -525,6 +537,93 @@ STDMETHODIMP	ExplorerBar::GetSizeMax( ULARGE_INTEGER *outSizeMax )
 	return( E_NOTIMPL );
 }
 
+
+//===========================================================================================================================
+//	QueryContextMenu
+//===========================================================================================================================
+
+STDMETHODIMP  ExplorerBar::QueryContextMenu(HMENU hShellContextMenu, UINT iContextMenuFirstItem, UINT idCmdFirst, UINT idCmdLast, UINT uFlags)
+{
+	DEBUG_UNUSED( idCmdLast );
+	DEBUG_UNUSED( uFlags );
+
+	CMenu menubar;
+
+	menubar.LoadMenu(IDR_CONTEXT_MENU);
+	CMenu * menu = menubar.GetSubMenu(0);
+
+	CMenu shellmenu;
+
+	shellmenu.Attach(hShellContextMenu);
+
+	UINT iShellItem = iContextMenuFirstItem;	//! remove plus one
+	UINT idShellCmd = idCmdFirst;
+
+	int n = menu->GetMenuItemCount();
+
+	for (int i=0; i<n; ++i)
+	{
+		MENUITEMINFO	mii;
+		TCHAR				sz[128] = {0};
+		
+		ZeroMemory(&mii, sizeof(mii));
+		mii.fMask		= MIIM_TYPE | MIIM_ID;
+		mii.fType		= MFT_STRING;
+		mii.cbSize		= sizeof(mii);
+		mii.cch			= LENGTHOF(sz);
+		mii.dwTypeData	= sz;
+		
+		menu->GetMenuItemInfo(i, &mii, TRUE);
+
+		mii.wID = idShellCmd++;
+
+		shellmenu.InsertMenuItem(iShellItem++, &mii, TRUE);
+	}
+
+	shellmenu.Detach();
+
+	return n;
+}
+
+
+//===========================================================================================================================
+//	GetCommandString
+//===========================================================================================================================
+
+// Not called for explorer bars
+STDMETHODIMP ExplorerBar::GetCommandString(UINT idCmd, UINT uType, UINT* pwReserved, LPSTR pszName, UINT cchMax)
+{
+	DEBUG_UNUSED( idCmd );
+	DEBUG_UNUSED( uType );
+	DEBUG_UNUSED( pwReserved );
+	DEBUG_UNUSED( pszName );
+	DEBUG_UNUSED( cchMax );
+
+	return E_NOTIMPL;
+}
+
+//===========================================================================================================================
+//	InvokeCommand
+//===========================================================================================================================
+
+//	The shell sends either strings or indexes
+//	IE never sends strings
+//	The indexes are into an array of my commands
+//	So the verb for the first command I added to the menu is always 0x0000
+//	Here - because I don't have any submenus - 
+//		I can treat the 'verb' as an menu item position	
+STDMETHODIMP ExplorerBar::InvokeCommand(LPCMINVOKECOMMANDINFO lpici)
+{
+	// IE doesn't send string commands
+	if (HIWORD(lpici->lpVerb) != 0) return 0;
+
+	CAbout dlg;
+
+	dlg.DoModal();
+
+	return S_OK;
+}
+
 #if 0
 #pragma mark -
 #pragma mark == Other ==
diff --git a/mDNSWindows/Applications/ExplorerPlugin/ExplorerBar.h b/Clients/ExplorerPlugin/ExplorerBar.h
similarity index 83%
rename from mDNSWindows/Applications/ExplorerPlugin/ExplorerBar.h
rename to Clients/ExplorerPlugin/ExplorerBar.h
index 1ab9df9..fe58176 100644
--- a/mDNSWindows/Applications/ExplorerPlugin/ExplorerBar.h
+++ b/Clients/ExplorerPlugin/ExplorerBar.h
@@ -3,8 +3,6 @@
  *
  * @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
@@ -25,8 +23,14 @@
     Change History (most recent first):
     
 $Log: ExplorerBar.h,v $
+Revision 1.2  2004/07/13 21:24:21  rpantos
+Fix for <rdar://problem/3701120>.
+
+Revision 1.1  2004/06/18 04:34:59  rpantos
+Move to Clients from mDNSWindows
+
 Revision 1.1  2004/01/30 03:01:56  bradley
-Explorer Plugin to browse for Rendezvous-enabled Web and FTP servers from within Internet Explorer.
+Explorer Plugin to browse for DNS-SD advertised Web and FTP servers from within Internet Explorer.
 
 */
 
@@ -45,7 +49,8 @@ Explorer Plugin to browse for Rendezvous-enabled Web and FTP servers from within
 class	ExplorerBar : public IDeskBand, 
 					  public IInputObject, 
 					  public IObjectWithSite, 
-					  public IPersistStream
+					  public IPersistStream,
+					  public IContextMenu
 {
 	protected:
 
@@ -103,6 +108,12 @@ class	ExplorerBar : public IDeskBand,
 		STDMETHOD( Save )( LPSTREAM inStream, BOOL inClearDirty );
 		STDMETHOD( GetSizeMax )( ULARGE_INTEGER *outSizeMax );
 		
+		// IContextMenu methods
+   
+		STDMETHOD( QueryContextMenu )( HMENU hContextMenu, UINT iContextMenuFirstItem, UINT idCmdFirst, UINT idCmdLast, UINT uFlags );
+		STDMETHOD( GetCommandString )( UINT idCmd, UINT uType, UINT* pwReserved, LPSTR pszName, UINT cchMax );
+		STDMETHOD( InvokeCommand )( LPCMINVOKECOMMANDINFO lpici );
+
 		// Other
 		
 		OSStatus	SetupWindow( void );
diff --git a/mDNSWindows/Applications/ExplorerPlugin/ExplorerBarWindow.cpp b/Clients/ExplorerPlugin/ExplorerBarWindow.cpp
similarity index 73%
rename from mDNSWindows/Applications/ExplorerPlugin/ExplorerBarWindow.cpp
rename to Clients/ExplorerPlugin/ExplorerBarWindow.cpp
index 7ca9f2a..beb0b35 100644
--- a/mDNSWindows/Applications/ExplorerPlugin/ExplorerBarWindow.cpp
+++ b/Clients/ExplorerPlugin/ExplorerBarWindow.cpp
@@ -3,8 +3,6 @@
  *
  * @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
@@ -25,6 +23,46 @@
     Change History (most recent first):
     
 $Log: ExplorerBarWindow.cpp,v $
+Revision 1.12  2004/10/26 00:56:03  cheshire
+Use "#if 0" instead of commenting out code
+
+Revision 1.11  2004/10/18 23:49:17  shersche
+<rdar://problem/3841564> Remove trailing dot from hostname, because some flavors of Windows have difficulty parsing hostnames with a trailing dot.
+Bug #: 3841564
+
+Revision 1.10  2004/09/02 02:18:58  cheshire
+Minor textual cleanup to improve readability
+
+Revision 1.9  2004/09/02 02:11:56  cheshire
+<rdar://problem/3783611> Fix incorrect testing of MoreComing flag
+
+Revision 1.8  2004/07/26 05:47:31  shersche
+use TXTRecord APIs, fix bug in locating service to be removed
+
+Revision 1.7  2004/07/22 16:08:20  shersche
+clean up debug print statements, re-enable code inadvertently commented out
+
+Revision 1.6  2004/07/22 05:27:20  shersche
+<rdar://problem/3735827> Check to make sure error isn't WSAEWOULDBLOCK when canceling browse
+Bug #: 3735827
+
+Revision 1.5  2004/07/20 06:49:18  shersche
+clean up socket handling code
+
+Revision 1.4  2004/07/13 21:24:21  rpantos
+Fix for <rdar://problem/3701120>.
+
+Revision 1.3  2004/06/27 14:59:59  shersche
+reference count service info to handle multi-homed hosts
+
+Revision 1.2  2004/06/23 16:09:34  shersche
+Add the resolve DNSServiceRef to list of extant refs.  This fixes the "doesn't resolve when double clicking" problem
+
+Submitted by: Scott Herscher
+
+Revision 1.1  2004/06/18 04:34:59  rpantos
+Move to Clients from mDNSWindows
+
 Revision 1.5  2004/04/15 01:00:05  bradley
 Removed support for automatically querying for A/AAAA records when resolving names. Platforms
 without .local name resolving support will need to manually query for A/AAAA records as needed.
@@ -39,7 +77,7 @@ 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.
+Explorer Plugin to browse for DNS-SD advertised Web and FTP servers from within Internet Explorer.
 
 */
 
@@ -47,7 +85,8 @@ Explorer Plugin to browse for Rendezvous-enabled Web and FTP servers from within
 
 #include	"CommonServices.h"
 #include	"DebugServices.h"
-#include	"DNSSD.h"
+#include	"WinServices.h"
+#include	"dns_sd.h"
 
 #include	"ExplorerBar.h"
 #include	"LoginDialog.h"
@@ -77,14 +116,11 @@ static char THIS_FILE[] = __FILE__;
 
 // 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 )
+#define WM_PRIVATE_SERVICE_EVENT				( WM_USER + 0x100 )
 
 // TXT records
 
-#define	kTXTRecordKeyPath				"path="
-#define	kTXTRecordKeyPathSize			sizeof_string( kTXTRecordKeyPath )
+#define	kTXTRecordKeyPath				"path"
 
 #if 0
 #pragma mark == Prototypes ==
@@ -95,7 +131,6 @@ static char THIS_FILE[] = __FILE__;
 //===========================================================================================================================
 
 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 ==
@@ -110,9 +145,7 @@ BEGIN_MESSAGE_MAP( ExplorerBarWindow, CWnd )
 	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 )
+	ON_MESSAGE( WM_PRIVATE_SERVICE_EVENT, OnServiceEvent )
 END_MESSAGE_MAP()
 
 #if 0
@@ -152,25 +185,16 @@ int	ExplorerBarWindow::OnCreate( LPCREATESTRUCT inCreateStruct )
 	
 	OSStatus		err;
 	CRect			rect;
+	CBitmap			bitmap;
 	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, 
+	mTree.Create( WS_TABSTOP | WS_VISIBLE | WS_CHILD | TVS_HASBUTTONS | TVS_LINESATROOT | TVS_HASLINES | TVS_NOHSCROLL , 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;
 	
@@ -194,6 +218,11 @@ int	ExplorerBarWindow::OnCreate( LPCREATESTRUCT inCreateStruct )
 	err = DNSServiceBrowse( &e->ref, 0, 0, e->type, NULL, BrowseCallBack, e );
 	require_noerr( err, exit );
 
+	err = WSAAsyncSelect((SOCKET) DNSServiceRefSockFD(e->ref), m_hWnd, WM_PRIVATE_SERVICE_EVENT, FD_READ|FD_CLOSE);
+	require_noerr( err, exit );
+
+	m_serviceRefs.push_back(e->ref); 
+
 	// FTP Site Handler
 	
 	e = new ServiceHandlerEntry;
@@ -213,8 +242,29 @@ int	ExplorerBarWindow::OnCreate( LPCREATESTRUCT inCreateStruct )
 	
 	err = DNSServiceBrowse( &e->ref, 0, 0, e->type, NULL, BrowseCallBack, e );
 	require_noerr( err, exit );
+
+	err = WSAAsyncSelect((SOCKET) DNSServiceRefSockFD(e->ref), m_hWnd, WM_PRIVATE_SERVICE_EVENT, FD_READ|FD_CLOSE);
+	require_noerr( err, exit );
+
+	m_serviceRefs.push_back(e->ref); 
+
+	m_imageList.Create(16, 16, ILC_COLORDDB, 1, 0);
+	bitmap.LoadBitmap(IDB_LOGO);
+	m_imageList.Add(&bitmap, (CBitmap*) NULL);
+
+	mTree.SetImageList(&m_imageList, TVSIL_NORMAL);
 	
 exit:
+
+	// Cannot talk to the mDNSResponder service. Show the error message and exit (with kNoErr so they can see it).
+	if ( err != kNoErr )
+	{
+		s.LoadString( IDS_MDNSRESPONDER_NOT_AVAILABLE );
+		mTree.DeleteAllItems();
+		mTree.InsertItem( s, 0, 0, TVI_ROOT, TVI_LAST );
+		err = kNoErr;
+	}
+
 	return( err );
 }
 
@@ -228,6 +278,20 @@ void	ExplorerBarWindow::OnDestroy( void )
 	
 	StopResolve();
 	
+	// Clean up the extant browses
+	while (m_serviceRefs.size() > 0)
+	{
+		//
+		// take the head of the list
+		//
+		DNSServiceRef ref = m_serviceRefs.front();
+
+		//
+		// Stop will remove it from the list
+		//
+		Stop( ref );
+	}
+
 	// Clean up the service handlers.
 	
 	int		i;
@@ -239,7 +303,6 @@ void	ExplorerBarWindow::OnDestroy( void )
 		delete mServiceHandlers[ i ];
 	}
 	
-	DNSServiceFinalize();
 	CWnd::OnDestroy();
 }
 
@@ -278,6 +341,56 @@ exit:
 	*outResult = 0;
 }
 
+
+//===========================================================================================================================
+//	OnServiceEvent
+//===========================================================================================================================
+
+LONG
+ExplorerBarWindow::OnServiceEvent(WPARAM inWParam, LPARAM inLParam)
+{
+	if (WSAGETSELECTERROR(inLParam) && !(HIWORD(inLParam)))
+    {
+		dlog( kDebugLevelError, "OnServiceEvent: window error\n" );
+    }
+    else
+    {
+		SOCKET sock = (SOCKET) inWParam;
+
+		// iterate thru list
+		ServiceRefList::iterator it;
+
+		for (it = m_serviceRefs.begin(); it != m_serviceRefs.end(); it++)
+		{
+			DNSServiceRef ref = *it;
+
+			check(ref != NULL);
+
+			if ((SOCKET) DNSServiceRefSockFD(ref) == sock)
+			{
+				DNSServiceErrorType err;
+
+				err = DNSServiceProcessResult(ref);
+
+				if (err != 0)
+				{
+					CString s;
+
+					s.LoadString( IDS_MDNSRESPONDER_NOT_AVAILABLE );
+					mTree.DeleteAllItems();
+					mTree.InsertItem( s, 0, 0, TVI_ROOT, TVI_LAST );
+
+					Stop(ref);
+				}
+
+				break;
+			}
+		}
+	}
+
+	return ( 0 );
+}
+
 #if 0
 #pragma mark -
 #endif
@@ -286,7 +399,7 @@ exit:
 //	BrowseCallBack
 //===========================================================================================================================
 
-void CALLBACK_COMPAT
+void DNSSD_API
 	ExplorerBarWindow::BrowseCallBack(
 		DNSServiceRef 			inRef,
 		DNSServiceFlags 		inFlags,
@@ -303,6 +416,7 @@ void CALLBACK_COMPAT
 	
 	DEBUG_UNUSED( inRef );
 	
+	obj		=	NULL;
 	service = NULL;
 	
 	require_noerr( inErrorCode, exit );
@@ -310,16 +424,19 @@ void CALLBACK_COMPAT
 	check( obj );
 	check( obj->obj );
 	
+	//
+	// set the UI to hold off on updates
+	//
+	obj->obj->mTree.SetRedraw(FALSE);
+
 	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 );
 		
@@ -331,17 +448,13 @@ void CALLBACK_COMPAT
 		
 		service->ifi 		= inInterfaceIndex;
 		service->handler	= obj;
+
+		service->refs		= 1;
 		
-		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;
-		}
+		if (inFlags & kDNSServiceFlagsAdd) obj->obj->OnServiceAdd   (service);
+		else                               obj->obj->OnServiceRemove(service);
+	
+		service = NULL;
 	}
 	catch( ... )
 	{
@@ -349,6 +462,15 @@ void CALLBACK_COMPAT
 	}
 	
 exit:
+	//
+	// If no more coming, then update UI
+	//
+	if (obj && obj->obj && ((inFlags & kDNSServiceFlagsMoreComing) == 0))
+	{
+		obj->obj->mTree.SetRedraw(TRUE);
+		obj->obj->mTree.Invalidate();
+	}
+
 	if( service )
 	{
 		delete service;
@@ -359,16 +481,13 @@ exit:
 //	OnServiceAdd
 //===========================================================================================================================
 
-LONG	ExplorerBarWindow::OnServiceAdd( WPARAM inWParam, LPARAM inLParam )
+LONG	ExplorerBarWindow::OnServiceAdd( ServiceInfo * service )
 {
-	ServiceInfo *				service;
 	ServiceHandlerEntry *		handler;
 	int							cmp;
 	int							index;
 	
-	DEBUG_UNUSED( inWParam );
 	
-	service = reinterpret_cast < ServiceInfo * > ( inLParam );
 	check( service );
 	handler = service->handler; 
 	check( handler );
@@ -380,12 +499,10 @@ LONG	ExplorerBarWindow::OnServiceAdd( WPARAM inWParam, LPARAM inLParam )
 		
 		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 );
+
+		handler->array[ index ]->refs++;
+
+		delete service;
 	}
 	else
 	{
@@ -413,16 +530,13 @@ LONG	ExplorerBarWindow::OnServiceAdd( WPARAM inWParam, LPARAM inLParam )
 //	OnServiceRemove
 //===========================================================================================================================
 
-LONG	ExplorerBarWindow::OnServiceRemove( WPARAM inWParam, LPARAM inLParam )
+LONG	ExplorerBarWindow::OnServiceRemove( ServiceInfo * service )
 {
-	ServiceInfo *				service;
 	ServiceHandlerEntry *		handler;
 	int							cmp;
 	int							index;
 	
-	DEBUG_UNUSED( inWParam );
 	
-	service = reinterpret_cast < ServiceInfo * > ( inLParam );
 	check( service );
 	handler = service->handler; 
 	check( handler );
@@ -431,17 +545,22 @@ LONG	ExplorerBarWindow::OnServiceRemove( WPARAM inWParam, LPARAM inLParam )
 	
 	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.
-		
+		// Possibly 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 );
+
+		if ( --handler->array[ index ]->refs == 0 )
+		{
+			mTree.DeleteItem( handler->array[ index ]->item );
+			delete handler->array[ index ];
+			handler->array.RemoveAt( index );
+		}
 	}
+
 	delete service;
 	return( 0 );
 }
@@ -465,11 +584,15 @@ OSStatus	ExplorerBarWindow::StartResolve( ServiceInfo *inService )
 	StopResolve();
 	
 	// Resolve the service.
-	
-	err = DNSServiceResolve( &mResolveServiceRef, kDNSServiceFlagsNone, inService->ifi, 
-		inService->name, inService->type, inService->domain, ResolveCallBack, inService->handler );
+	err = DNSServiceResolve( &mResolveServiceRef, 0, 0, 
+		inService->name, inService->type, inService->domain, (DNSServiceResolveReply) ResolveCallBack, inService->handler );
+	require_noerr( err, exit );
+
+	err = WSAAsyncSelect((SOCKET) DNSServiceRefSockFD(mResolveServiceRef), m_hWnd, WM_PRIVATE_SERVICE_EVENT, FD_READ|FD_CLOSE);
 	require_noerr( err, exit );
 	
+	m_serviceRefs.push_back(mResolveServiceRef);
+
 exit:
 	return( err );
 }
@@ -482,7 +605,7 @@ void	ExplorerBarWindow::StopResolve( void )
 {
 	if( mResolveServiceRef )
 	{
-		DNSServiceRefDeallocate( mResolveServiceRef );
+		Stop( mResolveServiceRef );
 		mResolveServiceRef = NULL;
 	}
 }
@@ -491,7 +614,7 @@ void	ExplorerBarWindow::StopResolve( void )
 //	ResolveCallBack
 //===========================================================================================================================
 
-void CALLBACK_COMPAT
+void DNSSD_API
 	ExplorerBarWindow::ResolveCallBack(
 		DNSServiceRef			inRef,
 		DNSServiceFlags			inFlags,
@@ -522,7 +645,7 @@ void CALLBACK_COMPAT
 	try
 	{
 		ResolveInfo *		resolve;
-		BOOL				ok;
+		int					idx;
 		
 		dlog( kDebugLevelNotice, "resolved %s on ifi %d to %s\n", inFullName, inInterfaceIndex, inHostName );
 		
@@ -536,6 +659,19 @@ void CALLBACK_COMPAT
 		require_action( resolve, exit, err = kNoMemoryErr );
 		
 		UTF8StringToStringObject( inHostName, resolve->host );
+
+		// rdar://problem/3841564
+		// 
+		// strip trailing dot from hostname because some flavors of Windows
+		// have trouble parsing it.
+
+		idx = resolve->host.ReverseFind('.');
+
+		if ((idx > 1) && ((resolve->host.GetLength() - 1) == idx))
+		{
+			resolve->host.Delete(idx, 1);
+		}
+
 		resolve->port		= ntohs( inPort );
 		resolve->ifi		= inInterfaceIndex;
 		resolve->handler	= handler;
@@ -543,12 +679,7 @@ void CALLBACK_COMPAT
 		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;
-		}
+		obj->OnResolve(resolve);
 	}
 	catch( ... )
 	{
@@ -563,19 +694,16 @@ exit:
 //	OnResolve
 //===========================================================================================================================
 
-LONG	ExplorerBarWindow::OnResolve( WPARAM inWParam, LPARAM inLParam )
+LONG	ExplorerBarWindow::OnResolve( ResolveInfo * resolve )
 {
-	ResolveInfo *		resolve;
 	CString				url;
 	uint8_t *			path;
-	size_t				pathSize;
+	uint8_t				pathSize;
 	char *				pathPrefix;
 	CString				username;
 	CString				password;
 	
-	DEBUG_UNUSED( inWParam );
 	
-	resolve = reinterpret_cast < ResolveInfo * > ( inLParam );
 	check( resolve );
 		
 	// Get login info if needed.
@@ -595,30 +723,23 @@ LONG	ExplorerBarWindow::OnResolve( WPARAM inWParam, LPARAM inLParam )
 	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 != '/' )
+		uint8_t	*	txtData;
+		uint16_t	txtLen;	
+
+		resolve->txt.GetData( &txtData, &txtLen );
+
+		path	 = (uint8_t*) TXTRecordGetValuePtr(txtLen, txtData, kTXTRecordKeyPath, &pathSize);
+
+		if (path == NULL)
 		{
-			pathPrefix = "/";
+			path = (uint8_t*) "";
+			pathSize = 1;
 		}
 	}
 	else
 	{
-		path			= (uint8_t *) "";
-		pathSize		= 1;
+		path		= (uint8_t *) "";
+		pathSize	= 1;
 	}
 
 	// Build the URL in the following format:
@@ -651,6 +772,19 @@ exit:
 	return( 0 );
 }
 
+//===========================================================================================================================
+//	Stop
+//===========================================================================================================================
+void ExplorerBarWindow::Stop( DNSServiceRef ref )
+{
+	m_serviceRefs.remove( ref );
+
+	WSAAsyncSelect(DNSServiceRefSockFD( ref ), m_hWnd, WM_PRIVATE_SERVICE_EVENT, 0);
+
+	DNSServiceRefDeallocate( ref );
+}
+
+
 #if 0
 #pragma mark -
 #endif
@@ -674,10 +808,12 @@ DEBUG_LOCAL int	FindServiceArrayIndex( const ServiceInfoArray &inArray, const Se
 	{
 		mid = ( lo + hi ) / 2;
 		result = inService.displayName.CompareNoCase( inArray[ mid ]->displayName );
+#if 0
 		if( result == 0 )
 		{
 			result = ( (int) inService.ifi ) - ( (int) inArray[ mid ]->ifi );
 		}
+#endif
 		if( result == 0 )
 		{
 			break;
@@ -702,50 +838,3 @@ DEBUG_LOCAL int	FindServiceArrayIndex( const ServiceInfoArray &inArray, const Se
 	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/Clients/ExplorerPlugin/ExplorerBarWindow.h
similarity index 83%
rename from mDNSWindows/Applications/ExplorerPlugin/ExplorerBarWindow.h
rename to Clients/ExplorerPlugin/ExplorerBarWindow.h
index ac234f5..afa4e99 100644
--- a/mDNSWindows/Applications/ExplorerPlugin/ExplorerBarWindow.h
+++ b/Clients/ExplorerPlugin/ExplorerBarWindow.h
@@ -3,8 +3,6 @@
  *
  * @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
@@ -25,6 +23,21 @@
     Change History (most recent first):
     
 $Log: ExplorerBarWindow.h,v $
+Revision 1.5  2004/07/26 05:47:31  shersche
+use TXTRecord APIs, fix bug in locating service to be removed
+
+Revision 1.4  2004/07/20 06:49:18  shersche
+clean up socket handling code
+
+Revision 1.3  2004/07/13 21:24:21  rpantos
+Fix for <rdar://problem/3701120>.
+
+Revision 1.2  2004/06/27 14:59:59  shersche
+reference count service info to handle multi-homed hosts
+
+Revision 1.1  2004/06/18 04:34:59  rpantos
+Move to Clients from mDNSWindows
+
 Revision 1.3  2004/04/15 01:00:05  bradley
 Removed support for automatically querying for A/AAAA records when resolving names. Platforms
 without .local name resolving support will need to manually query for A/AAAA records as needed.
@@ -33,7 +46,7 @@ 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.
+Explorer Plugin to browse for DNS-SD advertised Web and FTP servers from within Internet Explorer.
 
 */
 
@@ -44,7 +57,8 @@ Explorer Plugin to browse for Rendezvous-enabled Web and FTP servers from within
 
 #include	"afxtempl.h"
 
-#include	"DNSSD.h"
+#include	"dns_sd.h"
+#include	<list>
 
 //===========================================================================================================================
 //	Structures
@@ -66,6 +80,7 @@ struct	ServiceInfo
 	uint32_t					ifi;
 	HTREEITEM					item;
 	ServiceHandlerEntry *		handler;
+	DWORD						refs;
 	
 	ServiceInfo( void )
 	{
@@ -99,7 +114,7 @@ typedef CArray < ServiceInfo *, ServiceInfo * >		ServiceInfoArray;
 struct	TextRecord
 {
 	uint8_t *		mData;
-	size_t			mSize;
+	uint16_t		mSize;
 	
 	TextRecord( void )
 	{
@@ -115,7 +130,7 @@ struct	TextRecord
 		}
 	}
 	
-	void	GetData( void *outData, size_t *outSize )
+	void	GetData( void *outData, uint16_t *outSize )
 	{
 		if( outData )
 		{
@@ -127,7 +142,7 @@ struct	TextRecord
 		}
 	}
 	
-	OSStatus	SetData( const void *inData, size_t inSize )
+	OSStatus	SetData( const void *inData, uint16_t inSize )
 	{
 		OSStatus		err;
 		uint8_t *		newData;
@@ -186,11 +201,6 @@ struct	ServiceHandlerEntry
 	
 	~ServiceHandlerEntry( void )
 	{
-		if( ref )
-		{
-			DNSServiceRefDeallocate( ref );
-		}
-		
 		int		i;
 		int		n;
 		
@@ -233,10 +243,11 @@ class	ExplorerBarWindow : public CWnd
 		afx_msg void	OnDestroy( void );
 		afx_msg void	OnSize( UINT inType, int inX, int inY );
 		afx_msg void	OnDoubleClick( NMHDR *inNMHDR, LRESULT *outResult );
+		afx_msg LONG	OnServiceEvent( WPARAM inWParam, LPARAM inLParam );
 		
 		// Browsing
 		
-		static void CALLBACK_COMPAT
+		static void DNSSD_API
 			BrowseCallBack(
 				DNSServiceRef 			inRef,
 				DNSServiceFlags 		inFlags,
@@ -246,15 +257,19 @@ class	ExplorerBarWindow : public CWnd
 				const char *			inType,	
 				const char *			inDomain,	
 				void *					inContext );
-		afx_msg LONG OnServiceAdd( WPARAM inWParam, LPARAM inLParam );
-		afx_msg LONG OnServiceRemove( WPARAM inWParam, LPARAM inLParam );
+		LONG OnServiceAdd( ServiceInfo * service );
+		LONG OnServiceRemove( ServiceInfo * service );
 		
 		// Resolving
 		
 		OSStatus	StartResolve( ServiceInfo *inService );
 		void		StopResolve( void );
 
-		static void CALLBACK_COMPAT
+
+		void		Stop( DNSServiceRef ref );
+
+
+		static void DNSSD_API
 			ResolveCallBack(
 				DNSServiceRef			inRef,
 				DNSServiceFlags			inFlags,
@@ -266,7 +281,7 @@ class	ExplorerBarWindow : public CWnd
 				uint16_t 				inTXTSize,
 				const char *			inTXT,
 				void *					inContext );
-		afx_msg LONG OnResolve( WPARAM inWParam, LPARAM inLParam );		
+		LONG OnResolve( ResolveInfo * resolve );		
 				
 		// Accessors
 	
@@ -276,6 +291,12 @@ class	ExplorerBarWindow : public CWnd
 		void			SetOwner( ExplorerBar *inOwner )	{ mOwner = inOwner; }
 		
 		DECLARE_MESSAGE_MAP()
+	private:
+
+		typedef std::list< DNSServiceRef >  ServiceRefList;
+		
+		ServiceRefList	m_serviceRefs;
+		CImageList		m_imageList;
 };
 
 #endif	// __EXPLORER_BAR_WINDOW__
diff --git a/mDNSWindows/Applications/ExplorerPlugin/ExplorerPlugin.cpp b/Clients/ExplorerPlugin/ExplorerPlugin.cpp
similarity index 83%
rename from mDNSWindows/Applications/ExplorerPlugin/ExplorerPlugin.cpp
rename to Clients/ExplorerPlugin/ExplorerPlugin.cpp
index 9528577..5de124d 100644
--- a/mDNSWindows/Applications/ExplorerPlugin/ExplorerPlugin.cpp
+++ b/Clients/ExplorerPlugin/ExplorerPlugin.cpp
@@ -3,8 +3,6 @@
  *
  * @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
@@ -25,8 +23,25 @@
     Change History (most recent first):
     
 $Log: ExplorerPlugin.cpp,v $
+Revision 1.5  2004/09/15 10:33:54  shersche
+<rdar://problem/3721611> Install XP toolbar button (8 bit mask) if running on XP platform, otherwise install 1 bit mask toolbar button
+Bug #: 3721611
+
+Revision 1.4  2004/07/13 21:24:21  rpantos
+Fix for <rdar://problem/3701120>.
+
+Revision 1.3  2004/06/26 14:12:07  shersche
+Register the toolbar button
+
+Revision 1.2  2004/06/24 20:09:39  shersche
+Change text
+Submitted by: herscher
+
+Revision 1.1  2004/06/18 04:34:59  rpantos
+Move to Clients from mDNSWindows
+
 Revision 1.1  2004/01/30 03:01:56  bradley
-Explorer Plugin to browse for Rendezvous-enabled Web and FTP servers from within Internet Explorer.
+Explorer Plugin to browse for DNS-SD advertised Web and FTP servers from within Internet Explorer.
 
 */
 
@@ -114,7 +129,7 @@ BOOL WINAPI	DllMain( HINSTANCE inInstance, DWORD inReason, LPVOID inReserved )
 	{
 		case DLL_PROCESS_ATTACH:
 			gInstance = inInstance;
-			debug_initialize( kDebugOutputTypeWindowsEventLog, "RendezvousBar", inInstance );
+			debug_initialize( kDebugOutputTypeWindowsEventLog, "DNSServices Bar", inInstance );
 			debug_set_property( kDebugPropertyTagPrintLevel, kDebugLevelTrace );
 			dlog( kDebugLevelTrace, "\nDllMain: process attach\n" );
 			
@@ -436,7 +451,53 @@ DEBUG_LOCAL OSStatus	RegisterServer( HINSTANCE inInstance, CLSID inCLSID, LPCTST
 		err = RegSetValueEx( key, clsidString, 0, REG_SZ, (LPBYTE) data, size );
 		RegCloseKey( key );
 	}
-	err = kNoErr;
+
+	// register toolbar button
+	lstrcpyn( keyName, TEXT( "SOFTWARE\\Microsoft\\Internet Explorer\\Extensions\\{7F9DB11C-E358-4ca6-A83D-ACC663939424}"), 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, L"Yes", sizeof_array( data ) );
+	size = (DWORD)( ( lstrlen( data ) + 1 ) * sizeof( TCHAR ) );
+	RegSetValueEx( key, L"Default Visible", 0, REG_SZ, (LPBYTE) data, size );
+
+	lstrcpyn( data, inName, sizeof_array( data ) );
+	size = (DWORD)( ( lstrlen( data ) + 1 ) * sizeof( TCHAR ) );
+	RegSetValueEx( key, L"ButtonText", 0, REG_SZ, (LPBYTE) data, size );
+	
+	lstrcpyn( data, L"{E0DD6CAB-2D10-11D2-8F1A-0000F87ABD16}", sizeof_array( data ) );
+	size = (DWORD)( ( lstrlen( data ) + 1 ) * sizeof( TCHAR ) );
+	RegSetValueEx( key, L"CLSID", 0, REG_SZ, (LPBYTE) data, size );
+
+	lstrcpyn( data, clsidString, sizeof_array( data ) );
+	size = (DWORD)( ( lstrlen( data ) + 1 ) * sizeof( TCHAR ) );
+	RegSetValueEx( key, L"BandCLSID", 0, REG_SZ, (LPBYTE) data, size );
+
+	// check if we're running XP or later
+	if ( ( versionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT ) &&
+		 ( versionInfo.dwMajorVersion == 5 ) &&
+	     ( versionInfo.dwMinorVersion >= 1 ) )
+	{
+		wsprintf( data, L"%s,%d", moduleName, IDI_BUTTON_XP );
+		size = (DWORD)( ( lstrlen( data ) + 1 ) * sizeof( TCHAR ) );
+		RegSetValueEx( key, L"Icon", 0, REG_SZ, (LPBYTE) data, size);
+
+		wsprintf( data, L"%s,%d", moduleName, IDI_BUTTON_XP );
+		size = (DWORD)( ( lstrlen( data ) + 1 ) * sizeof( TCHAR ) );
+		RegSetValueEx( key, L"HotIcon", 0, REG_SZ, (LPBYTE) data, size);
+	}
+	else
+	{
+		wsprintf( data, L"%s,%d", moduleName, IDI_BUTTON_2K );
+		size = (DWORD)( ( lstrlen( data ) + 1 ) * sizeof( TCHAR ) );
+		RegSetValueEx( key, L"Icon", 0, REG_SZ, (LPBYTE) data, size);
+
+		wsprintf( data, L"%s,%d", moduleName, IDI_BUTTON_2K );
+		size = (DWORD)( ( lstrlen( data ) + 1 ) * sizeof( TCHAR ) );
+		RegSetValueEx( key, L"HotIcon", 0, REG_SZ, (LPBYTE) data, size);
+	}
+
+	RegCloseKey( key );
 	
 exit:
 	return( err );
diff --git a/mDNSWindows/Applications/ExplorerPlugin/ExplorerPlugin.def b/Clients/ExplorerPlugin/ExplorerPlugin.def
similarity index 82%
rename from mDNSWindows/Applications/ExplorerPlugin/ExplorerPlugin.def
rename to Clients/ExplorerPlugin/ExplorerPlugin.def
index 028856c..e825180 100644
--- a/mDNSWindows/Applications/ExplorerPlugin/ExplorerPlugin.def
+++ b/Clients/ExplorerPlugin/ExplorerPlugin.def
@@ -23,8 +23,14 @@
 ;	Change History (most recent first):
 ;    
 ; $Log: ExplorerPlugin.def,v $
+; Revision 1.2  2004/07/13 21:24:21  rpantos
+; Fix for <rdar://problem/3701120>.
+;
+; Revision 1.1  2004/06/18 04:34:59  rpantos
+; Move to Clients from mDNSWindows
+;
 ; Revision 1.1  2004/01/30 03:01:56  bradley
-; Explorer Plugin to browse for Rendezvous-enabled Web and FTP servers from within Internet Explorer.
+; Explorer Plugin to browse for DNS-SD advertised Web and FTP servers from within Internet Explorer.
 ;
 ;
 
diff --git a/mDNSWindows/Applications/ExplorerPlugin/ExplorerPlugin.h b/Clients/ExplorerPlugin/ExplorerPlugin.h
similarity index 86%
rename from mDNSWindows/Applications/ExplorerPlugin/ExplorerPlugin.h
rename to Clients/ExplorerPlugin/ExplorerPlugin.h
index e072af0..0acca3f 100644
--- a/mDNSWindows/Applications/ExplorerPlugin/ExplorerPlugin.h
+++ b/Clients/ExplorerPlugin/ExplorerPlugin.h
@@ -3,8 +3,6 @@
  *
  * @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
@@ -25,8 +23,14 @@
     Change History (most recent first):
     
 $Log: ExplorerPlugin.h,v $
+Revision 1.2  2004/07/13 21:24:21  rpantos
+Fix for <rdar://problem/3701120>.
+
+Revision 1.1  2004/06/18 04:34:59  rpantos
+Move to Clients from mDNSWindows
+
 Revision 1.1  2004/01/30 03:01:56  bradley
-Explorer Plugin to browse for Rendezvous-enabled Web and FTP servers from within Internet Explorer.
+Explorer Plugin to browse for DNS-SD advertised Web and FTP servers from within Internet Explorer.
 
 */
 
diff --git a/mDNSWindows/Applications/ExplorerPlugin/ExplorerPlugin.rc b/Clients/ExplorerPlugin/ExplorerPlugin.rc
similarity index 66%
rename from mDNSWindows/Applications/ExplorerPlugin/ExplorerPlugin.rc
rename to Clients/ExplorerPlugin/ExplorerPlugin.rc
index f9e79ba..7879e58 100644
--- a/mDNSWindows/Applications/ExplorerPlugin/ExplorerPlugin.rc
+++ b/Clients/ExplorerPlugin/ExplorerPlugin.rc
@@ -8,6 +8,7 @@
 // Generated from the TEXTINCLUDE 2 resource.
 //
 #include "afxres.h"
+#include "WinVersRes.h"
 
 /////////////////////////////////////////////////////////////////////////////
 #undef APSTUDIO_READONLY_SYMBOLS
@@ -35,6 +36,7 @@ END
 2 TEXTINCLUDE 
 BEGIN
     "#include ""afxres.h""\r\n"
+    "#include ""WinVersRes.h""\r\n"
     "\0"
 END
 
@@ -62,8 +64,8 @@ END
 //
 
 VS_VERSION_INFO VERSIONINFO
- FILEVERSION 1,0,0,1
- PRODUCTVERSION 1,0,0,1
+ FILEVERSION MASTER_PROD_VERS
+ PRODUCTVERSION MASTER_PROD_VERS
  FILEFLAGSMASK 0x3fL
 #ifdef _DEBUG
  FILEFLAGS 0x1L
@@ -76,16 +78,16 @@ VS_VERSION_INFO VERSIONINFO
 BEGIN
     BLOCK "StringFileInfo"
     BEGIN
-        BLOCK "040904B0"
+        BLOCK "040904b0"
         BEGIN
             VALUE "CompanyName", "Apple Computer, Inc."
-            VALUE "FileDescription", "Rendezvous Bar"
-            VALUE "FileVersion", "1.0.0.1"
+            VALUE "FileDescription", "DNSServices Explorer Bar"
+            VALUE "FileVersion", MASTER_PROD_VERS_STR
             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"
+            VALUE "ProductName", MASTER_PROD_NAME
+            VALUE "ProductVersion", MASTER_PROD_VERS_STR
         END
     END
     BLOCK "VarFileInfo"
@@ -116,6 +118,20 @@ BEGIN
     PUSHBUTTON      "Cancel",IDCANCEL,77,70,44,14
 END
 
+IDD_ABOUT DIALOGEX 0, 0, 219, 87
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_RTLREADING | WS_EX_LEFTSCROLLBAR
+CAPTION "About Rendezvous"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+    CONTROL         119,IDC_STATIC,"Static",SS_BITMAP | SS_REALSIZEIMAGE,0,0,
+                    220,86
+    CONTROL         MASTER_PROD_VERS_STR3,IDC_COMPONENT,"Static",
+                    SS_SIMPLE | WS_GROUP,92,10,122,8
+    LTEXT           "Copyright (c) 2004 Apple Computer, Inc. All rights reserved. Apple and the Apple logo are trademarks of Apple Computer, Inc., registered in the U.S. and other countries.",
+                    IDC_LEGAL,92,31,123,50,0,WS_EX_RTLREADING
+END
+
 
 /////////////////////////////////////////////////////////////////////////////
 //
@@ -129,10 +145,48 @@ BEGIN
     BEGIN
         BOTTOMMARGIN, 62
     END
+
+    IDD_ABOUT, DIALOG
+    BEGIN
+        BOTTOMMARGIN, 132
+    END
 END
 #endif    // APSTUDIO_INVOKED
 
 
+/////////////////////////////////////////////////////////////////////////////
+//
+// Bitmap
+//
+
+IDB_LOGO                BITMAP                  "res\\logo.bmp"
+IDB_ABOUT               BITMAP                  "res\\about.bmp"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_BUTTON_2K           ICON                    "res\\button-2k.ico"
+IDI_BUTTON_XP           ICON                    "res\\button-xp.ico"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Menu
+//
+
+IDR_CONTEXT_MENU MENU 
+BEGIN
+    POPUP "ContextMenu"
+    BEGIN
+        MENUITEM "About Rendezvous...",         ID_Menu
+        MENUITEM SEPARATOR
+    END
+END
+
+
 /////////////////////////////////////////////////////////////////////////////
 //
 // String Table
@@ -144,7 +198,7 @@ BEGIN
     IDS_WEB_SITES           "Web Sites"
     IDS_FTP_SITES           "FTP Sites"
     IDS_PRINTERS            "Printers"
-    IDS_RENDEZVOUS_NOT_AVAILABLE "Rendezvous Not Available"
+    IDS_MDNSRESPONDER_NOT_AVAILABLE "Rendezvous Service Not Available"
 END
 
 #endif    // English (U.S.) resources
diff --git a/mDNSWindows/Applications/ExplorerPlugin/ExplorerPlugin.vcproj b/Clients/ExplorerPlugin/ExplorerPlugin.vcproj
similarity index 58%
rename from mDNSWindows/Applications/ExplorerPlugin/ExplorerPlugin.vcproj
rename to Clients/ExplorerPlugin/ExplorerPlugin.vcproj
index ec8b589..62f37fc 100644
--- a/mDNSWindows/Applications/ExplorerPlugin/ExplorerPlugin.vcproj
+++ b/Clients/ExplorerPlugin/ExplorerPlugin.vcproj
@@ -22,34 +22,36 @@
 			<Tool
 				Name="VCCLCompilerTool"
 				Optimization="0"
-				AdditionalIncludeDirectories="..\..\"
-				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;DEBUG=1;DNS_SD_DIRECT_ENABLED=0"
+				AdditionalIncludeDirectories="..\..\mDNSShared;..\..\mDNSWindows"
+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;DEBUG=1;ENABLE_DOT_LOCAL_NAMES;WINVER=0x0400"
 				StringPooling="TRUE"
 				BasicRuntimeChecks="3"
 				RuntimeLibrary="1"
 				ForceConformanceInForLoopScope="TRUE"
-				UsePrecompiledHeader="2"
-				PrecompiledHeaderFile="$(OutDir)/$(ProjectName).pch"
+				UsePrecompiledHeader="0"
+				PrecompiledHeaderFile=""
 				AssemblerListingLocation=".\Debug/"
 				ObjectFile=".\Debug/"
 				ProgramDataBaseFileName=".\Debug/"
 				BrowseInformation="1"
 				WarningLevel="4"
-				WarnAsError="TRUE"
+				WarnAsError="FALSE"
 				SuppressStartupBanner="TRUE"
 				Detect64BitPortabilityProblems="TRUE"
 				DebugInformationFormat="3"
+				CallingConvention="2"
 				CompileAs="0"/>
 			<Tool
 				Name="VCCustomBuildTool"
 				Description="Registering"
-				CommandLine="regsvr32.exe /s /c $(OutDir)/$(ProjectName).dll
+				CommandLine="regsvr32.exe /s /c $(OutDir)/ExplorerPlugin.dll
 "
 				Outputs="$(OUTDIR)\Register.out"/>
 			<Tool
 				Name="VCLinkerTool"
 				AdditionalOptions="/MACHINE:I386 /IGNORE:4089 "
-				AdditionalDependencies="uafxcwd.lib ws2_32.lib"
+				AdditionalDependencies="../../mDNSWindows/DLL/Debug/dnssd.lib uafxcwd.lib ws2_32.lib"
+				OutputFile="$(OutDir)/ExplorerPlugin.dll"
 				LinkIncremental="1"
 				SuppressStartupBanner="TRUE"
 				IgnoreDefaultLibraryNames="uafxcwd.lib"
@@ -74,7 +76,8 @@
 			<Tool
 				Name="VCResourceCompilerTool"
 				PreprocessorDefinitions="_DEBUG"
-				Culture="1033"/>
+				Culture="1033"
+				AdditionalIncludeDirectories="../../mDNSWindows"/>
 			<Tool
 				Name="VCWebServiceProxyGeneratorTool"/>
 			<Tool
@@ -95,21 +98,21 @@
 				InlineFunctionExpansion="2"
 				FavorSizeOrSpeed="2"
 				OmitFramePointers="TRUE"
-				AdditionalIncludeDirectories="..\..\"
-				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;DNS_SD_DIRECT_ENABLED=0"
+				AdditionalIncludeDirectories="..\..\mDNSShared;..\..\mDNSWindows"
+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;WINVER=0x0400"
 				StringPooling="TRUE"
 				RuntimeLibrary="0"
 				BufferSecurityCheck="FALSE"
 				EnableFunctionLevelLinking="FALSE"
 				ForceConformanceInForLoopScope="TRUE"
-				UsePrecompiledHeader="2"
-				PrecompiledHeaderFile="$(OutDir)/$(ProjectName).pch"
+				UsePrecompiledHeader="0"
+				PrecompiledHeaderFile=""
 				AssemblerListingLocation=".\Release/"
 				ObjectFile=".\Release/"
 				ProgramDataBaseFileName=".\Release/"
 				BrowseInformation="1"
 				WarningLevel="4"
-				WarnAsError="TRUE"
+				WarnAsError="FALSE"
 				SuppressStartupBanner="TRUE"
 				Detect64BitPortabilityProblems="TRUE"
 				CompileAs="0"/>
@@ -122,7 +125,7 @@
 			<Tool
 				Name="VCLinkerTool"
 				AdditionalOptions="/MACHINE:I386 /IGNORE:4089 "
-				AdditionalDependencies="uafxcw.lib ws2_32.lib"
+				AdditionalDependencies="../../mDNSWindows/DLL/Release/dnssd.lib ws2_32.lib uafxcw.lib"
 				OutputFile="$(OutDir)/$(ProjectName).dll"
 				LinkIncremental="1"
 				SuppressStartupBanner="TRUE"
@@ -130,8 +133,8 @@
 				ModuleDefinitionFile="./$(ProjectName).def"
 				ProgramDatabaseFile="$(OutDir)/$(ProjectName).pdb"
 				SubSystem="2"
-				OptimizeReferences="2"
-				EnableCOMDATFolding="2"
+				OptimizeReferences="0"
+				EnableCOMDATFolding="0"
 				ImportLibrary="$(OutDir)/$(ProjectName).lib"/>
 			<Tool
 				Name="VCMIDLTool"
@@ -149,7 +152,8 @@
 			<Tool
 				Name="VCResourceCompilerTool"
 				PreprocessorDefinitions="NDEBUG"
-				Culture="1033"/>
+				Culture="1033"
+				AdditionalIncludeDirectories="../../mDNSWindows"/>
 			<Tool
 				Name="VCWebServiceProxyGeneratorTool"/>
 			<Tool
@@ -161,82 +165,115 @@
 			Name="Support"
 			Filter="">
 			<File
-				RelativePath="..\..\CommonServices.h">
+				RelativePath="..\..\mDNSWindows\CommonServices.h">
+			</File>
+			<File
+				RelativePath="..\..\mDNSWindows\DebugServices.c">
+			</File>
+			<File
+				RelativePath="..\..\mDNSWindows\DebugServices.h">
+			</File>
+			<File
+				RelativePath="..\..\mDNSWindows\WinServices.cpp">
+			</File>
+			<File
+				RelativePath="..\..\mDNSWindows\WinServices.h">
+			</File>
+		</Filter>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm">
+			<File
+				RelativePath="About.cpp">
+			</File>
+			<File
+				RelativePath="ClassFactory.cpp">
+			</File>
+			<File
+				RelativePath="ExplorerBar.cpp">
+			</File>
+			<File
+				RelativePath="ExplorerBarWindow.cpp">
+			</File>
+			<File
+				RelativePath="ExplorerPlugin.cpp">
+			</File>
+			<File
+				RelativePath="ExplorerPlugin.def">
+			</File>
+			<File
+				RelativePath="LoginDialog.cpp">
+			</File>
+			<File
+				RelativePath="StdAfx.cpp">
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc">
+			<File
+				RelativePath=".\About.h">
+			</File>
+			<File
+				RelativePath="ClassFactory.h">
+			</File>
+			<File
+				RelativePath="ExplorerBar.h">
+			</File>
+			<File
+				RelativePath="ExplorerBarWindow.h">
+			</File>
+			<File
+				RelativePath="ExplorerPlugin.h">
+			</File>
+			<File
+				RelativePath="LoginDialog.h">
+			</File>
+			<File
+				RelativePath="Resource.h">
+			</File>
+			<File
+				RelativePath="StdAfx.h">
+			</File>
+		</Filter>
+		<Filter
+			Name="Resource Files"
+			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;jpg;jpeg;jpe;manifest">
+			<File
+				RelativePath="ExplorerPlugin.rc">
+			</File>
+			<File
+				RelativePath="Web.ico">
 			</File>
 			<File
-				RelativePath="..\..\DNSSD.c">
+				RelativePath=".\about.bmp">
 			</File>
 			<File
-				RelativePath="..\..\DNSSD.h">
+				RelativePath=".\res\about.bmp">
 			</File>
 			<File
-				RelativePath="..\..\DebugServices.c">
+				RelativePath=".\res\cold.ico">
 			</File>
 			<File
-				RelativePath="..\..\DebugServices.h">
+				RelativePath=".\cold.ico">
 			</File>
 			<File
-				RelativePath="..\..\RMxClient.c">
+				RelativePath=".\hot.ico">
 			</File>
 			<File
-				RelativePath="..\..\RMxClient.h">
+				RelativePath=".\res\hot.ico">
 			</File>
 			<File
-				RelativePath="..\..\RMxCommon.c">
+				RelativePath=".\logo.bmp">
 			</File>
 			<File
-				RelativePath="..\..\RMxCommon.h">
+				RelativePath=".\res\logo.bmp">
 			</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>
+		<Global
+			Name="RESOURCE_FILE"
+			Value="ExplorerPlugin.rc"/>
 	</Globals>
 </VisualStudioProject>
diff --git a/mDNSWindows/Applications/ExplorerPlugin/LoginDialog.cpp b/Clients/ExplorerPlugin/LoginDialog.cpp
similarity index 93%
rename from mDNSWindows/Applications/ExplorerPlugin/LoginDialog.cpp
rename to Clients/ExplorerPlugin/LoginDialog.cpp
index 1947947..ccee81c 100644
--- a/mDNSWindows/Applications/ExplorerPlugin/LoginDialog.cpp
+++ b/Clients/ExplorerPlugin/LoginDialog.cpp
@@ -3,8 +3,6 @@
  *
  * @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
@@ -25,8 +23,14 @@
     Change History (most recent first):
     
 $Log: LoginDialog.cpp,v $
+Revision 1.2  2004/07/13 21:24:21  rpantos
+Fix for <rdar://problem/3701120>.
+
+Revision 1.1  2004/06/18 04:34:59  rpantos
+Move to Clients from mDNSWindows
+
 Revision 1.1  2004/01/30 03:01:56  bradley
-Explorer Plugin to browse for Rendezvous-enabled Web and FTP servers from within Internet Explorer.
+Explorer Plugin to browse for DNS-SD advertised Web and FTP servers from within Internet Explorer.
 
 */
 
diff --git a/mDNSWindows/Applications/ExplorerPlugin/LoginDialog.h b/Clients/ExplorerPlugin/LoginDialog.h
similarity index 88%
rename from mDNSWindows/Applications/ExplorerPlugin/LoginDialog.h
rename to Clients/ExplorerPlugin/LoginDialog.h
index 11d9d1c..a89c3a6 100644
--- a/mDNSWindows/Applications/ExplorerPlugin/LoginDialog.h
+++ b/Clients/ExplorerPlugin/LoginDialog.h
@@ -3,8 +3,6 @@
  *
  * @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
@@ -25,8 +23,14 @@
     Change History (most recent first):
     
 $Log: LoginDialog.h,v $
+Revision 1.2  2004/07/13 21:24:21  rpantos
+Fix for <rdar://problem/3701120>.
+
+Revision 1.1  2004/06/18 04:34:59  rpantos
+Move to Clients from mDNSWindows
+
 Revision 1.1  2004/01/30 03:01:56  bradley
-Explorer Plugin to browse for Rendezvous-enabled Web and FTP servers from within Internet Explorer.
+Explorer Plugin to browse for DNS-SD advertised Web and FTP servers from within Internet Explorer.
 
 */
 
diff --git a/mDNSWindows/Applications/ExplorerPlugin/ReadMe.txt b/Clients/ExplorerPlugin/ReadMe.txt
similarity index 82%
rename from mDNSWindows/Applications/ExplorerPlugin/ReadMe.txt
rename to Clients/ExplorerPlugin/ReadMe.txt
index ed73c22..2fbe666 100644
--- a/mDNSWindows/Applications/ExplorerPlugin/ReadMe.txt
+++ b/Clients/ExplorerPlugin/ReadMe.txt
@@ -1,4 +1,4 @@
-The Rendezvous Explorer Plugin is a vertical Explorer bar. It lets you browse for Rendezvous-enabled services directly within Internet Explorer. 
+The DNSServices Explorer Plugin is a vertical Explorer bar. It lets you browse for DNS-SD advertised 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):
 
diff --git a/mDNSWindows/Applications/ExplorerPlugin/Resource.h b/Clients/ExplorerPlugin/Resource.h
similarity index 57%
rename from mDNSWindows/Applications/ExplorerPlugin/Resource.h
rename to Clients/ExplorerPlugin/Resource.h
index 744ae44..2e56708 100644
--- a/mDNSWindows/Applications/ExplorerPlugin/Resource.h
+++ b/Clients/ExplorerPlugin/Resource.h
@@ -6,16 +6,25 @@
 #define IDS_WEB_SITES                   107
 #define IDS_FTP_SITES                   108
 #define IDS_PRINTERS                    109
-#define IDS_RENDEZVOUS_NOT_AVAILABLE    110
+#define IDS_MDNSRESPONDER_NOT_AVAILABLE 110
+#define IDB_LOGO                        115
+#define IDI_BUTTON_2K                   115
+#define IDD_ABOUT                       118
+#define IDI_BUTTON_XP                   118
+#define IDB_ABOUT                       119
+#define IDR_CONTEXT_MENU                120
 #define IDD_LOGIN                       145
+#define IDC_COMPONENT                   1001
+#define IDC_LEGAL                       1002
 #define IDC_LOGIN_USERNAME_TEXT         1182
 #define IDC_LOGIN_PASSWORD_TEXT         1183
+#define ID_Menu                         40001
 
 // Next default values for new objects
 // 
 #ifdef APSTUDIO_INVOKED
 #ifndef APSTUDIO_READONLY_SYMBOLS
-#define _APS_NEXT_RESOURCE_VALUE        115
+#define _APS_NEXT_RESOURCE_VALUE        119
 #define _APS_NEXT_COMMAND_VALUE         40001
 #define _APS_NEXT_CONTROL_VALUE         1001
 #define _APS_NEXT_SYMED_VALUE           101
diff --git a/mDNSWindows/Applications/ExplorerPlugin/StdAfx.cpp b/Clients/ExplorerPlugin/StdAfx.cpp
similarity index 81%
rename from mDNSWindows/Applications/ExplorerPlugin/StdAfx.cpp
rename to Clients/ExplorerPlugin/StdAfx.cpp
index 673073f..b97d864 100644
--- a/mDNSWindows/Applications/ExplorerPlugin/StdAfx.cpp
+++ b/Clients/ExplorerPlugin/StdAfx.cpp
@@ -3,8 +3,6 @@
  *
  * @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
@@ -25,8 +23,14 @@
     Change History (most recent first):
     
 $Log: StdAfx.cpp,v $
+Revision 1.2  2004/07/13 21:24:21  rpantos
+Fix for <rdar://problem/3701120>.
+
+Revision 1.1  2004/06/18 04:34:59  rpantos
+Move to Clients from mDNSWindows
+
 Revision 1.1  2004/01/30 03:01:56  bradley
-Explorer Plugin to browse for Rendezvous-enabled Web and FTP servers from within Internet Explorer.
+Explorer Plugin to browse for DNS-SD advertised Web and FTP servers from within Internet Explorer.
 
 */
 
diff --git a/mDNSWindows/Applications/ExplorerPlugin/StdAfx.h b/Clients/ExplorerPlugin/StdAfx.h
similarity index 86%
rename from mDNSWindows/Applications/ExplorerPlugin/StdAfx.h
rename to Clients/ExplorerPlugin/StdAfx.h
index 45020c1..ca625a1 100644
--- a/mDNSWindows/Applications/ExplorerPlugin/StdAfx.h
+++ b/Clients/ExplorerPlugin/StdAfx.h
@@ -3,8 +3,6 @@
  *
  * @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
@@ -25,8 +23,14 @@
     Change History (most recent first):
     
 $Log: StdAfx.h,v $
+Revision 1.2  2004/07/13 21:24:21  rpantos
+Fix for <rdar://problem/3701120>.
+
+Revision 1.1  2004/06/18 04:34:59  rpantos
+Move to Clients from mDNSWindows
+
 Revision 1.1  2004/01/30 03:01:56  bradley
-Explorer Plugin to browse for Rendezvous-enabled Web and FTP servers from within Internet Explorer.
+Explorer Plugin to browse for DNS-SD advertised Web and FTP servers from within Internet Explorer.
 
 */
 
diff --git a/Clients/ExplorerPlugin/res/about.bmp b/Clients/ExplorerPlugin/res/about.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..ab5e430bfc16000acc8546eb60f01f03b3fc76d4
GIT binary patch
literal 137944
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

literal 0
HcmV?d00001

diff --git a/Clients/ExplorerPlugin/res/button-2k.ico b/Clients/ExplorerPlugin/res/button-2k.ico
new file mode 100755
index 0000000000000000000000000000000000000000..3699b44180f893e870c4be2e61e865de834bce06
GIT binary patch
literal 10342
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

literal 0
HcmV?d00001

diff --git a/Clients/ExplorerPlugin/res/button-xp.ico b/Clients/ExplorerPlugin/res/button-xp.ico
new file mode 100755
index 0000000000000000000000000000000000000000..69d41dd943641702dc5e1659212d4e8d78b0db70
GIT binary patch
literal 7574
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

literal 0
HcmV?d00001

diff --git a/Clients/ExplorerPlugin/res/cold.ico b/Clients/ExplorerPlugin/res/cold.ico
new file mode 100644
index 0000000000000000000000000000000000000000..3699b44180f893e870c4be2e61e865de834bce06
GIT binary patch
literal 10342
zcmeHN33OCtmc9sBL2aQo1w}=H0TltYwNYE5f<U*ejf%3#qJWSDNF^kxS6k}U`f5w<
zYbyJ`Ktf2u4hf(jPTS7(>G8B@dS-OaOzWBB^g(-Oj^ohOeD_setgs1Ax97}EU-;|&
z`~Saxx%c~S9?>Yup@|bG5X;A-h#YuMn2<@&M0)!*gmSr<-ny13Hk!*b=`CZ4)?W8z
z`4Sb;$?;j`sC(nhUzR(^5tZGNRX&F3+*G2O=#Gb&i!h3i37LYi72)BAhD1!1|C1<k
z3<3W*3qON{gUCtC|0$j37y|xr7XMsMB#o#PYal~$RqBU=q|PK%$++MYhT;OEQYOwV
zRZ5)8hZ?K6U3Pq^tt3boK;*_6L7*I@QB%@z-5iyKT7sIeluqQSb2u&%eo}K)PSjH)
zrAh|mIJZDV#k1nkRH!dW8kGjUYS2)l?G+@IMk7cf<!F=05uEZHXf#f)Jv2F<2@9{0
z9FEDWM(4<ckSm9?x98H?T*OV8aF*_%GxJn*V!oA59X>`<^@k+AkMR2s$@<ZUBwEch
zm@|q#m^_-!%pWiJ%lkY5VG4q>&m!U%7m+uYH#YOYFQQkw&sbF!S3I+c+IVIIHENYy
zfFI?F1;L_WXRuTn2|+`WI!DYQjT-AFI!PPAGe=FXfRGeX3w<OtPOK!>StF{1%t$;M
zAGNc&L}%_mz<v1CPxSkDGvNbltkp_1sfXyc`-yHZA{v7r;=CV2KDQltA9A=$dII-w
zSom%X-H%YXf$Y{_k`2M>uBWc9UDVUlL$$Tl6pi|+p*~KLu!rLD2=(>#(So&a&=X~8
zdP+#seJlTo0>Ln~w??S4GC^U~+rPJ#-a56DP8@HglW%m=z|j^;COqgXNHK&L)%`T5
zJWW5aq$#)HU5Z2^bZ~zq_4ig&U0p2&gB}DI@&gnKRZu8srjAw*^>l}6;7A=+Cfs!3
zzya#$Xs7n}IMq}KskN<>R#|%JMf(wor5e#TNb#6Nl}R_HQc3FU?4W}O50c9zQfre$
zt<5g#Z1<s_pDHRO>g!F?p#$|4@QKvBXAcGZJid$kJ{tn&9Z6trHB?pUL3s@Cn51yX
zg7@`Nva%Ux>bK-|e@tb%M)La|)U_*!J|wJR4Mj1RwzgJU`uaYar^dQz({#`3f2D?o
zda9{%(7wJn1p*Q^H8oNq5v5H+8_hOiee7v^Z2PY<KO6P$iBdRdp<n>((6gJWYiene
zt&>(bk5D*KPkZ<7MVW;<+Pvt?jlGCt4ZXB~|9<Ldk5P3>!aRJKvk&#G2wvK?YZvBd
zrTY3>YQ$Wk(E!C_F51}<#@Yl?$4+&ae=-?EJ&_t48*m1~s1ri)VQ;+X&rRLk-5AS_
z`Xct%PSLQ1dVBX!OOprdZ>9eJK0KXR7Z=voPKkIWC1SO-Z{L258N$9s$cH_sOf^xS
z`hD^S|3IrZzeBrwdhuTU=)Vi&d+=^S>g|b=T3=81=BH^s*745uX>wLz{`EmRbf|@n
z9BQC_{Ygs3t+WUG=n2-+T>UwE*o*ZnJ4019jnv%e!#S#_KCEebs~6|XM>c;I<w?y{
z5visi_N}$qgW$%#n{oC7bO7rZ31JPxcJg{`)ZEl0>!acO^#3mM_Fw+|onKt=*2ho0
z@#e`>Z=F7`VE=)GhYlY(Ixu)_WWlbk?%h3mdi(nK?i*3i*woz8+ScCDxw9fWKUl@*
z9#U7|kewfkCz6?TWhy(LBGIAb^o=9(L*b#Mt2jIVQJ4D$kGI0N)E~G$I9y;bmYYN~
zk~dhaHoHS&HBVH$qofpAB%`tgQfYO1**NFr7jW@b{@FH%Xv6kGHI(zZ^{>9hSt~Z+
zN1n{4*Eeq=dg<lomUBL>AX>SKBdcFovzF+m&p!7vPC=F~l^@T)@ZvI}C!bod@M$@{
zXtDgDB|rYjGemRd-v7XZKX`~9{^7hw9!0@pKYDzA?h}aII{CKS@0fDuT~nvg^uL%f
z^X_}@ops-AZh6DEZX7@1+u!*vqTl=eO*c=RbPKQ;%cyHcj~NS`22tgVyY6~9c8Q;F
z*4}6Am}0l&DP`HQQey+<n}0`Zw)H_T2dSl{S=NIM^&#5RQ$y8N(ACgoG1#=%H0|^t
z^y@<P+p=Ej-W8|T))v|3g+iW;ZVOszFLd+4168u^V*BLtd&v>3rp{emvaSw?ow9EC
zx=j?1I4K0(TUF(O&ale%tG#^}l^Nb8by*+zd=BWZ2y~f4)}?G`o0}WS9cZ8jq08pL
zHtgHC4|>`v>rl22v3Q&|T05!O(IDHffZrnPch>i8qgcnWeT&81)YcM!o{hpTb|4*w
z-LOLs_sTXX20hDqI|SPr3Hzb@cjCPz=v{|wNBz*tfq)C|?Zdk!$ZFX|7HcDHYZbM%
z`mvsVvUwUPSC4t-rO929lx_aL{uDJecxd<TZffuBqNS$ew7Pr`#&*;Ge%Q=fr>x`q
z`g$oEV!LCZYV`S)So#v@?a$eNUV*Dvfh|MYIMd|S*EVc~)*WuYauw^^b?cRk7ni+6
z^zw3O;*3m_74P#eDCuXP<Jee5FGCS8TFlz_r=0!BqfohcLhC;H6cLm$(L+G*_Yv!4
zg5E{pEMnaYT}@MOp2n@lPR9?_GL4^f%dL|Msv2o%YohBF{VXeI<jQK9=vvmvNRAZ7
z{O8d2^YIAa2cMrJ`p=It;mm080vKNJuZesKBL6%h3&J3}_yGAA@`Z_V=Yts=Fmj;(
zRVko0fHq(@KsH8fS1-VYfQ3MX0ENJWfP_GV3<$4A078L50YQO40YHI20Y8C00X`Xf
zUa<i90`~&;0`&s)0`mg$0`UUy0`IaZxH19I2F?b|2FeD=2F3=&2Eqow2EJx9aRma@
z4=@ib4=B$_K1%@Vf$162Ux9!rfGB_`Fip5Xz#Eu0T$zA;F!#8afKxKHx-tQoVJ>qq
z0e)c9dj$f<iOS$jpv+)SAWm3V&?YcO5GU{^&}n8)mlkj}P&F_$5H;{LrfG_BpAGdO
zY~X94YhY_2Ys}R~3Z@E!3r@(CP!{k)riCMgNg^@y0aFA~1W(N54A%k!1p#ILnI%j`
zvjnV^3Arp_vH<Gfr=X|IPGtd{0ow)HWv-hgpvcU86*+I4K!(AEL4}zK%K~~0b`1i~
z{CcD?+m;2Cn;CbOfP8~{gL*UbmIYKEOdkC(kH45;r<mT46p(#zeNcU7`m(@%0Pg{u
z2k;%R>tLh+q_H320)b-zeg(J{*sCB5RuA3`I5XhOfGY!@40dD?yE5R(fFlDqkKGuG
zz?}ha2Amo2Wx$oeo(x6cX@R2!eipb{;AMf61wIzISb$*J!9wg}frkYS7Wh}-UV(Q7
z&K3Ap;96nNN|xZH!QTUS54=5a_Q2NzR}Xu76oJPF4j=e?;O>F92hJY&dKlVXAn-H6
z%>*wKoJ^>|E~b%!69|73+)eN{v9sw<Am1!snV5M4*xx^i08|50<AyV$zN`S61DOMu
z1D6Aq1C_Jm<<bJE52O#E51fzv2FeG>XN-Rd0c8MVV8S2^SOZ7{bB0R@=n*rHECKmo
z?r{kLRbi%*B_Mah>Lx3jqu@WFKVUx~KhOxEKG3`%KHxn}d$I)A34{vD5sH%8lp-*t
zxNP85pj6DLWC1k;GaEKAP-nv`X85>+u7RyFSp(GaIl%Uq>?y(yG-CHEvp!is{lNT~
z_z}}aFij?oS%TMOH>e_@lVFofCIRF8F5G7jQt(lxqr`+1d~|qL$N?<{D`iqD3z#p6
zFL*C#FPek&g7f0mf$_3U3R*#TF$Z?kDgsgsP7O*8M$Lp;7FZFGYH(^$YG%||FMnLT
zIz^tq`f*o3kN+zza5rxfG=;~@O7q_ngyQ<DRBGP;^xa@!RC;Sg!TQpQxXl$<Bbv1K
za%0}-<%TU^l$CCNUy|$_j~qGjwY8g73a^;<%F*=9yn*!HtNQ;f98ErHF&Dk(uMpCb
zy)ccj&f0Aj*^~Bl-X*^{P%`Cb1L@hT2GSFk45UR{Xtm9%8T9$eKdta;(=MqvEtGBk
z2j~khr>m1ghYnpE3?&yVTh;b=dE1VjduCbvU$?b&OaWB81=nP{#Zq2uF{?ju*b38b
zxAT>&>z&vaHO-(eO;&jQ%f0T<D_vdPL&oIGp4={Jo!wUW2ctn4fyBP7ap@SpbGb49
zGp(@YZ+Gt8dF#b$9zJ|{tX{wU=Vr4(d$ID%<?;IHwA)T-%JSYhdi3Zum#T|((!nOJ
zyj1z+@-1eguB<fg6xZSL09vmDdKt&_R@zlmcvp0Fbxl&zSMua@-_X!73vFL6EzLX8
z+1WWcnM}@ixuh+UWGgb6w2d~KC}8degTAcQ<8iHRX=$1MRd=DkzyC&u-Lh5CY};?O
zm`a+Pn`UZ-!tQuHmaEK*$HsWKC6kF<jJ4fhDDJnKi_Tcgh1e_go>(lhP^p{!<Z~yK
zZ9QZv&pT_zx(o~quxAuTqT(ftRhC^>iSORM`zBtiNF==2W-a|kgTCNBr)1p>R&uja
zho8KEdVOht@1&q9IL>oa%3(Oah4D-<jwAfUZEbCL)z{a}QR<~qm5+oY(M79@{dLb2
z#@}%Jqt7a3Slb`zwR!*Sl8Vwe^CLa@s1%Jx7NI?RwPgV$9q;wJ*I>*WlstZ}+3Jtn
zwPqkaW5YoDffcR4QOYp)N{e~hf4QB-+<&E#uRQsEVi<$hg5TBYw7(AA@SswzJeRDD
z_1v>;Abmgd$(@V(&M5hMec`Vhc6FNj*OcX-=6zPmlqcpq0dVBo4u@r{&1NpS*qsQ5
zDi>_n(ETr4^LsworuG|^w&mqIvn1{KqQWDb6*OCWfqO2{SA6zGlip@Dlyvf4P}(X_
zfbH+<bvvp}<z|Q5<z0_+^t4jeP+vdGW-I%9i&@xTTiY;u>9*jWC0pZf`a<y~JZI?n
z&3awo38SItcp%_=f$xUWmY?YRdxEAYZq#pr&ffAL7W3B6B*~heT?e{qy$kF5%=$?8
z)V0{7R|nD$FK_rOr_;H?<KBU_6F!T@Vheds&E|4LdAZ=nKD=hPn+ssmPMVBc(l+b%
zG}{J)UVRE<em}c^>|qYyo5z+`ot(QOvq#excYkEI*fcoXzu|kJ)aNq`TNd=Vg@2Dl
z&FN6kn2v<Sbii*oYc%XQ(%jrUL#ccI)9sEe&ChFkFE6j@Z$xu=HP^*izw`WhoQ_7r
zOQ0j%R;&JaxlyRcnO$-IJ-JxBKW1Jw-^qN7k@+6uEWXK*zsHzA^i9TsT>6~G(+6`^
zbZq`;vQEbL7zuofVaB%@#}G~&BXKmo$G{(71}F0O7%JI^KNFLkfG`DNl>CeD48|bw
z4GHYnxVpN!+jQEZ(}JLW%jc_De5FGtlBs)^6-M4%Q{?M18Vz2_UY0f*3xA9Ajz7SC
zwV2GlRSP$DrypD0ofgefzRjxrrQ{I4Fd5ZnYHF&dUakk|>oJn#T2Wf!Z5Fg13*O^8
zoL?2sUle!z&ThB9e!2G0(WCUbq5+dhC!JqU6pc2kRs2fa1byK!ne=Avi|4~n?kgIN
zK9oo#W}n}$l1AOpuuu0nCC3_5xz1KwTYHD!?_1)qTMHzIeG~c(+H96>(Ajsx_KvXq
z(Dk!)y5hZ}SgwU0nS{BDaC^vl9Pgh~Q&Teq_vHC<qo!9BOFo9)cv%@2^(X4Ig}=~g
z)o=5BIX@H%&4>MbK&g{TrDkv$ucy=HTD76X-Bze`*|@yisP);bCD>!lu#Mp{(FZ&3
z@prV;jA$hM2*+70cK@=+H)4O+bu&LBqp<|`QAlIm2RW?>@YA)tX4ta=?oY{2BvSWo
zDM<b*Z<}BC+TdM{l0$b!6io(`-ScWPm73Yw+B)9la<0If+T!u}@O$vN)@gS%8TBOt
zyhhw7bj^2wAM!UAdMY0;=uSVoDRJ6p)K&x2eiDmC9}4*WPn*pq1NOdHrz<+{u$QKJ
zz7B_VlQJjXkD@Y<aZN$%r|Y)(J2B@x%>7|5=lyrPUCTvLd)nbJd@PE>0Mf&HQ|aUD
vJelvEh1F92K5+&J;?s|io`JtX;M5J8iEM))tZ*#(fON&V2pEX-x$S=gNiN?N

literal 0
HcmV?d00001

diff --git a/Clients/ExplorerPlugin/res/hot.ico b/Clients/ExplorerPlugin/res/hot.ico
new file mode 100644
index 0000000000000000000000000000000000000000..95b03d051a292cff9428174135f2c726da147404
GIT binary patch
literal 10342
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
F{|^P((%b+5

literal 0
HcmV?d00001

diff --git a/Clients/ExplorerPlugin/res/logo.bmp b/Clients/ExplorerPlugin/res/logo.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..f866bd796319037daaf29b670dec6c8cfb781852
GIT binary patch
literal 822
zcmY*WS#J_i6vp@meDo*y=2Lms_+pGd!9QS(Px{h_##oo6jnQhTBRi!a(6E#pX4uNU
zr5&KqXc?%rbl3-&4F=Gg4okSnx%Zs!eD|F1p8N2r@V4M)3Bi63*qxc(65PGP1+zRK
z@cX~jMf3>#`U-YCEGA<j9wWM))%;3yf)UR(wRID2cfvC0vv~K5)nX<HVudshrqk)B
zk-Wb_3ExtX^&D{+3_n#;XeS&BaU3^iEziMVpocHk#l2VGNfcwQ{$55SVU-*@&}k@&
zTJq*ztJONtDi9>v?hbiuGMS`PDea!T)9KDx%adUkwNiq3oq)DLTkW>fcE~d90$Df=
zL%SR{1opO?O&rJTb-dANR4bKaJl5~`$K&yWIp(+uh8=~10Uu&JG-FsfkD|#$Jm7=v
zR+HIifIY54K2Ht$;L32w!XCFm3gu7~JlXAZblS6-1BJO<E}Kc~G)n!xv~-#uvNWh8
z+SvkEc-iR5@o_fGx5molQn3j9i)vLL`1L|}EeqmWwL&ibmd#{%4oT7JRFY-cX0sUy
zhiIAxIQW`pyX4wOdTpaG7mL&i2=TfXFRImQXQdL*49fCFIBvA1@4kk}m!clfX4LO_
z+%EL@B})%Ta!{#Mj0SBo5#!0A4iIKFn@yHrG?EO5f_~Wj#$10S>TEk2k)VHHDGB(z
z*>w7}P^i}%U@~f@{D<h1Qt~w!kMxLc;q1@jcfAK6s3-3`R;wNHIDmeVBz>?)uT^T*
wGL1^2(<uCiho%_5sm@PrN(l|pFPG237<q8SjZ39s<R}EbCZEd<ha-Uh2gJLJ5C8xG

literal 0
HcmV?d00001

diff --git a/Clients/Java/BrowserApp.java b/Clients/Java/BrowserApp.java
index d3805ae..0b55fa5 100644
--- a/Clients/Java/BrowserApp.java
+++ b/Clients/Java/BrowserApp.java
@@ -1,40 +1,42 @@
 /*
  * 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.
+ * Disclaimer: IMPORTANT:  This Apple software is supplied to you by Apple Computer, Inc.
+ * ("Apple") in consideration of your agreement to the following terms, and your
+ * use, installation, modification or redistribution of this Apple software
+ * constitutes acceptance of these terms.  If you do not agree with these terms,
+ * please do not use, install, modify or redistribute this Apple software.
+ *
+ * In consideration of your agreement to abide by the following terms, and subject
+ * to these terms, Apple grants you a personal, non-exclusive license, under Apple's
+ * copyrights in this original Apple software (the "Apple Software"), to use,
+ * reproduce, modify and redistribute the Apple Software, with or without
+ * modifications, in source and/or binary forms; provided that if you redistribute
+ * the Apple Software in its entirety and without modifications, you must retain
+ * this notice and the following text and disclaimers in all such redistributions of
+ * the Apple Software.  Neither the name, trademarks, service marks or logos of
+ * Apple Computer, Inc. may be used to endorse or promote products derived from the
+ * Apple Software without specific prior written permission from Apple.  Except as
+ * expressly stated in this notice, no other rights or licenses, express or implied,
+ * are granted by Apple herein, including but not limited to any patent rights that
+ * may be infringed by your derivative works or by other works in which the Apple
+ * Software may be incorporated.
+ *
+ * The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO
+ * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+ * WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
+ * COMBINATION WITH YOUR PRODUCTS.
+ *
+ * IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
+ * OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
+ * (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+	BrowserApp demonstrates how to use DNS-SD to browse for and resolve services.
 
 	To do:
 	- display resolved TXTRecord
@@ -75,7 +77,7 @@ class	BrowserApp implements ListSelectionListener, ResolveListener
 		try {
 			domainBrowser = DNSSD.enumerateDomains( DNSSD.BROWSE_DOMAINS, 0, domainList);
 
-			servicesBrowser = DNSSD.browse( 0, 0, "_services._mdns._udp.", "", servicesList);
+			servicesBrowser = DNSSD.browse( 0, 0, "_services._dns-sd._udp.", "", servicesList);
 			serviceBrowser = null;
 		}
 		catch ( Exception ex) { terminateWithException( ex); }
@@ -142,7 +144,7 @@ class	BrowserApp implements ListSelectionListener, ResolveListener
 					if ( serviceBrowser != null)
 						serviceBrowser.stop();
 					serviceList.removeAllElements();
-					servicesBrowser = DNSSD.browse( 0, 0, "_services._mdns._udp.", "", servicesList);
+					servicesBrowser = DNSSD.browse( 0, 0, "_services._dns-sd._udp.", "", servicesList);
 				}
 			}
 			else if ( e.getSource() == servicesPane && !e.getValueIsAdjusting())
diff --git a/Clients/Java/BrowserApp.manifest b/Clients/Java/BrowserApp.manifest
new file mode 100644
index 0000000..7c392a1
--- /dev/null
+++ b/Clients/Java/BrowserApp.manifest
@@ -0,0 +1,2 @@
+Manifest-Version: 1.0
+Main-Class: BrowserApp
diff --git a/Clients/Java/DNSSDUnitTest.java b/Clients/Java/DNSSDUnitTest.java
index e4523e1..786cab7 100644
--- a/Clients/Java/DNSSDUnitTest.java
+++ b/Clients/Java/DNSSDUnitTest.java
@@ -3,8 +3,6 @@
  *
  * @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
@@ -25,6 +23,9 @@
     Change History (most recent first):
 
 $Log: DNSSDUnitTest.java,v $
+Revision 1.4  2004/08/04 01:07:43  rpantos
+Update unit test for <rdar://problems/3731579&3731582>.
+
 Revision 1.3  2004/05/26 01:41:58  cheshire
 Pass proper flags to DNSSD.enumerateDomains
 
@@ -67,19 +68,34 @@ class	DNSSDUnitTest
 		String		a;
 		
 		txtRecord.set( "path", "~/names");
+		txtRecord.set( "rw", (String) null);
+		txtRecord.set( "empty", "");
 		txtRecord.set( "ttl", "4");
 
 		byte[]	rawBytes = txtRecord.getRawBytes();
 		System.out.println( ( new String( rawBytes, 0, rawBytes.length)) + " has count " + 
 								String.valueOf( txtRecord.size()));
 
+		System.out.println( txtRecord);
 		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));
+		txtRecord.set( "path", "~/numbers");
+		System.out.println( txtRecord);
+
+		txtRecord.remove( "ttl");
+		System.out.println( txtRecord);
+
+		txtRecord.remove( "path");
+		System.out.println( txtRecord);
+
+		txtRecord.remove( "at");
+		System.out.println( txtRecord);
+
+		txtRecord.set( "rw", "1");
+		System.out.println( txtRecord);
 	}
 
 	public void	run() throws DNSSDException
diff --git a/Clients/Java/SimpleChat.java b/Clients/Java/SimpleChat.java
index 07f58d2..745b9a0 100644
--- a/Clients/Java/SimpleChat.java
+++ b/Clients/Java/SimpleChat.java
@@ -1,42 +1,45 @@
 /*
  * 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.
+ * Disclaimer: IMPORTANT:  This Apple software is supplied to you by Apple Computer, Inc.
+ * ("Apple") in consideration of your agreement to the following terms, and your
+ * use, installation, modification or redistribution of this Apple software
+ * constitutes acceptance of these terms.  If you do not agree with these terms,
+ * please do not use, install, modify or redistribute this Apple software.
+ *
+ * In consideration of your agreement to abide by the following terms, and subject
+ * to these terms, Apple grants you a personal, non-exclusive license, under Apple's
+ * copyrights in this original Apple software (the "Apple Software"), to use,
+ * reproduce, modify and redistribute the Apple Software, with or without
+ * modifications, in source and/or binary forms; provided that if you redistribute
+ * the Apple Software in its entirety and without modifications, you must retain
+ * this notice and the following text and disclaimers in all such redistributions of
+ * the Apple Software.  Neither the name, trademarks, service marks or logos of
+ * Apple Computer, Inc. may be used to endorse or promote products derived from the
+ * Apple Software without specific prior written permission from Apple.  Except as
+ * expressly stated in this notice, no other rights or licenses, express or implied,
+ * are granted by Apple herein, including but not limited to any patent rights that
+ * may be infringed by your derivative works or by other works in which the Apple
+ * Software may be incorporated.
+ *
+ * The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO
+ * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+ * WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
+ * COMBINATION WITH YOUR PRODUCTS.
+ *
+ * IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
+ * OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
+ * (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 	SimpleChat is a simple peer-to-peer chat program that demonstrates 
-	DNSSD registration, browsing, resolving and record-querying.
+	DNS-SD registration, browsing, resolving and record-querying.
 
 	To do:
-	- remove TXTRecord tests
-	- remove diagnostic printf's
 	- implement better coloring algorithm
  */
 
@@ -94,11 +97,7 @@ class	SimpleChat implements	ResolveListener, RegisterListener, QueryListener,
 
 		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);
+		registration = DNSSD.register( 0, 0, ourName, kChatExampleRegType, "", "", inSocket.getLocalPort(), null, this);
 
 		new ListenerThread( this, inSocket, dataPacket).start();
 	}
@@ -155,7 +154,6 @@ class	SimpleChat implements	ResolveListener, RegisterListener, QueryListener,
 									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)
@@ -166,10 +164,6 @@ System.out.println( "ServiceRegisterCallback() invoked as " + serviceName);
 	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
diff --git a/Clients/Java/SimpleChat.manifest b/Clients/Java/SimpleChat.manifest
new file mode 100644
index 0000000..45c0202
--- /dev/null
+++ b/Clients/Java/SimpleChat.manifest
@@ -0,0 +1,2 @@
+Manifest-Version: 1.0
+Main-Class: SimpleChat
diff --git a/Clients/Java/SwingBrowseListener.java b/Clients/Java/SwingBrowseListener.java
index 4855dde..78bfe4f 100644
--- a/Clients/Java/SwingBrowseListener.java
+++ b/Clients/Java/SwingBrowseListener.java
@@ -1,36 +1,40 @@
 /*
  * 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.
-
+ * Disclaimer: IMPORTANT:  This Apple software is supplied to you by Apple Computer, Inc.
+ * ("Apple") in consideration of your agreement to the following terms, and your
+ * use, installation, modification or redistribution of this Apple software
+ * constitutes acceptance of these terms.  If you do not agree with these terms,
+ * please do not use, install, modify or redistribute this Apple software.
+ *
+ * In consideration of your agreement to abide by the following terms, and subject
+ * to these terms, Apple grants you a personal, non-exclusive license, under Apple's
+ * copyrights in this original Apple software (the "Apple Software"), to use,
+ * reproduce, modify and redistribute the Apple Software, with or without
+ * modifications, in source and/or binary forms; provided that if you redistribute
+ * the Apple Software in its entirety and without modifications, you must retain
+ * this notice and the following text and disclaimers in all such redistributions of
+ * the Apple Software.  Neither the name, trademarks, service marks or logos of
+ * Apple Computer, Inc. may be used to endorse or promote products derived from the
+ * Apple Software without specific prior written permission from Apple.  Except as
+ * expressly stated in this notice, no other rights or licenses, express or implied,
+ * are granted by Apple herein, including but not limited to any patent rights that
+ * may be infringed by your derivative works or by other works in which the Apple
+ * Software may be incorporated.
+ *
+ * The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO
+ * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+ * WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
+ * COMBINATION WITH YOUR PRODUCTS.
+ *
+ * IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
+ * OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
+ * (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
 
diff --git a/Clients/Java/SwingDomainListener.java b/Clients/Java/SwingDomainListener.java
index 2c5840f..c6c380b 100644
--- a/Clients/Java/SwingDomainListener.java
+++ b/Clients/Java/SwingDomainListener.java
@@ -1,36 +1,40 @@
 /*
  * 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.
-
+ * Disclaimer: IMPORTANT:  This Apple software is supplied to you by Apple Computer, Inc.
+ * ("Apple") in consideration of your agreement to the following terms, and your
+ * use, installation, modification or redistribution of this Apple software
+ * constitutes acceptance of these terms.  If you do not agree with these terms,
+ * please do not use, install, modify or redistribute this Apple software.
+ *
+ * In consideration of your agreement to abide by the following terms, and subject
+ * to these terms, Apple grants you a personal, non-exclusive license, under Apple's
+ * copyrights in this original Apple software (the "Apple Software"), to use,
+ * reproduce, modify and redistribute the Apple Software, with or without
+ * modifications, in source and/or binary forms; provided that if you redistribute
+ * the Apple Software in its entirety and without modifications, you must retain
+ * this notice and the following text and disclaimers in all such redistributions of
+ * the Apple Software.  Neither the name, trademarks, service marks or logos of
+ * Apple Computer, Inc. may be used to endorse or promote products derived from the
+ * Apple Software without specific prior written permission from Apple.  Except as
+ * expressly stated in this notice, no other rights or licenses, express or implied,
+ * are granted by Apple herein, including but not limited to any patent rights that
+ * may be infringed by your derivative works or by other works in which the Apple
+ * Software may be incorporated.
+ *
+ * The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO
+ * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+ * WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
+ * COMBINATION WITH YOUR PRODUCTS.
+ *
+ * IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
+ * OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
+ * (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
 
diff --git a/Clients/Java/SwingQueryListener.java b/Clients/Java/SwingQueryListener.java
index 4b58e67..5f2de1d 100644
--- a/Clients/Java/SwingQueryListener.java
+++ b/Clients/Java/SwingQueryListener.java
@@ -1,36 +1,40 @@
 /*
  * 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.
-
+ * Disclaimer: IMPORTANT:  This Apple software is supplied to you by Apple Computer, Inc.
+ * ("Apple") in consideration of your agreement to the following terms, and your
+ * use, installation, modification or redistribution of this Apple software
+ * constitutes acceptance of these terms.  If you do not agree with these terms,
+ * please do not use, install, modify or redistribute this Apple software.
+ *
+ * In consideration of your agreement to abide by the following terms, and subject
+ * to these terms, Apple grants you a personal, non-exclusive license, under Apple's
+ * copyrights in this original Apple software (the "Apple Software"), to use,
+ * reproduce, modify and redistribute the Apple Software, with or without
+ * modifications, in source and/or binary forms; provided that if you redistribute
+ * the Apple Software in its entirety and without modifications, you must retain
+ * this notice and the following text and disclaimers in all such redistributions of
+ * the Apple Software.  Neither the name, trademarks, service marks or logos of
+ * Apple Computer, Inc. may be used to endorse or promote products derived from the
+ * Apple Software without specific prior written permission from Apple.  Except as
+ * expressly stated in this notice, no other rights or licenses, express or implied,
+ * are granted by Apple herein, including but not limited to any patent rights that
+ * may be infringed by your derivative works or by other works in which the Apple
+ * Software may be incorporated.
+ *
+ * The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO
+ * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+ * WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
+ * COMBINATION WITH YOUR PRODUCTS.
+ *
+ * IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
+ * OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
+ * (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
 
diff --git a/Clients/Java/SwingResolveListener.java b/Clients/Java/SwingResolveListener.java
index 1422a6e..f2be4b0 100644
--- a/Clients/Java/SwingResolveListener.java
+++ b/Clients/Java/SwingResolveListener.java
@@ -1,36 +1,40 @@
 /*
  * 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
-
+ * Disclaimer: IMPORTANT:  This Apple software is supplied to you by Apple Computer, Inc.
+ * ("Apple") in consideration of your agreement to the following terms, and your
+ * use, installation, modification or redistribution of this Apple software
+ * constitutes acceptance of these terms.  If you do not agree with these terms,
+ * please do not use, install, modify or redistribute this Apple software.
+ *
+ * In consideration of your agreement to abide by the following terms, and subject
+ * to these terms, Apple grants you a personal, non-exclusive license, under Apple's
+ * copyrights in this original Apple software (the "Apple Software"), to use,
+ * reproduce, modify and redistribute the Apple Software, with or without
+ * modifications, in source and/or binary forms; provided that if you redistribute
+ * the Apple Software in its entirety and without modifications, you must retain
+ * this notice and the following text and disclaimers in all such redistributions of
+ * the Apple Software.  Neither the name, trademarks, service marks or logos of
+ * Apple Computer, Inc. may be used to endorse or promote products derived from the
+ * Apple Software without specific prior written permission from Apple.  Except as
+ * expressly stated in this notice, no other rights or licenses, express or implied,
+ * are granted by Apple herein, including but not limited to any patent rights that
+ * may be infringed by your derivative works or by other works in which the Apple
+ * Software may be incorporated.
+ *
+ * The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO
+ * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+ * WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
+ * COMBINATION WITH YOUR PRODUCTS.
+ *
+ * IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
+ * OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
+ * (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
 
diff --git a/Clients/Java/nmakefile b/Clients/Java/nmakefile
new file mode 100644
index 0000000..4c655d8
--- /dev/null
+++ b/Clients/Java/nmakefile
@@ -0,0 +1,106 @@
+# 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@
+#
+#
+# This Makefile builds .jar files for the DNS-SD Java sample apps.
+# You must have the Java support installed.
+#
+# 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\Common7\tools\vsvars32.bat"
+# 
+# The default location of the JDK is \javasdk. You can override this on the
+# command line (e.g. 'nmake JDK=\j2dk1.4.2_03').
+
+############################################################################
+
+JDK = \javasdk
+
+CP = copy
+RM = del /Q
+RMDIR = rmdir /S /Q
+JAVAC = $(JDK)\bin\javac
+JAVAH = $(JDK)\bin\javah
+JAR = $(JDK)\bin\jar
+
+# Set up diverging paths for debug vs. prod builds
+DEBUG=0
+!if $(DEBUG) == 1
+JFLAGS = -g
+OBJDIR = objects\debug
+BUILDDIR = build\debug
+!else
+JFLAGS = 
+OBJDIR = objects\prod
+BUILDDIR = build\prod
+!endif
+
+SCOBJ = $(OBJDIR)\SimpleChat
+BAOBJ = $(OBJDIR)\BrowserApp
+
+#############################################################################
+
+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 $(SCOBJ)		mkdir $(SCOBJ)
+	@if not exist $(BAOBJ)		mkdir $(BAOBJ)
+	@if not exist $(BUILDDIR)	mkdir $(BUILDDIR)
+
+# clean removes targets and objects
+clean:
+	@if exist $(OBJDIR)		$(RMDIR) $(OBJDIR)
+	@if exist $(BUILDDIR)	$(RMDIR) $(BUILDDIR)
+
+#############################################################################
+
+Java: setup $(BUILDDIR)\SimpleChat.jar $(BUILDDIR)\BrowserApp.jar
+	@echo "Build complete"
+
+SIMPLECHATOBJ =	$(SCOBJ)\SwingBrowseListener.class \
+				$(SCOBJ)\SwingQueryListener.class \
+				$(SCOBJ)\SimpleChat.class 
+SIMPLECHATMAN = SimpleChat.manifest
+
+$(BUILDDIR)\SimpleChat.jar: $(SIMPLECHATOBJ) $(SIMPLECHATMAN)
+	$(JAR) -cfm $@ $(SIMPLECHATMAN) -C $(SCOBJ) .
+
+BROWSERAPPOBJ =	$(BAOBJ)\SwingResolveListener.class \
+				$(BAOBJ)\BrowserApp.class 
+BROWSERAPPMAN = BrowserApp.manifest
+
+$(BUILDDIR)\BrowserApp.jar: $(BROWSERAPPOBJ) $(BROWSERAPPMAN)
+	$(JAR) -cfm $@ $(BROWSERAPPMAN) -C $(BAOBJ) .
+
+JAVASRC	= .
+.SUFFIXES : .java
+{$(JAVASRC)}.java{$(BAOBJ)}.class:	
+	$(JAVAC) -d $(BAOBJ) -classpath $(BAOBJ) $<
+{$(JAVASRC)}.java{$(SCOBJ)}.class:	
+	$(JAVAC) -d $(SCOBJ) -classpath $(SCOBJ) $<
+
diff --git a/Clients/Makefile b/Clients/Makefile
index 11f4a83..709bd2b 100755
--- a/Clients/Makefile
+++ b/Clients/Makefile
@@ -20,6 +20,12 @@
 # @APPLE_LICENSE_HEADER_END@
 #
 # $Log: Makefile,v $
+# Revision 1.6  2004/09/24 21:15:26  cheshire
+# <rdar://problem/3724985> Library "libmdns" misnamed; should be "libdns_sd"
+#
+# Revision 1.5  2004/09/02 17:32:45  cheshire
+# Look for headers in ../mDNSShared before we go to /usr/include
+#
 # Revision 1.4  2004/05/21 17:25:56  cheshire
 # Fixes to make sample client work on Linux
 #
@@ -43,9 +49,9 @@
 #############################################################################
 
 
-# If library /usr/lib/libmdns.* exists, then link it
-ifneq "$(wildcard /usr/lib/libmdns.*)" ""
-LIBS = -lmdns
+# If library /usr/lib/libdns_sd.* exists, then link it
+ifneq "$(wildcard /usr/lib/libdns_sd.*)" ""
+LIBS = -ldns_sd
 else
 LIBS =
 endif
@@ -59,4 +65,4 @@ build:
 	mkdir build
 
 build/dns-sd: build dns-sd.c
-	cc $(filter %.c %.o, $+) $(LIBS) -o $@
+	cc $(filter %.c %.o, $+) $(LIBS) -I../mDNSShared -o $@
diff --git a/Clients/PrinterSetupWizard/About.cpp b/Clients/PrinterSetupWizard/About.cpp
new file mode 100644
index 0000000..6fda710
--- /dev/null
+++ b/Clients/PrinterSetupWizard/About.cpp
@@ -0,0 +1,31 @@
+// About.cpp : implementation file
+//
+
+#include "stdafx.h"
+#include "PrinterSetupWizardApp.h"
+#include "About.h"
+
+
+// CAbout dialog
+
+IMPLEMENT_DYNAMIC(CAbout, CDialog)
+CAbout::CAbout(CWnd* pParent /*=NULL*/)
+	: CDialog(CAbout::IDD, pParent)
+{
+}
+
+CAbout::~CAbout()
+{
+}
+
+void CAbout::DoDataExchange(CDataExchange* pDX)
+{
+	CDialog::DoDataExchange(pDX);
+}
+
+
+BEGIN_MESSAGE_MAP(CAbout, CDialog)
+END_MESSAGE_MAP()
+
+
+// CAbout message handlers
diff --git a/Clients/PrinterSetupWizard/About.h b/Clients/PrinterSetupWizard/About.h
new file mode 100644
index 0000000..1d84b7f
--- /dev/null
+++ b/Clients/PrinterSetupWizard/About.h
@@ -0,0 +1,21 @@
+#pragma once
+
+
+// CAbout dialog
+
+class CAbout : public CDialog
+{
+	DECLARE_DYNAMIC(CAbout)
+
+public:
+	CAbout(CWnd* pParent = NULL);   // standard constructor
+	virtual ~CAbout();
+
+// Dialog Data
+	enum { IDD = IDD_DIALOG1 };
+
+protected:
+	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
+
+	DECLARE_MESSAGE_MAP()
+};
diff --git a/Clients/PrinterSetupWizard/FirstPage.cpp b/Clients/PrinterSetupWizard/FirstPage.cpp
new file mode 100644
index 0000000..c71faf5
--- /dev/null
+++ b/Clients/PrinterSetupWizard/FirstPage.cpp
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+    
+$Log: FirstPage.cpp,v $
+Revision 1.2  2004/07/13 20:15:04  shersche
+<rdar://problem/3726363> Load large font name from resource
+Bug #: 3726363
+
+Revision 1.1  2004/06/18 04:36:57  rpantos
+First checked in
+
+
+*/
+
+#include "stdafx.h"
+#include "PrinterSetupWizardApp.h"
+#include "FirstPage.h"
+
+
+// CFirstPage dialog
+
+IMPLEMENT_DYNAMIC(CFirstPage, CPropertyPage)
+CFirstPage::CFirstPage()
+	: CPropertyPage(CFirstPage::IDD)
+{
+	CString fontName;
+
+	m_psp.dwFlags &= ~(PSP_HASHELP);
+	m_psp.dwFlags |= PSP_DEFAULT|PSP_HIDEHEADER;
+
+	fontName.LoadString(IDS_LARGE_FONT);
+
+	// create the large font
+	m_largeFont.CreateFont(-16, 0, 0, 0, 
+		FW_BOLD, FALSE, FALSE, 0, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, 
+		CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, fontName);
+}
+
+CFirstPage::~CFirstPage()
+{
+}
+
+void CFirstPage::DoDataExchange(CDataExchange* pDX)
+{
+	CPropertyPage::DoDataExchange(pDX);
+	DDX_Control(pDX, IDC_GREETING, m_greeting);
+}
+
+
+BOOL
+CFirstPage::OnSetActive()
+{
+	CPropertySheet* psheet = (CPropertySheet*) GetParent();   
+   
+	psheet->SetWizardButtons(PSWIZB_NEXT);
+
+	m_greeting.SetFont(&m_largeFont);
+
+	CString greetingText;
+
+	greetingText.LoadString(IDS_GREETING);
+	m_greeting.SetWindowText(greetingText);
+
+	return CPropertyPage::OnSetActive();
+}
+
+
+BEGIN_MESSAGE_MAP(CFirstPage, CPropertyPage)
+END_MESSAGE_MAP()
+
+
+// CFirstPage message handlers
diff --git a/Clients/PrinterSetupWizard/FirstPage.h b/Clients/PrinterSetupWizard/FirstPage.h
new file mode 100644
index 0000000..5c23bdf
--- /dev/null
+++ b/Clients/PrinterSetupWizard/FirstPage.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+    
+$Log: FirstPage.h,v $
+Revision 1.1  2004/06/18 04:36:57  rpantos
+First checked in
+
+
+*/
+
+#pragma once
+#include "afxwin.h"
+
+
+// CFirstPage dialog
+
+class CFirstPage : public CPropertyPage
+{
+	DECLARE_DYNAMIC(CFirstPage)
+
+public:
+	CFirstPage();
+	virtual ~CFirstPage();
+
+// Dialog Data
+	enum { IDD = IDD_FIRST_PAGE };
+
+protected:
+	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
+	virtual BOOL OnSetActive();
+	
+
+	DECLARE_MESSAGE_MAP()
+
+private:
+
+	CFont	m_largeFont;
+	
+public:
+
+	CStatic m_greeting;
+};
diff --git a/Clients/PrinterSetupWizard/FourthPage.cpp b/Clients/PrinterSetupWizard/FourthPage.cpp
new file mode 100644
index 0000000..c4ccc52
--- /dev/null
+++ b/Clients/PrinterSetupWizard/FourthPage.cpp
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+    
+$Log: FourthPage.cpp,v $
+Revision 1.4  2004/07/13 20:15:04  shersche
+<rdar://problem/3726363> Load large font name from resource
+Bug #: 3726363
+
+Revision 1.3  2004/07/12 06:59:03  shersche
+<rdar://problem/3723695> Use resource strings for Yes/No
+Bug #: 3723695
+
+Revision 1.2  2004/06/26 23:27:12  shersche
+support for installing multiple printers of the same name
+
+Revision 1.1  2004/06/18 04:36:57  rpantos
+First checked in
+
+
+*/
+
+#include "stdafx.h"
+#include "PrinterSetupWizardApp.h"
+#include "PrinterSetupWizardSheet.h"
+#include "FourthPage.h"
+
+
+// CFourthPage dialog
+
+IMPLEMENT_DYNAMIC(CFourthPage, CPropertyPage)
+CFourthPage::CFourthPage()
+	: CPropertyPage(CFourthPage::IDD),
+		m_initialized(false)
+{
+	CString fontName;
+
+	m_psp.dwFlags &= ~(PSP_HASHELP);
+	m_psp.dwFlags |= PSP_DEFAULT|PSP_HIDEHEADER;
+
+	fontName.LoadString(IDS_LARGE_FONT);
+
+	// create the large font
+	m_largeFont.CreateFont(-16, 0, 0, 0, 
+		FW_BOLD, FALSE, FALSE, 0, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, 
+		CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, fontName);
+}
+
+CFourthPage::~CFourthPage()
+{
+}
+
+void CFourthPage::DoDataExchange(CDataExchange* pDX)
+{
+	CPropertyPage::DoDataExchange(pDX);
+	DDX_Control(pDX, IDC_GOODBYE, m_goodbye);
+	DDX_Control(pDX, IDC_PRINTER_NAME, m_printerNameCtrl);
+	DDX_Control(pDX, IDC_PRINTER_MANUFACTURER, m_printerManufacturerCtrl);
+	DDX_Control(pDX, IDC_PRINTER_MODEL, m_printerModelCtrl);
+	DDX_Control(pDX, IDC_PRINTER_PORT, m_printerPortCtrl);
+	DDX_Control(pDX, IDC_PRINTER_DEFAULT, m_printerDefault);
+}
+
+
+BEGIN_MESSAGE_MAP(CFourthPage, CPropertyPage)
+END_MESSAGE_MAP()
+
+
+// CFourthPage message handlers
+OSStatus 
+CFourthPage::OnInitPage()
+{
+	return kNoErr;
+}
+
+
+BOOL
+CFourthPage::OnSetActive()
+{
+	CPrinterSetupWizardSheet	*	psheet;
+	CString							goodbyeText;
+	Printer						*	printer;
+	CString							defaultText;
+
+	psheet = reinterpret_cast<CPrinterSetupWizardSheet*>(GetParent());
+	require_quiet( psheet, exit );
+   
+	printer = psheet->GetSelectedPrinter();
+	require_quiet( psheet, exit );
+	
+	psheet->SetWizardButtons(PSWIZB_BACK|PSWIZB_FINISH);
+
+	if (m_initialized == false)
+	{
+		m_initialized = true;
+		OnInitPage();
+	}
+
+	m_goodbye.SetFont(&m_largeFont);
+
+	goodbyeText.LoadString(IDS_GOODBYE);
+	m_goodbye.SetWindowText(goodbyeText);
+
+	m_printerNameCtrl.SetWindowText( printer->actualName );
+	m_printerManufacturerCtrl.SetWindowText ( printer->manufacturer );
+	m_printerModelCtrl.SetWindowText ( printer->model );
+	m_printerPortCtrl.SetWindowText ( printer->portName );
+
+	if (printer->deflt)
+	{
+		defaultText.LoadString(IDS_YES);
+	}
+	else
+	{
+		defaultText.LoadString(IDS_NO);
+	}
+
+	m_printerDefault.SetWindowText ( defaultText );
+
+exit:
+
+	return CPropertyPage::OnSetActive();
+}
diff --git a/Clients/PrinterSetupWizard/FourthPage.h b/Clients/PrinterSetupWizard/FourthPage.h
new file mode 100644
index 0000000..78bbf52
--- /dev/null
+++ b/Clients/PrinterSetupWizard/FourthPage.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+    
+$Log: FourthPage.h,v $
+Revision 1.1  2004/06/18 04:36:57  rpantos
+First checked in
+
+
+*/
+
+#pragma once
+#include "afxwin.h"
+
+
+// CFourthPage dialog
+
+class CFourthPage : public CPropertyPage
+{
+	DECLARE_DYNAMIC(CFourthPage)
+
+public:
+	CFourthPage();
+	virtual ~CFourthPage();
+
+// Dialog Data
+	enum { IDD = IDD_FOURTH_PAGE };
+
+	virtual BOOL OnSetActive();
+
+protected:
+	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
+
+	DECLARE_MESSAGE_MAP()
+
+private:
+
+	OSStatus	OnInitPage();
+	CFont		m_largeFont;
+	bool		m_initialized;
+
+
+public:
+	CStatic m_goodbye;
+private:
+	CStatic m_printerNameCtrl;
+	CStatic m_printerManufacturerCtrl;
+	CStatic m_printerModelCtrl;
+	CStatic m_printerPortCtrl;
+	CStatic m_printerDefault;
+};
diff --git a/Clients/PrinterSetupWizard/PrinterSetupWizard.ncb b/Clients/PrinterSetupWizard/PrinterSetupWizard.ncb
new file mode 100644
index 0000000..9057eba
--- /dev/null
+++ b/Clients/PrinterSetupWizard/PrinterSetupWizard.ncb
@@ -0,0 +1 @@
+Microsoft C/C++ MSF 7.00
diff --git a/Clients/PrinterSetupWizard/PrinterSetupWizard.rc b/Clients/PrinterSetupWizard/PrinterSetupWizard.rc
new file mode 100644
index 0000000..f099a44
--- /dev/null
+++ b/Clients/PrinterSetupWizard/PrinterSetupWizard.rc
@@ -0,0 +1,346 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+#include "WinVersRes.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// Russian resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_RUS)
+#ifdef _WIN32
+LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT
+#pragma code_page(1251)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE 
+BEGIN
+    "resource.h\0"
+END
+
+2 TEXTINCLUDE 
+BEGIN
+    "#include ""afxres.h""\r\n"
+    "#include ""WinVersRes.h""\r\n"
+    "\0"
+END
+
+3 TEXTINCLUDE 
+BEGIN
+    "#define _AFX_NO_SPLITTER_RESOURCES\r\n"
+    "#define _AFX_NO_OLE_RESOURCES\r\n"
+    "#define _AFX_NO_TRACKER_RESOURCES\r\n"
+    "#define _AFX_NO_PROPERTY_RESOURCES\r\n"
+    "\r\n"
+    "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n"
+    "LANGUAGE 9, 1\r\n"
+    "#pragma code_page(1252)\r\n"
+    "#include ""res\\PrinterSetupWizard.rc2""  // non-Microsoft Visual C++ edited resources\r\n"
+    "#include ""afxres.rc""         // Standard components\r\n"
+    "#endif\r\n"
+    "\0"
+END
+
+#endif    // APSTUDIO_INVOKED
+
+#endif    // Russian resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDR_MAINFRAME           ICON                    "res\\Print.ico"
+IDI_INFO                ICON                    "res\\Info.ico"
+IDI_PRINTER             ICON                    "res\\NetworkPrinter.ico"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Bitmap
+//
+
+IDB_WATERMARK           BITMAP                  "res\\watermark.bmp"
+IDB_BANNER_ICON         BITMAP                  "res\\banner_icon.bmp"
+IDB_ABOUT               BITMAP                  "res\\about.bmp"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_ABOUTBOX DIALOGEX 0, 0, 235, 55
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | 
+    WS_SYSMENU
+CAPTION "About Printer Setup Wizard"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+    ICON            IDR_MAINFRAME,IDC_STATIC,11,17,20,20
+    LTEXT           "Printer Setup Wizard Version 1.0",IDC_STATIC,40,10,119,
+                    8,SS_NOPREFIX
+    LTEXT           "Copyright (C) 2002",IDC_STATIC,40,25,119,8
+    DEFPUSHBUTTON   "OK",IDOK,178,7,50,16,WS_GROUP
+END
+
+IDD_PRINTERSETUPWIZARD_DIALOG DIALOGEX 0, 0, 320, 200
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE | 
+    WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_APPWINDOW
+CAPTION "Printer Setup Wizard"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+    DEFPUSHBUTTON   "OK",IDOK,263,7,50,16
+    PUSHBUTTON      "Cancel",IDCANCEL,263,25,50,16
+    PUSHBUTTON      "Start Wizard",IDC_BUTTON1,100,86,109,35
+END
+
+IDD_SECOND_PAGE DIALOGEX 0, 0, 290, 154
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_DISABLED | WS_CAPTION
+CAPTION "Rendezvous Printer Wizard"
+FONT 8, "MS Shell Dlg", 0, 0, 0x0
+BEGIN
+    LTEXT           "Shared Printers:",IDC_STATIC,3,0,171,8
+    CONTROL         "",IDC_BROWSE_LIST,"SysTreeView32",TVS_DISABLEDRAGDROP | 
+                    TVS_SHOWSELALWAYS | TVS_FULLROWSELECT | WS_BORDER | 
+                    WS_TABSTOP,2,11,286,142
+END
+
+IDD_FIRST_PAGE DIALOGEX 0, 0, 290, 199
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_DISABLED | WS_CAPTION
+CAPTION "Rendezvous Printer Wizard"
+FONT 8, "MS Shell Dlg", 0, 0, 0x0
+BEGIN
+    LTEXT           "Welcome to the Rendezvous Printer Setup Wizard",IDC_GREETING,
+                    114,7,171,46
+    LTEXT           "Click next to continue.",IDC_STATIC,115,188,143,8
+    LTEXT           "This wizard helps you connect to a shared printer using Rendezvous.  Make sure your printer is turned on and connected to your network.",
+                    IDC_STATIC,146,60,139,62
+    ICON            IDI_INFO,IDC_STATIC,118,60,21,20,SS_REALSIZEIMAGE,
+                    WS_EX_TRANSPARENT
+END
+
+IDD_THIRD_PAGE DIALOGEX 0, 0, 290, 154
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | 
+    WS_SYSMENU
+CAPTION "Rendezvous Printer Wizard"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+    CONTROL         "",IDC_PRINTER_MODEL,"SysListView32",LVS_REPORT | 
+                    LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_SORTASCENDING | 
+                    LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,110,58,178,76
+    CONTROL         "",IDC_PRINTER_MANUFACTURER,"SysListView32",LVS_REPORT | 
+                    LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_SORTASCENDING | 
+                    LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,2,58,105,76
+    ICON            IDI_PRINTER,IDC_PRINTER_IMAGE,1,0,21,20,SS_REALSIZEIMAGE
+    LTEXT           "",IDC_PRINTER_NAME,40,5,173,8
+    LTEXT           "The Rendezvous Printer Wizard has auto-selected the following printer settings.  Click 'Next' to continue installing this printer.",
+                    IDC_PRINTER_SELECTION_TEXT,40,23,243,26
+    CONTROL         "Use this printer as the default printer",
+                    IDC_DEFAULT_PRINTER,"Button",BS_AUTOCHECKBOX | 
+                    WS_TABSTOP,3,142,224,10
+    PUSHBUTTON      "Have Disk...",IDC_HAVE_DISK,238,140,50,14
+END
+
+IDD_FOURTH_PAGE DIALOGEX 0, 0, 290, 199
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_DISABLED | WS_CAPTION
+CAPTION "Rendezvous Printer Wizard"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+    LTEXT           "Completing the Rendezvous Printer Wizard",IDC_GOODBYE,
+                    116,7,171,27
+    LTEXT           "You have successfully completed the Rendezvous Printer Wizard.  The printer has the following settings:",
+                    IDC_STATIC,116,42,158,31
+    LTEXT           "Name:",IDC_STATIC,116,78,22,8
+    LTEXT           "Manufacturer:",IDC_STATIC,116,91,47,8
+    LTEXT           "Model:",IDC_STATIC,116,104,22,8
+    LTEXT           "Port:",IDC_STATIC,116,117,17,8
+    LTEXT           "Default:",IDC_STATIC,116,130,27,8
+    LTEXT           "",IDC_PRINTER_NAME,172,79,113,8
+    LTEXT           "",IDC_PRINTER_MANUFACTURER,172,91,113,8
+    LTEXT           "",IDC_PRINTER_MODEL,172,103,113,8
+    LTEXT           "",IDC_PRINTER_PORT,172,116,113,8
+    LTEXT           "",IDC_PRINTER_DEFAULT,172,130,113,8
+    LTEXT           "To close this wizard, click Finish.",IDC_STATIC,116,187,
+                    103,8
+END
+
+IDD_DIALOG1 DIALOGEX 0, 0, 265, 130
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | 
+    WS_SYSMENU
+CAPTION "Dialog"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+    CONTROL         138,IDC_STATIC,"Static",SS_BITMAP | SS_REALSIZEIMAGE,0,0,
+                    265,131
+    LTEXT           "Static",IDC_STATIC,77,12,19,8
+    LTEXT           "Static",IDC_STATIC,71,46,19,8
+    LTEXT           "Static",IDC_STATIC,71,89,19,8
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION MASTER_PROD_VERS
+ PRODUCTVERSION MASTER_PROD_VERS
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x1L
+ FILESUBTYPE 0x0L
+BEGIN
+    BLOCK "StringFileInfo"
+    BEGIN
+        BLOCK "040904e4"
+        BEGIN
+            VALUE "CompanyName", "Apple Computer, Inc."
+            VALUE "FileDescription", "Rendezvous Printer Wizard"
+            VALUE "FileVersion", MASTER_PROD_VERS_STR
+            VALUE "InternalName", "RendezvousPrinterWizard.exe"
+            VALUE "LegalCopyright", "Copyright (C) 2003-2004 Apple Computer, Inc."
+            VALUE "OriginalFilename", "RendezvousPrinterWizard.exe"
+            VALUE "ProductName", MASTER_PROD_NAME
+            VALUE "ProductVersion", MASTER_PROD_VERS_STR
+        END
+    END
+    BLOCK "VarFileInfo"
+    BEGIN
+        VALUE "Translation", 0x409, 1252
+    END
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO 
+BEGIN
+    IDD_SECOND_PAGE, DIALOG
+    BEGIN
+        BOTTOMMARGIN, 153
+    END
+
+    IDD_FIRST_PAGE, DIALOG
+    BEGIN
+        RIGHTMARGIN, 285
+        BOTTOMMARGIN, 196
+    END
+
+    IDD_FOURTH_PAGE, DIALOG
+    BEGIN
+        RIGHTMARGIN, 285
+        BOTTOMMARGIN, 197
+    END
+END
+#endif    // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// RT_MANIFEST
+//
+
+IDR_MANIFEST            RT_MANIFEST             "res\\PrinterSetupWizard.manifest"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// String Table
+//
+
+STRINGTABLE 
+BEGIN
+    IDS_ABOUTBOX            "&About Printer Setup Wizard..."
+    IDS_GOODBYE             "Completing the Rendezvous Printer Setup Wizard."
+    IDS_GREETING            "Welcome to the Rendezvous Printer Setup Wizard"
+    IDS_BROWSE_TITLE        "Browse for Rendezvous Printers"
+    IDS_BROWSE_SUBTITLE     "Select the printer you want to use from the list below."
+    IDS_CAPTION             "Rendezvous Printer Wizard"
+    IDS_GOODBYE_GOOD1       "You have successfully completed the Rendezvous Printer Wizard.  The printer has the following settings:"
+    IDS_SEARCHING           "Searching for printers..."
+    IDS_GOODBYTE_GOOD2      "To close this wizard, click Finish."
+    IDS_INSTALL_TITLE       "Install Rendezvous Printer"
+    IDS_INSTALL_SUBTITLE    "The manufacturer and model determine which printer software to use."
+END
+
+STRINGTABLE 
+BEGIN
+    IDS_ERROR_SELECTING_PRINTER_TEXT 
+                            "There was an error selecting this printer."
+    IDS_ERROR_SELECTING_PRINTER_CAPTION "Error"
+    IDS_INSTALL_ERROR_CAPTION "Error"
+    IDS_INSTALL_ERROR_MESSAGE 
+                            "You do not have sufficient access to your computer to connect to the selected printer."
+    IDS_MANUFACTURER_HEADING "Manufacturer"
+    IDS_MODEL_HEADING       "Model"
+    IDS_NO_RENDEZVOUS_PRINTERS "No Rendezvous Printers are available"
+    IDS_NO_MDNSRESPONDER_SERVICE_TEXT "Rendezvous Service is not available"
+    IDS_NO_MDNSRESPONDER_SERVICE_CAPTION "Error"
+    IDS_PRINTER_MATCH_GOOD  "The Rendezvous Printer Wizard has auto-selected the following printer settings.  Click 'Next' to continue installing this printer."
+    IDS_PRINTER_MATCH_BAD   "The Rendezvous Printer Wizard cannot find a driver for this printer.  Manually select from the list, or click 'Have Disk' if your printer came with an installation disk. "
+    IDS_YES                 "Yes"
+    IDS_NO                  "No"
+    IDS_LARGE_FONT          "MS Sans Serif"
+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 "res\PrinterSetupWizard.rc2"  // non-Microsoft Visual C++ edited resources
+#include "afxres.rc"         // Standard components
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+#endif    // not APSTUDIO_INVOKED
+
diff --git a/Clients/PrinterSetupWizard/PrinterSetupWizard.vcproj b/Clients/PrinterSetupWizard/PrinterSetupWizard.vcproj
new file mode 100644
index 0000000..280c398
--- /dev/null
+++ b/Clients/PrinterSetupWizard/PrinterSetupWizard.vcproj
@@ -0,0 +1,269 @@
+<?xml version="1.0" encoding = "windows-1251"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="7.00"
+	Name="PrinterSetupWizard"
+	ProjectGUID="{B1D2CDA2-CC8F-45D5-A694-2EE45B0308CF}"
+	Keyword="MFCProj">
+	<Platforms>
+		<Platform
+			Name="Win32"/>
+	</Platforms>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="Debug"
+			IntermediateDirectory="Debug"
+			ConfigurationType="1"
+			UseOfMFC="1"
+			CharacterSet="2">
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories=".;../../mDNSWindows;../../mDNSShared;C:\WINDDK\2600.1106\inc;C:\WINDDK\2600.1106\inc\wxp"
+				PreprocessorDefinitions="WIN32;_WINDOWS;_DEBUGS;DEBUG=1;WINVER=0x0400;UNICODE;_UNICODE"
+				StringPooling="TRUE"
+				MinimalRebuild="TRUE"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="1"
+				BufferSecurityCheck="TRUE"
+				TreatWChar_tAsBuiltInType="TRUE"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				Detect64BitPortabilityProblems="TRUE"
+				DebugInformationFormat="4"
+				CallingConvention="0"
+				DisableSpecificWarnings="4702"/>
+			<Tool
+				Name="VCCustomBuildTool"/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="../../mDNSWindows/DLL/Debug/dnssd.lib ws2_32.lib iphlpapi.lib winspool.lib"
+				OutputFile="$(OutDir)/RendezvousPrinterWizard.exe"
+				LinkIncremental="2"
+				GenerateDebugInformation="TRUE"
+				SubSystem="2"
+				EntryPointSymbol="wWinMainCRTStartup"
+				TargetMachine="1"/>
+			<Tool
+				Name="VCMIDLTool"
+				PreprocessorDefinitions="_DEBUG"
+				MkTypLibCompatible="FALSE"/>
+			<Tool
+				Name="VCPostBuildEventTool"/>
+			<Tool
+				Name="VCPreBuildEventTool"/>
+			<Tool
+				Name="VCPreLinkEventTool"/>
+			<Tool
+				Name="VCResourceCompilerTool"
+				PreprocessorDefinitions="_DEBUG"
+				Culture="1033"
+				AdditionalIncludeDirectories="$(IntDir);../../mDNSWindows"/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"/>
+			<Tool
+				Name="VCWebDeploymentTool"/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="Release"
+			IntermediateDirectory="Release"
+			ConfigurationType="1"
+			UseOfMFC="1"
+			CharacterSet="2">
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="2"
+				InlineFunctionExpansion="1"
+				OmitFramePointers="TRUE"
+				AdditionalIncludeDirectories=".;../../mDNSWindows;../../mDNSShared;C:\WINDDK\2600.1106\inc;C:\WINDDK\2600.1106\inc\wxp"
+				PreprocessorDefinitions="WIN32;_WINDOWS;NDEBUG;WINVER=0x0400;UNICODE;_UNICODE"
+				StringPooling="TRUE"
+				MinimalRebuild="FALSE"
+				RuntimeLibrary="0"
+				EnableFunctionLevelLinking="TRUE"
+				TreatWChar_tAsBuiltInType="TRUE"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				Detect64BitPortabilityProblems="TRUE"
+				DebugInformationFormat="3"
+				DisableSpecificWarnings="4702"/>
+			<Tool
+				Name="VCCustomBuildTool"/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="../../mDNSWindows/DLL/Release/dnssd.lib ws2_32.lib iphlpapi.lib winspool.lib"
+				OutputFile="$(OutDir)/RendezvousPrinterWizard.exe"
+				LinkIncremental="1"
+				GenerateDebugInformation="TRUE"
+				SubSystem="2"
+				OptimizeReferences="0"
+				EnableCOMDATFolding="0"
+				EntryPointSymbol="wWinMainCRTStartup"
+				TargetMachine="1"/>
+			<Tool
+				Name="VCMIDLTool"
+				PreprocessorDefinitions="NDEBUG"
+				MkTypLibCompatible="FALSE"/>
+			<Tool
+				Name="VCPostBuildEventTool"/>
+			<Tool
+				Name="VCPreBuildEventTool"/>
+			<Tool
+				Name="VCPreLinkEventTool"/>
+			<Tool
+				Name="VCResourceCompilerTool"
+				PreprocessorDefinitions="NDEBUG"
+				Culture="1033"
+				AdditionalIncludeDirectories="$(IntDir);../../mDNSWindows"/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"/>
+			<Tool
+				Name="VCWebDeploymentTool"/>
+		</Configuration>
+	</Configurations>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm">
+			<File
+				RelativePath=".\About.cpp">
+			</File>
+			<File
+				RelativePath="FirstPage.cpp">
+			</File>
+			<File
+				RelativePath=".\FourthPage.cpp">
+			</File>
+			<File
+				RelativePath="PrinterSetupWizardApp.cpp">
+			</File>
+			<File
+				RelativePath="PrinterSetupWizardSheet.cpp">
+			</File>
+			<File
+				RelativePath="SecondPage.cpp">
+			</File>
+			<File
+				RelativePath=".\StdioFileEx.cpp">
+			</File>
+			<File
+				RelativePath="ThirdPage.cpp">
+			</File>
+			<File
+				RelativePath="stdafx.cpp">
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc">
+			<File
+				RelativePath=".\About.h">
+			</File>
+			<File
+				RelativePath="FirstPage.h">
+			</File>
+			<File
+				RelativePath=".\FourthPage.h">
+			</File>
+			<File
+				RelativePath="PrinterSetupWizardApp.h">
+			</File>
+			<File
+				RelativePath="PrinterSetupWizardSheet.h">
+			</File>
+			<File
+				RelativePath="Resource.h">
+			</File>
+			<File
+				RelativePath="SecondPage.h">
+			</File>
+			<File
+				RelativePath=".\StdioFileEx.h">
+			</File>
+			<File
+				RelativePath="ThirdPage.h">
+			</File>
+			<File
+				RelativePath=".\UtilTypes.h">
+			</File>
+			<File
+				RelativePath="stdafx.h">
+			</File>
+		</Filter>
+		<Filter
+			Name="Resource Files"
+			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;jpg;jpeg;jpe;manifest">
+			<File
+				RelativePath=".\res\Info.ico">
+			</File>
+			<File
+				RelativePath=".\res\NetworkPrinter.ico">
+			</File>
+			<File
+				RelativePath=".\res\Print.ico">
+			</File>
+			<File
+				RelativePath=".\res\Printer.bmp">
+			</File>
+			<File
+				RelativePath=".\res\Printer.ico">
+			</File>
+			<File
+				RelativePath=".\res\Printer2.ico">
+			</File>
+			<File
+				RelativePath="res\PrinterSetupWizard.ico">
+			</File>
+			<File
+				RelativePath="res\PrinterSetupWizard.manifest">
+			</File>
+			<File
+				RelativePath="PrinterSetupWizard.rc">
+			</File>
+			<File
+				RelativePath="res\PrinterSetupWizard.rc2">
+			</File>
+			<File
+				RelativePath=".\res\about.bmp">
+			</File>
+			<File
+				RelativePath="res\banner_icon.bmp">
+			</File>
+			<File
+				RelativePath="res\watermark.bmp">
+			</File>
+		</Filter>
+		<Filter
+			Name="Support"
+			Filter="">
+			<File
+				RelativePath="..\..\mDNSWindows\CommonServices.h">
+			</File>
+			<File
+				RelativePath="..\..\mDNSWindows\DebugServices.c">
+			</File>
+			<File
+				RelativePath="..\..\mDNSWindows\DebugServices.h">
+			</File>
+			<File
+				RelativePath="..\..\mDNSWindows\WinServices.cpp">
+			</File>
+			<File
+				RelativePath="..\..\mDNSWindows\WinServices.h">
+			</File>
+			<File
+				RelativePath="..\..\mDNSShared\dns_sd.h">
+			</File>
+		</Filter>
+		<File
+			RelativePath="ReadMe.txt">
+		</File>
+	</Files>
+	<Globals>
+		<Global
+			Name="RESOURCE_FILE"
+			Value="PrinterSetupWizard.rc"/>
+	</Globals>
+</VisualStudioProject>
diff --git a/Clients/PrinterSetupWizard/PrinterSetupWizardApp.cpp b/Clients/PrinterSetupWizard/PrinterSetupWizardApp.cpp
new file mode 100644
index 0000000..295b4a9
--- /dev/null
+++ b/Clients/PrinterSetupWizard/PrinterSetupWizardApp.cpp
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+    
+$Log: PrinterSetupWizardApp.cpp,v $
+Revision 1.3  2004/07/13 21:24:23  rpantos
+Fix for <rdar://problem/3701120>.
+
+Revision 1.2  2004/06/24 20:12:08  shersche
+Clean up source code
+Submitted by: herscher
+
+Revision 1.1  2004/06/18 04:36:57  rpantos
+First checked in
+
+
+*/
+
+#include "stdafx.h"
+#include "PrinterSetupWizardApp.h"
+#include "PrinterSetupWizardSheet.h"
+#include "DebugServices.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#endif
+
+
+// CPrinterSetupWizardApp
+
+BEGIN_MESSAGE_MAP(CPrinterSetupWizardApp, CWinApp)
+	ON_COMMAND(ID_HELP, CWinApp::OnHelp)
+END_MESSAGE_MAP()
+
+
+// CPrinterSetupWizardApp construction
+
+CPrinterSetupWizardApp::CPrinterSetupWizardApp()
+{
+	// TODO: add construction code here,
+	// Place all significant initialization in InitInstance
+}
+
+
+// The one and only CPrinterSetupWizardApp object
+
+CPrinterSetupWizardApp theApp;
+
+
+// CPrinterSetupWizardApp initialization
+
+BOOL CPrinterSetupWizardApp::InitInstance()
+{
+	//
+	// initialize the debugging framework
+	//
+	debug_initialize( kDebugOutputTypeWindowsDebugger, "PrinterSetupWizard", NULL );
+	debug_set_property( kDebugPropertyTagPrintLevel, kDebugLevelTrace );
+
+
+	// InitCommonControls() is required on Windows XP if an application
+	// manifest specifies use of ComCtl32.dll version 6 or later to enable
+	// visual styles.  Otherwise, any window creation will fail.
+	InitCommonControls();
+
+	CWinApp::InitInstance();
+
+	AfxEnableControlContainer();
+
+	CPrinterSetupWizardSheet dlg(IDS_CAPTION);
+
+	m_pMainWnd = &dlg;
+
+	try
+	{
+		INT_PTR nResponse = dlg.DoModal();
+	
+		if (nResponse == IDOK)
+		{
+			// TODO: Place code here to handle when the dialog is
+			//  dismissed with OK
+		}
+		else if (nResponse == IDCANCEL)
+		{
+			// TODO: Place code here to handle when the dialog is
+			//  dismissed with Cancel
+		}
+	}
+	catch (CPrinterSetupWizardSheet::WizardException & exc)
+	{
+		MessageBox(NULL, exc.text, exc.caption, MB_OK|MB_ICONEXCLAMATION);
+	}
+
+	// Since the dialog has been closed, return FALSE so that we exit the
+	//  application, rather than start the application's message pump.
+	return FALSE;
+}
diff --git a/mDNSWindows/Applications/mdnsNSP/Prefix.h b/Clients/PrinterSetupWizard/PrinterSetupWizardApp.h
similarity index 62%
rename from mDNSWindows/Applications/mdnsNSP/Prefix.h
rename to Clients/PrinterSetupWizard/PrinterSetupWizardApp.h
index b1b7369..aa3f233 100644
--- a/mDNSWindows/Applications/mdnsNSP/Prefix.h
+++ b/Clients/PrinterSetupWizard/PrinterSetupWizardApp.h
@@ -1,10 +1,8 @@
 /*
- * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
+ * 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
@@ -24,22 +22,39 @@
 
     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.
+$Log: PrinterSetupWizardApp.h,v $
+Revision 1.1  2004/06/18 04:36:57  rpantos
+First checked in
+
 
 */
 
-#ifndef __PREFIX__
-#define __PREFIX__
+#pragma once
 
-#if( defined( _DEBUG ) )
-	#define	DEBUG						1
-	#define	DNS_SD_DIRECT_ENABLED		0
-#else
-	#define	DEBUG						0
-	#define	DNS_SD_DIRECT_ENABLED		0
+#ifndef __AFXWIN_H__
+	#error include 'stdafx.h' before including this file for PCH
 #endif
 
-#endif	// __PREFIX__
+#include "resource.h"		// main symbols
+
+
+// CWiz97_3App:
+// See Wiz97_3.cpp for the implementation of this class
+//
+
+class CPrinterSetupWizardApp : public CWinApp
+{
+public:
+	CPrinterSetupWizardApp();
+
+// Overrides
+	public:
+	virtual BOOL InitInstance();
+
+// Implementation
+
+	DECLARE_MESSAGE_MAP()
+};
+
+
+extern CPrinterSetupWizardApp theApp;
diff --git a/Clients/PrinterSetupWizard/PrinterSetupWizardSheet.cpp b/Clients/PrinterSetupWizard/PrinterSetupWizardSheet.cpp
new file mode 100644
index 0000000..02b2952
--- /dev/null
+++ b/Clients/PrinterSetupWizard/PrinterSetupWizardSheet.cpp
@@ -0,0 +1,1085 @@
+/*
+ * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+    
+$Log: PrinterSetupWizardSheet.cpp,v $
+Revision 1.17  2004/10/12 18:02:53  shersche
+<rdar://problem/3764873> Escape '/', '@', '"' characters in printui command.
+Bug #: 3764873
+
+Revision 1.16  2004/09/13 21:27:22  shersche
+<rdar://problem/3796483> Pass the moreComing flag to OnAddPrinter and OnRemovePrinter callbacks
+Bug #: 3796483
+
+Revision 1.15  2004/09/11 05:59:06  shersche
+<rdar://problem/3785766> Fix code that generates unique printer names based on currently installed printers
+Bug #: 3785766
+
+Revision 1.14  2004/09/02 01:57:58  cheshire
+<rdar://problem/3783611> Fix incorrect testing of MoreComing flag
+
+Revision 1.13  2004/07/26 21:06:29  shersche
+<rdar://problem/3739200> Removing trailing '.' in hostname
+Bug #: 3739200
+
+Revision 1.12  2004/07/13 21:24:23  rpantos
+Fix for <rdar://problem/3701120>.
+
+Revision 1.11  2004/06/28 00:51:47  shersche
+Move call to EnumPrinters out of browse callback into standalone function
+
+Revision 1.10  2004/06/27 23:06:47  shersche
+code cleanup, make sure EnumPrinters returns non-zero value
+
+Revision 1.9  2004/06/27 15:49:31  shersche
+clean up some cruft in the printer browsing code
+
+Revision 1.8  2004/06/27 08:04:51  shersche
+copy selected printer to prevent printer being deleted out from under
+
+Revision 1.7  2004/06/26 23:27:12  shersche
+support for installing multiple printers of the same name
+
+Revision 1.6  2004/06/26 21:22:39  shersche
+handle spaces in file names
+
+Revision 1.5  2004/06/26 03:19:57  shersche
+clean up warning messages
+
+Submitted by: herscher
+
+Revision 1.4  2004/06/25 02:26:52  shersche
+Normalize key fields in text record entries
+Submitted by: herscher
+
+Revision 1.3  2004/06/24 20:12:07  shersche
+Clean up source code
+Submitted by: herscher
+
+Revision 1.2  2004/06/23 17:58:21  shersche
+<rdar://problem/3701837> eliminated memory leaks on exit
+<rdar://problem/3701926> installation of a printer that is already installed results in a no-op
+Bug #: 3701837, 3701926
+Submitted by: herscher
+
+Revision 1.1  2004/06/18 04:36:57  rpantos
+First checked in
+
+
+*/
+
+#include "stdafx.h"
+#include "PrinterSetupWizardApp.h"
+#include "PrinterSetupWizardSheet.h"
+#include "CommonServices.h"
+#include "DebugServices.h"
+#include "WinServices.h"
+#include "About.h"
+#include <winspool.h>
+#include <tcpxcv.h>
+#include <string>
+
+// unreachable code
+#pragma warning(disable:4702)
+
+
+#if( !TARGET_OS_WINDOWS_CE )
+#	include	<mswsock.h>
+#	include	<process.h>
+#endif
+
+// Private Messages
+
+#define WM_SERVICE_EVENT				( WM_USER + 0x100 )
+#define WM_PROCESS_EVENT				( WM_USER + 0x101 )
+
+// Service Types
+
+#define	kPDLDataStreamServiceType		"_pdl-datastream._tcp"
+#define kLPRServiceType					"_printer._tcp"
+#define kIPPServiceType					"_ipp._tcp"
+
+
+// CPrinterSetupWizardSheet
+
+IMPLEMENT_DYNAMIC(CPrinterSetupWizardSheet, CPropertySheet)
+CPrinterSetupWizardSheet::CPrinterSetupWizardSheet(UINT nIDCaption, CWnd* pParentWnd, UINT iSelectPage)
+	:CPropertySheet(nIDCaption, pParentWnd, iSelectPage),
+	m_selectedPrinter(NULL)
+{
+	m_arrow		=	LoadCursor(0, IDC_ARROW);
+	m_wait		=	LoadCursor(0, IDC_APPSTARTING);
+	m_active	=	m_arrow;
+	
+	Init();
+}
+
+
+CPrinterSetupWizardSheet::~CPrinterSetupWizardSheet()
+{
+	//
+	// rdar://problem/3701837 memory leaks
+	//
+	// Clean up the ServiceRef and printer list on exit
+	//
+	if (m_pdlBrowser != NULL)
+	{
+		DNSServiceRefDeallocate(m_pdlBrowser);
+		m_pdlBrowser = NULL;
+	}
+
+	while (m_printerList.size() > 0)
+	{
+		Printer * printer = m_printerList.front();
+
+		m_printerList.pop_front();
+
+		delete printer;
+	}
+
+	if (m_selectedPrinter != NULL)
+	{
+		delete m_selectedPrinter;
+	}
+}
+
+
+// ------------------------------------------------------
+// InstallEventHandler
+//
+// Installs an event handler for DNSService events.  
+//	
+int
+CPrinterSetupWizardSheet::InstallEventHandler(EventHandler * handler)
+{
+	PrinterList::iterator iter;
+	
+	m_eventHandlerList.push_back(handler);
+
+	iter = m_printerList.begin();
+
+	while (iter != m_printerList.end())
+	{
+		Printer * printer = *iter++;
+
+		handler->OnAddPrinter(printer, iter != m_printerList.end());
+	}
+	
+	return kNoErr;
+}
+
+
+// ------------------------------------------------------
+// RemoveEventHandler
+//
+// Removes an event handler for DNSService events.  
+//	
+int
+CPrinterSetupWizardSheet::RemoveEventHandler(EventHandler * handler)
+{
+	m_eventHandlerList.remove(handler);
+
+	return kNoErr;
+}
+
+
+
+// ------------------------------------------------------
+// SetSelectedPrinter
+//
+// Manages setting a printer as the printer to install.  Stops
+// any pending resolves.  
+//	
+OSStatus
+CPrinterSetupWizardSheet::SetSelectedPrinter(Printer * printer)
+{
+	OSStatus err;
+
+	//
+	// we only want one resolve going on at a time, so we check
+	// state of the m_selectedPrinter
+	//
+	if (m_selectedPrinter != NULL)
+	{
+		//
+		// if we're currently resolving, then stop the resolve
+		//
+		if (m_selectedPrinter->serviceRef)
+		{
+			err = StopResolve(m_selectedPrinter);
+			require_noerr(err, exit);
+		}
+
+		delete m_selectedPrinter;
+		m_selectedPrinter = NULL;
+	}
+
+	check( m_selectedPrinter == NULL );
+
+	try
+	{
+		m_selectedPrinter = new Printer;
+	}
+	catch (...)
+	{
+		m_selectedPrinter = NULL;
+	}
+
+	require_action( m_selectedPrinter, exit, err = E_OUTOFMEMORY );
+
+	m_selectedPrinter->window		=	printer->window;
+	m_selectedPrinter->serviceRef	=	NULL;
+	m_selectedPrinter->item			=	NULL;
+	m_selectedPrinter->ifi			=	printer->ifi;
+	m_selectedPrinter->name			=	printer->name;
+	m_selectedPrinter->displayName	=	printer->displayName;
+	m_selectedPrinter->actualName	=	printer->actualName;
+	m_selectedPrinter->type			=	printer->type;
+	m_selectedPrinter->domain		=	printer->domain;
+	m_selectedPrinter->installed	=	printer->installed;
+	m_selectedPrinter->deflt		=	printer->deflt;
+	m_selectedPrinter->refs			=	1;
+			
+	err = StartResolve(m_selectedPrinter);
+	require_noerr(err, exit);
+
+exit:
+
+	return err;
+}
+
+
+// ------------------------------------------------------
+// InstallPrinter
+//
+// Installs a printer with Windows.
+//
+// NOTE: this works one of two ways, depending on whether
+// there are drivers already installed for this printer.
+// If there are, then we can just create a port with XcvData,
+// and then call AddPrinter.  If not, we use the printui.dll
+// to install the printer. Actually installing drivers that
+// are not currently installed is painful, and it's much
+// easier and less error prone to just let printui.dll do
+// the hard work for us.
+//	
+
+OSStatus
+CPrinterSetupWizardSheet::InstallPrinter(Printer * printer)
+{
+	PRINTER_DEFAULTS	printerDefaults =	{ NULL,  NULL, SERVER_ACCESS_ADMINISTER };
+	DWORD				dwStatus;
+	DWORD				cbInputData		=	100;
+	PBYTE				pOutputData		=	NULL;
+	DWORD				cbOutputNeeded	=	0;
+	PORT_DATA_1			portData;
+	HANDLE				hXcv			=	NULL;
+	HANDLE				hPrinter		=	NULL;
+	BOOL				ok;
+	OSStatus			err;
+
+	check(printer != NULL);
+	check(printer->installed == false);
+
+	ok = OpenPrinter(L",XcvMonitor Standard TCP/IP Port", &hXcv, &printerDefaults);
+	err = translate_errno( ok, errno_compat(), kUnknownErr );
+	require_noerr( err, exit );
+	
+	//
+	// BUGBUG: MSDN said this is not required, but my experience shows it is required
+	//
+	try
+	{
+		pOutputData = new BYTE[cbInputData];
+	}
+	catch (...)
+	{
+		pOutputData = NULL;
+	}
+
+	require_action( pOutputData, exit, err = kNoMemoryErr );
+	
+	//
+	// setup the port
+	//
+	ZeroMemory(&portData, sizeof(PORT_DATA_1));
+	wcscpy(portData.sztPortName, printer->portName);
+    	
+	portData.dwPortNumber	=	printer->portNumber;
+	portData.dwVersion		=	1;
+    	
+	portData.dwProtocol	= PROTOCOL_RAWTCP_TYPE;
+	portData.cbSize		= sizeof PORT_DATA_1;
+	portData.dwReserved	= 0L;
+    	
+	wcscpy(portData.sztQueue, printer->hostname);
+	wcscpy(portData.sztIPAddress, printer->hostname); 
+	wcscpy(portData.sztHostAddress, printer->hostname);
+		
+	ok = XcvData(hXcv, L"AddPort", (PBYTE) &portData, sizeof(PORT_DATA_1), pOutputData, cbInputData,  &cbOutputNeeded, &dwStatus);
+	err = translate_errno( ok, errno_compat(), kUnknownErr );
+	require_noerr( err, exit );
+	
+	if (printer->driverInstalled)
+	{
+		PRINTER_INFO_2 pInfo;
+	
+		ZeroMemory(&pInfo, sizeof(pInfo));
+			
+		pInfo.pPrinterName			=	printer->actualName.GetBuffer();
+		pInfo.pServerName			=	NULL;
+		pInfo.pShareName			=	NULL;
+		pInfo.pPortName				=	printer->portName.GetBuffer();
+		pInfo.pDriverName			=	printer->model.GetBuffer();
+		pInfo.pComment				=	printer->model.GetBuffer();
+		pInfo.pLocation				=	L"";
+		pInfo.pDevMode				=	NULL;
+		pInfo.pDevMode				=	NULL;
+		pInfo.pSepFile				=	L"";
+		pInfo.pPrintProcessor		=	L"winprint";
+		pInfo.pDatatype				=	L"RAW";
+		pInfo.pParameters			=	L"";
+		pInfo.pSecurityDescriptor	=	NULL;
+		pInfo.Attributes			=	PRINTER_ATTRIBUTE_QUEUED;
+		pInfo.Priority				=	0;
+		pInfo.DefaultPriority		=	0;
+		pInfo.StartTime				=	0;
+		pInfo.UntilTime				=	0;
+	
+		hPrinter = AddPrinter(NULL, 2, (LPBYTE) &pInfo);
+		err = translate_errno( hPrinter, errno_compat(), kUnknownErr );
+		require_noerr( err, exit );
+	}
+	else
+	{
+		DWORD		dwResult;
+		HANDLE		hThread;
+		unsigned	threadID;
+			
+	
+		m_processFinished = false;
+	
+		//
+		// create the thread
+		//
+		hThread = (HANDLE) _beginthreadex_compat( NULL, 0, InstallPrinterThread, printer, 0, &threadID );
+		err = translate_errno( hThread, (OSStatus) GetLastError(), kUnknownErr );
+		require_noerr( err, exit );
+			
+		//
+		// go modal
+		//
+		while (!m_processFinished)
+		{
+			MSG msg;
+	
+			GetMessage( &msg, m_hWnd, 0, 0 );
+			TranslateMessage(&msg);
+			DispatchMessage(&msg);
+		}
+	
+		//
+		// Wait until child process exits.
+		//
+		dwResult = WaitForSingleObject( hThread, INFINITE );
+		err = translate_errno( dwResult == WAIT_OBJECT_0, errno_compat(), err = kUnknownErr );
+		require_noerr( err, exit );
+	}
+
+	printer->installed = true;
+
+	//
+	// if the user specified a default printer, set it
+	//
+	if (printer->deflt)
+	{
+		ok = SetDefaultPrinter(printer->actualName);
+		err = translate_errno( ok, errno_compat(), err = kUnknownErr );
+		require_noerr( err, exit );
+	}
+
+exit:
+
+	if (hPrinter != NULL)
+	{
+		ClosePrinter(hPrinter);
+	}
+
+	if (hXcv != NULL)
+	{
+		ClosePrinter(hXcv);
+	}
+
+	if (pOutputData != NULL)
+	{
+		delete [] pOutputData;
+	}
+
+	return err;
+}
+
+
+BEGIN_MESSAGE_MAP(CPrinterSetupWizardSheet, CPropertySheet)
+ON_MESSAGE( WM_SERVICE_EVENT, OnServiceEvent )
+ON_MESSAGE( WM_PROCESS_EVENT, OnProcessEvent )
+ON_WM_SETCURSOR()
+END_MESSAGE_MAP()
+
+
+// ------------------------------------------------------
+// OnCommand
+//
+// Traps when the user hits Finish  
+//	
+BOOL CPrinterSetupWizardSheet::OnCommand(WPARAM wParam, LPARAM lParam)
+{
+	//
+	// Check if this is OK
+	//
+	if (wParam == ID_WIZFINISH)              // If OK is hit...
+	{
+		OnOK();
+	}
+ 
+	return CPropertySheet::OnCommand(wParam, lParam);
+}
+
+
+// ------------------------------------------------------
+// OnInitDialog
+//
+// Initializes this Dialog object.  We start the browse here,
+// so that printers show up instantly when the user clicks
+// the next button.  
+//	
+BOOL CPrinterSetupWizardSheet::OnInitDialog()
+{
+	OSStatus err;
+
+	CPropertySheet::OnInitDialog();
+	
+	//
+	// setup the DNS-SD browsing
+	//
+	err = DNSServiceBrowse( &m_pdlBrowser, 0, 0, kPDLDataStreamServiceType, NULL, OnBrowse, this );
+	require_noerr( err, exit );
+
+	m_serviceRefList.push_back(m_pdlBrowser);
+
+	err = WSAAsyncSelect((SOCKET) DNSServiceRefSockFD(m_pdlBrowser), m_hWnd, WM_SERVICE_EVENT, FD_READ|FD_CLOSE);
+	require_noerr( err, exit );
+
+	LoadPrinterNames();
+
+exit:
+
+	if (err != kNoErr)
+	{
+		WizardException exc;
+
+		exc.text.LoadString(IDS_NO_MDNSRESPONDER_SERVICE_TEXT);
+		exc.caption.LoadString(IDS_NO_MDNSRESPONDER_SERVICE_CAPTION);
+
+		throw(exc);
+	}
+
+	return TRUE;
+}
+
+
+// ------------------------------------------------------
+// OnSetCursor
+//
+// This is called when Windows wants to know what cursor
+// to display.  So we tell it.  
+//	
+BOOL
+CPrinterSetupWizardSheet::OnSetCursor(CWnd * pWnd, UINT nHitTest, UINT message)
+{
+	DEBUG_UNUSED(pWnd);
+	DEBUG_UNUSED(nHitTest);
+	DEBUG_UNUSED(message);
+
+	SetCursor(m_active);
+	return TRUE;
+}
+
+
+// ------------------------------------------------------
+// OnContextMenu
+//
+// This is not fully implemented yet.  
+//	
+
+void
+CPrinterSetupWizardSheet::OnContextMenu(CWnd * pWnd, CPoint pos)
+{
+	DEBUG_UNUSED(pWnd);
+	DEBUG_UNUSED(pos);
+
+	CAbout dlg;
+
+	dlg.DoModal();
+}
+
+
+// ------------------------------------------------------
+// OnOK
+//
+// This is called when the user hits the "Finish" button  
+//	
+void
+CPrinterSetupWizardSheet::OnOK()
+{
+	check ( m_selectedPrinter != NULL );
+
+	SetWizardButtons( PSWIZB_DISABLEDFINISH );
+
+	if ( InstallPrinter( m_selectedPrinter ) != kNoErr )
+	{
+		CString caption;
+		CString message;
+
+		caption.LoadString(IDS_INSTALL_ERROR_CAPTION);
+		message.LoadString(IDS_INSTALL_ERROR_MESSAGE);
+
+		MessageBox(message, caption, MB_OK|MB_ICONEXCLAMATION);
+	}
+}
+
+
+// CPrinterSetupWizardSheet message handlers
+
+void CPrinterSetupWizardSheet::Init(void)
+{
+	AddPage(&m_pgFirst);
+	AddPage(&m_pgSecond);
+	AddPage(&m_pgThird);
+	AddPage(&m_pgFourth);
+
+	m_psh.dwFlags &= (~PSH_HASHELP);
+
+	m_psh.dwFlags |= PSH_WIZARD97|PSH_WATERMARK|PSH_HEADER;
+	m_psh.pszbmWatermark = MAKEINTRESOURCE(IDB_WATERMARK);
+	m_psh.pszbmHeader = MAKEINTRESOURCE(IDB_BANNER_ICON);
+
+	m_psh.hInstance = AfxGetInstanceHandle();
+
+	SetWizardMode();
+}
+
+
+LONG
+CPrinterSetupWizardSheet::OnServiceEvent(WPARAM inWParam, LPARAM inLParam)
+{
+	if (WSAGETSELECTERROR(inLParam) && !(HIWORD(inLParam)))
+    {
+		dlog( kDebugLevelError, "OnServiceEvent: window error\n" );
+    }
+    else
+    {
+		SOCKET sock = (SOCKET) inWParam;
+
+		// iterate thru list
+		ServiceRefList::iterator begin = m_serviceRefList.begin();
+		ServiceRefList::iterator end   = m_serviceRefList.end();
+
+		while (begin != end)
+		{
+			DNSServiceRef ref = *begin++;
+
+			check(ref != NULL);
+
+			if ((SOCKET) DNSServiceRefSockFD(ref) == sock)
+			{
+				DNSServiceProcessResult(ref);
+				break;
+			}
+		}
+	}
+
+	return ( 0 );
+}
+
+
+LONG
+CPrinterSetupWizardSheet::OnProcessEvent(WPARAM inWParam, LPARAM inLParam)
+{
+	DEBUG_UNUSED(inWParam);
+	DEBUG_UNUSED(inLParam);
+
+	m_processFinished = true;
+
+	return 0;
+}
+
+
+void DNSSD_API
+CPrinterSetupWizardSheet::OnBrowse(
+								DNSServiceRef 			inRef,
+								DNSServiceFlags 		inFlags,
+								uint32_t 				inInterfaceIndex,
+								DNSServiceErrorType 	inErrorCode,
+								const char *			inName,	
+								const char *			inType,	
+								const char *			inDomain,	
+								void *					inContext )
+{
+	DEBUG_UNUSED(inRef);
+
+	CPrinterSetupWizardSheet	*	self;
+	Printer						*	printer;
+	EventHandlerList::iterator		it;
+	DWORD							printerNameCount;
+	bool							moreComing = (bool) (inFlags & kDNSServiceFlagsMoreComing);
+
+	require_noerr( inErrorCode, exit );
+	
+	self = reinterpret_cast <CPrinterSetupWizardSheet*>( inContext );
+	require_quiet( self, exit );
+
+	printer = self->LookUp(inName);
+
+	if (inFlags & kDNSServiceFlagsAdd)
+	{
+		OSStatus err;
+
+		if (printer != NULL)
+		{
+			printer->refs++;
+		}
+		else
+		{
+			try
+			{
+				printer = new Printer;
+			}
+			catch (...)
+			{
+				printer = NULL;
+			}
+
+			require_action( printer, exit, err = E_OUTOFMEMORY );
+
+			printer->window		=	self;
+			printer->ifi		=	inInterfaceIndex;
+			printer->name		=	inName;
+			err = UTF8StringToStringObject(inName, printer->displayName);
+			check_noerr( err );
+			printer->actualName	=	printer->displayName;
+
+			//
+			// Compare this name against printers that are already installed
+			// to avoid name clashes.  Rename as necessary
+			// to come up with a unique name.
+			//
+			printerNameCount = 2;
+
+			for (;;)
+			{
+				PrinterNameMap::iterator it;
+
+				it = self->m_printerNames.find(printer->actualName);
+
+				if (it != self->m_printerNames.end())
+				{
+					printer->actualName.Format(L"%s (%d)", printer->displayName, printerNameCount);
+				}
+				else
+				{
+					break;
+				}
+
+				printerNameCount++;
+			}
+
+			printer->type		=	inType;
+			printer->domain		=	inDomain;
+			printer->installed	=	false;
+			printer->deflt		=	false;
+			printer->refs		=	1;
+			
+			self->m_printerList.push_back( printer );
+
+			//
+			// now invoke event handlers for AddPrinter event
+			//
+			for (it = self->m_eventHandlerList.begin(); it != self->m_eventHandlerList.end(); it++)
+			{
+				EventHandler * handler = *it;
+
+				handler->OnAddPrinter(printer, moreComing);
+			}
+		}
+	}
+	else
+	{
+		if ((printer != NULL) && (--printer->refs == 0))
+		{
+			//
+			// now invoke event handlers for RemovePrinter event
+			//
+			for (it = self->m_eventHandlerList.begin(); it != self->m_eventHandlerList.end(); it++)
+			{
+				EventHandler * handler = *it;
+
+				handler->OnRemovePrinter(printer, moreComing);
+			}
+
+			self->m_printerList.remove(printer);
+
+			//
+			// check to see if we've selected this printer
+			//
+			if (self->m_selectedPrinter == printer)
+			{
+				//
+				// this guy is being removed while we're resolving it...so let's 
+				// stop the resolve
+				//
+				if (printer->serviceRef != NULL)
+				{
+					self->StopResolve(printer);
+				}
+
+				self->m_selectedPrinter = NULL;
+			}
+
+			delete printer;
+		}
+	}
+
+exit:
+
+	return;
+}
+
+
+void DNSSD_API
+CPrinterSetupWizardSheet::OnResolve(
+								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 )
+{
+	DEBUG_UNUSED(inFullName);
+	DEBUG_UNUSED(inInterfaceIndex);
+	DEBUG_UNUSED(inFlags);
+	DEBUG_UNUSED(inRef);
+
+	Printer						*	printer;
+	CPrinterSetupWizardSheet	*	self;
+	EventHandlerList::iterator		it1;
+	EventHandlerList::iterator		it2;
+	int								idx;
+	OSStatus						err;
+
+	require_noerr( inErrorCode, exit );
+
+	printer = reinterpret_cast<Printer*>( inContext );
+	require_quiet( printer, exit);
+
+	self = printer->window;
+	require_quiet( self, exit );
+
+	err = self->StopResolve(printer);
+	require_noerr(err, exit);
+	
+	//
+	// hold on to the hostname...
+	//
+	err = UTF8StringToStringObject( inHostName, printer->hostname );
+	require_noerr( err, exit );
+
+	//
+	// <rdar://problem/3739200> remove the trailing dot on hostname
+	//
+	idx = printer->hostname.ReverseFind('.');
+
+	if ((idx > 1) && ((printer->hostname.GetLength() - 1) == idx))
+	{
+		printer->hostname.Delete(idx, 1);
+	}
+
+	//
+	// hold on to the port
+	//
+	printer->portNumber = ntohs(inPort);
+
+	//
+	// parse the text record.  we create a stringlist of text record
+	// entries that can be interrogated later
+	//
+	while (inTXTSize)
+	{
+		char buf[256];
+
+		unsigned char num = *inTXT;
+		check( (int) num < inTXTSize );
+
+		memset(buf, 0, sizeof(buf));
+		memcpy(buf, inTXT + 1, num);
+		
+		inTXTSize -= (num + 1);
+		inTXT += (num + 1);
+
+		CString elem;
+
+		err = UTF8StringToStringObject( buf, elem );
+		require_noerr( err, exit );
+
+		int curPos = 0;
+
+		CString key = elem.Tokenize(L"=", curPos);
+		CString val = elem.Tokenize(L"=", curPos);
+
+		key.MakeLower();
+
+		if ((key == L"usb_mfg") || (key == L"usb_manufacturer"))
+		{
+			printer->usb_MFG = val;
+		}
+		else if ((key == L"usb_mdl") || (key == L"usb_model"))
+		{
+			printer->usb_MDL = val;
+		}
+		else if (key == L"description")
+		{
+			printer->description = val;
+		}
+		else if (key == L"product")
+		{
+			printer->product = val;
+		}
+	}
+
+	//
+	// now invoke event handlers for Resolve event
+	//
+	it1 = self->m_eventHandlerList.begin();
+	it2 = self->m_eventHandlerList.end();
+
+	while (it1 != it2)
+	{
+		EventHandler * handler = *it1++;
+
+		handler->OnResolvePrinter(printer);
+	}
+
+exit:
+
+	return;
+}
+
+
+OSStatus
+CPrinterSetupWizardSheet::LoadPrinterNames()
+{
+	PBYTE		buffer	=	NULL;
+	OSStatus	err		= 0;
+
+	//
+	// rdar://problem/3701926 - Printer can't be installed twice
+	//
+	// First thing we want to do is make sure the printer isn't already installed.
+	// If the printer name is found, we'll try and rename it until we
+	// find a unique name
+	//
+	DWORD dwNeeded = 0, dwNumPrinters = 0;
+
+	BOOL ok = EnumPrinters(PRINTER_ENUM_LOCAL, NULL, 4, NULL, 0, &dwNeeded, &dwNumPrinters);
+	err = translate_errno( ok, errno_compat(), kUnknownErr );
+
+	if ((err == ERROR_INSUFFICIENT_BUFFER) && (dwNeeded > 0))
+	{
+		try
+		{
+			buffer = new unsigned char[dwNeeded];
+		}
+		catch (...)
+		{
+			buffer = NULL;
+		}
+	
+		require_action( buffer, exit, kNoMemoryErr );
+		ok = EnumPrinters(PRINTER_ENUM_LOCAL, NULL, 4, buffer, dwNeeded, &dwNeeded, &dwNumPrinters);
+		err = translate_errno( ok, errno_compat(), kUnknownErr );
+		require_noerr( err, exit );
+
+		for (DWORD index = 0; index < dwNumPrinters; index++)
+		{
+			PRINTER_INFO_4 * lppi4 = (PRINTER_INFO_4*) (buffer + index * sizeof(PRINTER_INFO_4));
+
+			m_printerNames[lppi4->pPrinterName] = lppi4->pPrinterName;
+		}
+	}
+
+exit:
+
+	if (buffer != NULL)
+	{
+		delete [] buffer;
+	}
+
+	return err;
+}
+
+
+OSStatus
+CPrinterSetupWizardSheet::StartResolve(Printer * printer)
+{
+	OSStatus err;
+
+	check( printer );
+
+	err = DNSServiceResolve( &printer->serviceRef, 0, 0, printer->name.c_str(), printer->type.c_str(), printer->domain.c_str(), (DNSServiceResolveReply) OnResolve, printer );
+	require_noerr( err, exit);
+
+	m_serviceRefList.push_back(printer->serviceRef);
+
+	err = WSAAsyncSelect((SOCKET) DNSServiceRefSockFD(printer->serviceRef), m_hWnd, WM_SERVICE_EVENT, FD_READ|FD_CLOSE);
+	require_noerr( err, exit );
+
+	//
+	// set the cursor to arrow+hourglass
+	//
+	m_active = m_wait;
+	SetCursor(m_active);
+
+exit:
+
+	return err;
+}
+
+
+OSStatus
+CPrinterSetupWizardSheet::StopResolve(Printer * printer)
+{
+	OSStatus err;
+
+	check( printer );
+	check( printer->serviceRef );
+
+	m_serviceRefList.remove( printer->serviceRef );
+
+	err = WSAAsyncSelect((SOCKET) DNSServiceRefSockFD(printer->serviceRef), m_hWnd, 0, 0);
+	check(err == 0);	
+
+	DNSServiceRefDeallocate( printer->serviceRef );
+
+	printer->serviceRef = NULL;
+	
+	//
+	// set the cursor back to normal
+	//
+	m_active = m_arrow;
+	SetCursor(m_active);
+
+	return kNoErr;
+}
+
+
+Printer*
+CPrinterSetupWizardSheet::LookUp(const char * inName)
+{
+	PrinterList::iterator it1 = m_printerList.begin();
+	PrinterList::iterator it2 = m_printerList.end();
+
+	while (it1 != it2)
+	{
+		Printer * printer = *it1++;
+
+		if (printer->name == inName)
+		{
+			return printer;
+		}
+	}
+
+	return NULL;
+}
+
+
+unsigned WINAPI
+CPrinterSetupWizardSheet::InstallPrinterThread( LPVOID inParam )
+{
+	check( inParam );
+		
+	Printer			*	printer = (Printer*) inParam;
+	CString				actualName;
+	CString				command;
+	DWORD				exitCode = 0;
+	DWORD				dwResult;
+	OSStatus			err;
+	STARTUPINFO			si;
+	PROCESS_INFORMATION pi;
+	BOOL				ok;
+
+	ZeroMemory( &si, sizeof(si) );
+	si.cb = sizeof(si);
+	ZeroMemory( &pi, sizeof(pi) );
+
+	//
+	// <rdar://problem/3764873> Escape '\', '@', '"' characters which seem to cause problems for printui
+	//
+
+	actualName = printer->actualName;
+
+	actualName.Replace(L"\\", L"\\\\");
+	actualName.Replace(L"@", L"\\@");
+	actualName.Replace(L"\"", L"\\\"");
+	
+	command.Format(L"rundll32.exe printui.dll,PrintUIEntry /if /b \"%s\" /f \"%s\" /r \"%s\" /m \"%s\"", (LPCTSTR) actualName, (LPCTSTR) printer->infFileName, (LPCTSTR) printer->portName, (LPCTSTR) printer->model);
+
+	ok = CreateProcess(NULL, command.GetBuffer(), NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
+	err = translate_errno( ok, errno_compat(), kUnknownErr );
+	require_noerr( err, exit );
+
+	dwResult = WaitForSingleObject( pi.hProcess, INFINITE );
+	translate_errno( dwResult == WAIT_OBJECT_0, errno_compat(), err = kUnknownErr );
+	require_noerr( err, exit );
+
+	ok = GetExitCodeProcess( pi.hProcess, &exitCode );
+	err = translate_errno( ok, errno_compat(), kUnknownErr );
+	require_noerr( err, exit );
+
+	//
+	// Close process and thread handles. 
+	//
+	CloseHandle( pi.hProcess );
+	CloseHandle( pi.hThread );
+
+exit:
+
+	//
+	// alert the main thread
+	//
+	printer->window->PostMessage( WM_PROCESS_EVENT, err, exitCode );
+
+	return 0;
+}
diff --git a/Clients/PrinterSetupWizard/PrinterSetupWizardSheet.h b/Clients/PrinterSetupWizard/PrinterSetupWizardSheet.h
new file mode 100644
index 0000000..e1077aa
--- /dev/null
+++ b/Clients/PrinterSetupWizard/PrinterSetupWizardSheet.h
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+    
+$Log: PrinterSetupWizardSheet.h,v $
+Revision 1.4  2004/07/13 21:24:23  rpantos
+Fix for <rdar://problem/3701120>.
+
+Revision 1.3  2004/06/28 00:51:47  shersche
+Move call to EnumPrinters out of browse callback into standalone function
+
+Revision 1.2  2004/06/24 20:12:07  shersche
+Clean up source code
+Submitted by: herscher
+
+Revision 1.1  2004/06/18 04:36:57  rpantos
+First checked in
+
+
+*/
+
+#pragma once
+
+
+#include "firstpage.h"
+#include "secondpage.h"
+#include "thirdpage.h"
+#include "fourthpage.h"
+#include "UtilTypes.h"
+#include "dns_sd.h"
+#include <stdexcept>
+#include <map>
+
+using namespace PrinterSetupWizard;
+
+// CPrinterSetupWizardSheet
+
+class CPrinterSetupWizardSheet : public CPropertySheet
+{
+	DECLARE_DYNAMIC(CPrinterSetupWizardSheet)
+
+public:
+
+	struct WizardException
+	{
+		CString	text;
+		CString	caption;
+	};
+
+public:
+
+	CPrinterSetupWizardSheet(UINT nIDCaption, CWnd* pParentWnd = NULL, UINT iSelectPage = 0);
+	virtual ~CPrinterSetupWizardSheet();
+	
+	int
+	InstallEventHandler(EventHandler * handler);
+
+	int
+	RemoveEventHandler(EventHandler * handler);
+
+	OSStatus
+	SetSelectedPrinter(Printer * printer);
+
+	Printer*
+	GetSelectedPrinter();
+
+	OSStatus
+	LoadPrinterDriver(const CString & filename);
+
+	HCURSOR
+	GetCursor();
+
+	//
+	// handles socket events for DNSService operations
+	//
+	virtual LONG
+	OnServiceEvent(WPARAM inWParam, LPARAM inLParam);
+
+	//
+	// handles end of process event
+	//
+	virtual LONG
+	OnProcessEvent(WPARAM inWParam, LPARAM inLParam);
+
+	virtual BOOL
+	OnCommand(WPARAM wParam, LPARAM lParam);
+
+	virtual BOOL
+	OnInitDialog();
+
+	virtual BOOL
+	OnSetCursor(CWnd * pWnd, UINT nHitTest, UINT message);
+
+	virtual void
+	OnContextMenu(CWnd * pWnd, CPoint pos);
+
+	afx_msg void
+	OnOK();
+
+protected:
+	DECLARE_MESSAGE_MAP()
+	CFirstPage		m_pgFirst;
+	CSecondPage		m_pgSecond;
+	CThirdPage		m_pgThird;
+	CFourthPage		m_pgFourth;
+
+	static void DNSSD_API
+	OnBrowse(
+		DNSServiceRef 			inRef,
+		DNSServiceFlags 		inFlags,
+		uint32_t 				inInterfaceIndex,
+		DNSServiceErrorType 	inErrorCode,
+		const char *			inName,	
+		const char *			inType,	
+		const char *			inDomain,	
+		void *					inContext );
+
+	static void DNSSD_API
+	OnResolve(
+		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 );
+
+	void Init(void);
+
+private:
+
+	OSStatus
+	LoadPrinterNames();
+
+	OSStatus
+	StartResolve(Printer * printer);
+
+	OSStatus
+	StopResolve(Printer * printer);
+
+	Printer*
+	LookUp(const char * inName);
+
+	OSStatus
+	InstallPrinter(Printer * printer);
+
+	static unsigned WINAPI
+	InstallPrinterThread( LPVOID inParam );
+
+
+	typedef std::list<Printer*>			PrinterList;
+	typedef std::list<EventHandler*>	EventHandlerList;
+	typedef std::list<DNSServiceRef>	ServiceRefList;
+	typedef std::map<CString,CString>	PrinterNameMap;
+
+	Printer	*	m_selectedPrinter;
+	
+	PrinterNameMap			m_printerNames;
+	PrinterList				m_printerList;
+	EventHandlerList		m_eventHandlerList;
+	ServiceRefList			m_serviceRefList;
+
+	bool					m_processFinished;
+
+	HCURSOR					m_active;
+	HCURSOR					m_arrow;
+	HCURSOR					m_wait;
+
+	DNSServiceRef			m_pdlBrowser;
+};
+
+
+inline Printer*
+CPrinterSetupWizardSheet::GetSelectedPrinter()
+{	
+	return m_selectedPrinter;
+}
+
+
+inline HCURSOR
+CPrinterSetupWizardSheet::GetCursor()
+{
+	return m_active;
+}
diff --git a/Clients/PrinterSetupWizard/ReadMe.txt b/Clients/PrinterSetupWizard/ReadMe.txt
new file mode 100644
index 0000000..9b5eb41
--- /dev/null
+++ b/Clients/PrinterSetupWizard/ReadMe.txt
@@ -0,0 +1,94 @@
+================================================================================
+    MICROSOFT FOUNDATION CLASS LIBRARY : Wiz97_3 Project Overview
+===============================================================================
+
+The application wizard has created this Wiz97_3 application for 
+you.  This application not only demonstrates the basics of using the Microsoft 
+Foundation Classes but is also a starting point for writing your application.
+
+This file contains a summary of what you will find in each of the files that
+make up your Wiz97_3 application.
+
+Wiz97_3.vcproj
+    This is the main project file for VC++ projects generated using an application wizard. 
+    It contains information about the version of Visual C++ that generated the file, and 
+    information about the platforms, configurations, and project features selected with the
+    application wizard.
+
+Wiz97_3.h
+    This is the main header file for the application.  It includes other
+    project specific headers (including Resource.h) and declares the
+    CWiz97_3App application class.
+
+Wiz97_3.cpp
+    This is the main application source file that contains the application
+    class CWiz97_3App.
+
+Wiz97_3.rc
+    This is a listing of all of the Microsoft Windows resources that the
+    program uses.  It includes the icons, bitmaps, and cursors that are stored
+    in the RES subdirectory.  This file can be directly edited in Microsoft
+    Visual C++. Your project resources are in 1033.
+
+res\Wiz97_3.ico
+    This is an icon file, which is used as the application's icon.  This
+    icon is included by the main resource file Wiz97_3.rc.
+
+res\Wiz97_3.rc2
+    This file contains resources that are not edited by Microsoft 
+    Visual C++. You should place all resources not editable by
+    the resource editor in this file.
+
+/////////////////////////////////////////////////////////////////////////////
+
+The application wizard creates one dialog class:
+Wiz97_3Dlg.h, Wiz97_3Dlg.cpp - the dialog
+    These files contain your CWiz97_3Dlg class.  This class defines
+    the behavior of your application's main dialog.  The dialog's template is
+    in Wiz97_3.rc, which can be edited in Microsoft Visual C++.
+/////////////////////////////////////////////////////////////////////////////
+
+Other Features:
+
+ActiveX Controls
+    The application includes support to use ActiveX controls.
+
+Printing and Print Preview support
+    The application wizard has generated code to handle the print, print setup, and print preview
+    commands by calling member functions in the CView class from the MFC library.
+/////////////////////////////////////////////////////////////////////////////
+
+Other standard files:
+
+StdAfx.h, StdAfx.cpp
+    These files are used to build a precompiled header (PCH) file
+    named Wiz97_3.pch and a precompiled types file named StdAfx.obj.
+
+Resource.h
+    This is the standard header file, which defines new resource IDs.
+    Microsoft Visual C++ reads and updates this file.
+
+Wiz97_3.manifest
+	Application manifest files are used by Windows XP to describe an applications 
+	dependency on specific versions of Side-by-Side assemblies. The loader uses this 
+	information to load the appropriate assembly from the assembly cache or private 
+	from the application. The Application manifest  maybe included for redistribution 
+	as an external .manifest file that is installed in the same folder as the application 
+	executable or it may be included in the executable in the form of a resource. 
+/////////////////////////////////////////////////////////////////////////////
+
+Other notes:
+
+The application wizard uses "TODO:" to indicate parts of the source code you
+should add to or customize.
+
+If your application uses MFC in a shared DLL, and your application is in a 
+language other than the operating system's current language, you will need 
+to copy the corresponding localized resources MFC70XXX.DLL from the Microsoft
+Visual C++ CD-ROM under the Win\System directory to your computer's system or 
+system32 directory, and rename it to be MFCLOC.DLL.  ("XXX" stands for the 
+language abbreviation.  For example, MFC70DEU.DLL contains resources 
+translated to German.)  If you don't do this, some of the UI elements of 
+your application will remain in the language of the operating system.
+
+/////////////////////////////////////////////////////////////////////////////
diff --git a/Clients/PrinterSetupWizard/SecondPage.cpp b/Clients/PrinterSetupWizard/SecondPage.cpp
new file mode 100644
index 0000000..abf4fa0
--- /dev/null
+++ b/Clients/PrinterSetupWizard/SecondPage.cpp
@@ -0,0 +1,347 @@
+/*
+ * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+    
+$Log: SecondPage.cpp,v $
+Revision 1.3  2004/09/13 21:26:15  shersche
+<rdar://problem/3796483> Use the moreComing flag to determine whether drawing should take place in OnAddPrinter and OnRemovePrinter callbacks
+Bug #: 3796483
+
+Revision 1.2  2004/06/26 03:19:57  shersche
+clean up warning messages
+
+Submitted by: herscher
+
+Revision 1.1  2004/06/18 04:36:57  rpantos
+First checked in
+
+
+*/
+
+#include "stdafx.h"
+#include "PrinterSetupWizardApp.h"
+#include "PrinterSetupWizardSheet.h"
+#include "SecondPage.h"
+#include "DebugServices.h"
+
+// local variable is initialize but not referenced
+#pragma warning(disable:4189)
+
+
+// CSecondPage dialog
+
+IMPLEMENT_DYNAMIC(CSecondPage, CPropertyPage)
+CSecondPage::CSecondPage()
+	: CPropertyPage(CSecondPage::IDD)
+{
+	m_psp.dwFlags &= ~(PSP_HASHELP);
+	m_psp.dwFlags |= PSP_DEFAULT|PSP_USEHEADERTITLE|PSP_USEHEADERSUBTITLE;
+
+	m_psp.pszHeaderTitle	= MAKEINTRESOURCE(IDS_BROWSE_TITLE);
+	m_psp.pszHeaderSubTitle	= MAKEINTRESOURCE(IDS_BROWSE_SUBTITLE);
+
+	m_resolver			=	NULL;
+	m_emptyListItem		=	NULL;
+	m_initialized		=	false;
+	m_waiting			=	false;
+}
+
+CSecondPage::~CSecondPage()
+{
+}
+
+
+void
+CSecondPage::InitBrowseList()
+{
+	CPrinterSetupWizardSheet	*	psheet;
+	CString							text;
+
+	psheet = reinterpret_cast<CPrinterSetupWizardSheet*>(GetParent());
+	require_quiet( psheet, exit );
+
+	//
+	// load the no rendezvous printers message until something shows up in the browse list
+	//
+	text.LoadString(IDS_NO_RENDEZVOUS_PRINTERS);
+
+	m_emptyListItem = m_browseList.InsertItem( text, 0, 0, NULL, TVI_FIRST );
+
+	//
+	// this will remove everything else in the list...we might be navigating
+	// back to this window, and the browse list might have changed since
+	// we last displayed it.
+	//
+	if ( m_emptyListItem )
+	{
+		HTREEITEM item = m_browseList.GetNextVisibleItem( m_emptyListItem );
+  
+		while ( item )
+		{
+			m_browseList.DeleteItem( item );
+			item = m_browseList.GetNextVisibleItem( m_emptyListItem );
+		}
+	}
+
+	//
+	// disable the next button until there's a printer to select
+	//
+	psheet->SetWizardButtons(PSWIZB_BACK);
+
+	//
+	// disable the window until there's a printer to select
+	//
+	m_browseList.EnableWindow( FALSE );
+
+exit:
+
+	return;
+}
+
+
+void CSecondPage::DoDataExchange(CDataExchange* pDX)
+{
+	CPropertyPage::DoDataExchange(pDX);
+	DDX_Control(pDX, IDC_BROWSE_LIST, m_browseList);
+}
+
+
+afx_msg BOOL
+CSecondPage::OnSetCursor(CWnd * pWnd, UINT nHitTest, UINT message)
+{
+	DEBUG_UNUSED(pWnd);
+	DEBUG_UNUSED(nHitTest);
+	DEBUG_UNUSED(message);
+
+	CPrinterSetupWizardSheet	*	psheet;
+
+	psheet = reinterpret_cast<CPrinterSetupWizardSheet*>(GetParent());
+	require_quiet( psheet, exit );
+
+	SetCursor(psheet->GetCursor());
+
+exit:
+
+	return TRUE;
+}
+
+
+BOOL
+CSecondPage::OnSetActive()
+{
+	CString							noPrinters;
+	CPrinterSetupWizardSheet	*	psheet;
+
+	psheet = reinterpret_cast<CPrinterSetupWizardSheet*>(GetParent());
+	require_quiet( psheet, exit );
+  
+	//
+	// initialize the browse list...this will remove everything currently
+	// in it, and add the no rendezvous printers item
+	//
+	InitBrowseList();
+
+	//
+	// this will invoke OnAddPrinter for all the printers that we have
+	// browsed
+	//
+	psheet->InstallEventHandler(this);
+
+exit:
+
+	return CPropertyPage::OnSetActive();
+}
+
+
+BOOL
+CSecondPage::OnKillActive()
+{
+	CPrinterSetupWizardSheet * psheet;
+
+	psheet = reinterpret_cast<CPrinterSetupWizardSheet*>(GetParent());
+	require_quiet( psheet, exit );
+
+	//
+	// we don't want our event handlers called when we don't have
+	// anywhere to put the data
+	//
+	psheet->RemoveEventHandler(this);
+
+exit:
+
+	return CPropertyPage::OnKillActive();
+}
+
+
+BEGIN_MESSAGE_MAP(CSecondPage, CPropertyPage)
+	ON_NOTIFY(TVN_SELCHANGED, IDC_BROWSE_LIST, OnTvnSelchangedBrowseList)
+	ON_WM_SETCURSOR()
+END_MESSAGE_MAP()
+
+
+// Printer::EventHandler implementation
+void
+CSecondPage::OnAddPrinter(
+						Printer	*	printer,
+						bool			moreComing)
+{
+	check( IsWindow( m_hWnd ) );
+
+	m_browseList.SetRedraw(FALSE);
+
+	printer->item = m_browseList.InsertItem(printer->displayName);
+
+	m_browseList.SetItemData( printer->item, (DWORD_PTR) printer );
+	
+	m_browseList.SortChildren(TVI_ROOT);
+
+	//
+	// if the searching item is still in the list
+	// get rid of it
+	//
+	// note that order is important here.  Insert the printer
+	// item before removing the placeholder so we always have
+	// an item in the list to avoid experiencing the bug
+	// in Microsoft's implementation of CTreeCtrl
+	//
+	if (m_emptyListItem != NULL)
+	{
+		m_browseList.DeleteItem(m_emptyListItem);
+		m_emptyListItem = NULL;
+		m_browseList.EnableWindow(TRUE);
+	}
+
+	if (!moreComing)
+	{
+		m_browseList.SetRedraw(TRUE);
+		m_browseList.Invalidate();
+	}
+}
+
+
+void
+CSecondPage::OnRemovePrinter(
+						Printer	*	printer,
+						bool			moreComing)
+{
+	check( IsWindow( m_hWnd ) );
+
+	m_browseList.SetRedraw(FALSE);
+
+	//
+	// check to make sure if we're the only item in the control...i.e.
+	// the list size is 1.
+	//
+	if (m_browseList.GetCount() > 1)
+	{
+		//
+		// if we're not the only thing in the list, then
+		// simply remove it from the list
+		//
+		m_browseList.DeleteItem( printer->item );
+	}
+	else
+	{
+		//
+		// if we're the only thing in the list, then redisplay
+		// it with the no rendezvous printers message
+		//
+		InitBrowseList();
+	}
+
+	if (!moreComing)
+	{
+		m_browseList.SetRedraw(TRUE);
+		m_browseList.Invalidate();
+	}
+}
+
+
+void
+CSecondPage::OnResolvePrinter(
+						Printer * printer)
+{
+	DEBUG_UNUSED(printer);
+
+	check( IsWindow( m_hWnd ) );
+
+	CPrinterSetupWizardSheet * psheet = reinterpret_cast<CPrinterSetupWizardSheet*>(GetParent());
+	require_quiet( psheet, exit );
+   
+	//
+	// setup the sheet to enable the next button if we've successfully
+	// resolved
+	//
+	psheet->SetWizardButtons( PSWIZB_BACK|PSWIZB_NEXT );
+
+exit:
+
+	return;
+}
+
+
+void CSecondPage::OnTvnSelchangedBrowseList(NMHDR *pNMHDR, LRESULT *pResult)
+{
+	LPNMTREEVIEW					pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);
+	CPrinterSetupWizardSheet	*	psheet;
+	int								err = 0;
+
+	HTREEITEM item = m_browseList.GetSelectedItem();
+	require_quiet( item, exit );
+
+	psheet = reinterpret_cast<CPrinterSetupWizardSheet*>(GetParent());
+	require_action( psheet, exit, err = kUnknownErr );	
+
+	Printer * printer;
+
+	printer = reinterpret_cast<Printer*>(m_browseList.GetItemData( item ) );
+	require_quiet( printer, exit );
+
+	//
+	// this call will trigger a resolve.  When the resolve is complete,
+	// our OnResolve will be called.
+	//
+	err = psheet->SetSelectedPrinter(printer);
+	require_noerr( err, exit );
+
+	//
+	// setup the sheet to disable the next button until we've successfully
+	// resolved this printer
+	//
+	psheet->SetWizardButtons( PSWIZB_BACK );
+
+exit:
+
+	if (err != 0)
+	{
+		CString text;
+		CString caption;
+
+		text.LoadString(IDS_ERROR_SELECTING_PRINTER_TEXT);
+		caption.LoadString(IDS_ERROR_SELECTING_PRINTER_CAPTION);
+
+		MessageBox(text, caption, MB_OK|MB_ICONEXCLAMATION);
+	}
+
+	*pResult = 0;
+}
diff --git a/Clients/PrinterSetupWizard/SecondPage.h b/Clients/PrinterSetupWizard/SecondPage.h
new file mode 100644
index 0000000..45c55c9
--- /dev/null
+++ b/Clients/PrinterSetupWizard/SecondPage.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+    
+$Log: SecondPage.h,v $
+Revision 1.2  2004/09/13 21:23:42  shersche
+<rdar://problem/3796483> Add moreComing argument to OnAddPrinter and OnRemovePrinter callbacks
+Bug #: 3796483
+
+Revision 1.1  2004/06/18 04:36:57  rpantos
+First checked in
+
+
+*/
+
+#pragma once
+
+#include "PrinterSetupWizardSheet.h"
+#include "CommonServices.h"
+#include "UtilTypes.h"
+#include "afxcmn.h"
+#include "dns_sd.h"
+#include "afxwin.h"
+#include <map>
+
+using namespace PrinterSetupWizard;
+
+// CSecondPage dialog
+
+class CSecondPage : public CPropertyPage, public EventHandler
+{
+	DECLARE_DYNAMIC(CSecondPage)
+
+public:
+	CSecondPage();
+	virtual ~CSecondPage();
+
+// Dialog Data
+	enum { IDD = IDD_SECOND_PAGE };
+
+	virtual void
+	OnAddPrinter(
+			Printer	*	printer,
+			bool			moreComing);
+
+	virtual void
+	OnRemovePrinter(
+			Printer	*	printer,
+			bool			moreComing);
+
+	virtual void
+	OnResolvePrinter(
+			Printer * printer);
+
+protected:
+
+	void		 InitBrowseList();
+	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
+	afx_msg BOOL OnSetCursor(CWnd * pWnd, UINT nHitTest, UINT message);
+	virtual BOOL OnSetActive();
+	virtual BOOL OnKillActive();
+
+	DECLARE_MESSAGE_MAP()
+
+public:
+
+	HTREEITEM		m_emptyListItem;
+	bool			m_selectOkay;
+	CTreeCtrl		m_browseList;
+	DNSServiceRef	m_resolver;
+	bool			m_initialized;
+	bool			m_waiting;
+	
+	afx_msg void OnTvnSelchangedBrowseList(NMHDR *pNMHDR, LRESULT *pResult);
+};
diff --git a/Clients/PrinterSetupWizard/ThirdPage.cpp b/Clients/PrinterSetupWizard/ThirdPage.cpp
new file mode 100644
index 0000000..6828f3c
--- /dev/null
+++ b/Clients/PrinterSetupWizard/ThirdPage.cpp
@@ -0,0 +1,1224 @@
+/*
+ * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+    
+$Log: ThirdPage.cpp,v $
+Revision 1.10  2004/10/11 22:55:34  shersche
+<rdar://problem/3827624> Use the IP port number when deriving the printer port name.
+Bug #: 3827624
+
+Revision 1.9  2004/06/27 23:08:00  shersche
+code cleanup, make sure EnumPrintDrivers returns non-zero value, ignore comments in inf files
+
+Revision 1.8  2004/06/27 08:06:45  shersche
+Parse [Strings] section of inf file
+
+Revision 1.7  2004/06/26 04:00:05  shersche
+fix warnings compiling in debug mode
+Submitted by: herscher
+
+Revision 1.6  2004/06/26 03:19:57  shersche
+clean up warning messages
+
+Submitted by: herscher
+
+Revision 1.5  2004/06/25 05:06:02  shersche
+Trim whitespace from key/value pairs when parsing inf files
+Submitted by: herscher
+
+Revision 1.4  2004/06/25 02:44:13  shersche
+Tweaked code to handle Xerox Phaser printer identification
+Submitted by: herscher
+
+Revision 1.3  2004/06/25 02:27:58  shersche
+Do a CListCtrl::FindItem() before calling CListCtrl::SetItemState().
+Submitted by: herscher
+
+Revision 1.2  2004/06/23 18:09:23  shersche
+Normalize tag names when parsing inf files.
+Submitted by: herscher
+
+Revision 1.1  2004/06/18 04:36:58  rpantos
+First checked in
+
+
+*/
+
+#include "stdafx.h"
+#include "PrinterSetupWizardApp.h"
+#include "PrinterSetupWizardSheet.h"
+#include "ThirdPage.h"
+#include "StdioFileEx.h"
+#include <dns_sd.h>
+#include <tcpxcv.h>
+#include <winspool.h>
+
+// local variable is initialize but not referenced
+#pragma warning(disable:4189)
+
+
+//
+// This is the printer description file that is shipped
+// with Windows
+//
+#define kNTPrintFile		L"inf\\ntprint.inf"
+
+//
+// These are pre-defined names for Generic manufacturer and model
+//
+#define kGenericManufacturer	L"Generic"
+#define kGenericModel			L"Generic / Text Only"
+
+//
+// states for parsing ntprint.inf
+//
+enum PrinterParsingState
+{
+	Looking,
+	ParsingManufacturers,
+	ParsingModels,
+	ParsingStrings
+};
+
+
+// CThirdPage dialog
+
+IMPLEMENT_DYNAMIC(CThirdPage, CPropertyPage)
+CThirdPage::CThirdPage()
+	: CPropertyPage(CThirdPage::IDD),
+		m_initialized(false)
+{
+	m_psp.dwFlags &= ~(PSP_HASHELP);
+	m_psp.dwFlags |= PSP_DEFAULT|PSP_USEHEADERTITLE|PSP_USEHEADERSUBTITLE;
+	
+	m_psp.pszHeaderTitle = MAKEINTRESOURCE(IDS_INSTALL_TITLE);
+	m_psp.pszHeaderSubTitle = MAKEINTRESOURCE(IDS_INSTALL_SUBTITLE);
+}
+
+
+CThirdPage::~CThirdPage()
+{
+	//
+	// clean up all the printer manufacturers
+	//
+	while (m_manufacturers.size())
+	{
+		Manufacturers::iterator iter = m_manufacturers.begin();
+
+		while (iter->second->models.size())
+		{
+			Models::iterator it = iter->second->models.begin();
+
+			Model * model = *it;
+
+			delete model;
+
+			iter->second->models.erase(it);
+		}
+
+		delete iter->second;
+
+		m_manufacturers.erase(iter);
+	}
+}
+
+
+// ----------------------------------------------------
+// SelectMatch
+//
+// SelectMatch will do all the UI work associated with
+// selected a manufacturer and model of printer.  It also
+// makes sure the printer object is update with the 
+// latest settings
+//
+// ----------------------------------------------------
+void
+CThirdPage::SelectMatch(Printer * printer, Manufacturer * manufacturer, Model * model)
+{
+	LVFINDINFO	info;
+	int			nIndex;
+
+	check( printer != NULL );
+	check( manufacturer != NULL );
+	check( model != NULL );
+
+	Manufacturers manufacturers;
+	manufacturers[manufacturer->name] = manufacturer;
+
+	PopulateUI( manufacturers );
+
+	//
+	// select the manufacturer
+	//
+	info.flags	= LVFI_STRING;
+	info.psz	= manufacturer->name;
+
+	nIndex = m_manufacturerListCtrl.FindItem(&info);
+	
+	if (nIndex != -1)
+	{
+		m_manufacturerListCtrl.SetItemState(nIndex, LVIS_SELECTED, LVIS_SELECTED);
+		m_manufacturerListCtrl.EnsureVisible(nIndex, FALSE);
+	}
+
+	//
+	// select the model
+	//
+	info.flags	= LVFI_STRING;
+	info.psz	= model->name;
+
+	nIndex = m_modelListCtrl.FindItem(&info);
+
+	if (nIndex != -1)
+	{
+		m_modelListCtrl.SetItemState(nIndex, LVIS_SELECTED, LVIS_SELECTED);
+		m_modelListCtrl.EnsureVisible(nIndex, FALSE);
+
+		m_modelListCtrl.SetFocus();
+	}
+
+	CopyPrinterSettings( printer, manufacturer, model );
+}
+
+
+// --------------------------------------------------------
+// CopyPrinterSettings
+//
+// This function makes sure that the printer object has the
+// latest settings from the manufacturer and model objects
+// --------------------------------------------------------
+
+void
+CThirdPage::CopyPrinterSettings( Printer * printer, Manufacturer * manufacturer, Model * model )
+{
+	printer->manufacturer		=	manufacturer->name;
+	printer->model				=	model->name;
+	printer->driverInstalled	=	model->driverInstalled;
+	printer->infFileName		=	model->infFileName;
+	printer->portName.Format(L"IP_%s.%d", static_cast<LPCTSTR>(printer->hostname), printer->portNumber);
+}
+
+
+// ------------------------------------------------------
+// LoadPrintDriverDefsFromFile
+//
+// This function does all the heavy lifting in parsing inf
+// files.  It is called to parse both ntprint.inf, and driver
+// files that might be shipped on a printer's installation
+// disk
+//
+// The inf file is not totally parsed.  I only want to determine
+// the manufacturer and models that are involved. I leave it
+// to printui.dll to actually copy the driver files to the
+// right places.
+//
+// I was aiming to parse as little as I could so as not to
+// duplicate the parsing code that is contained in Windows.  There
+// are no public APIs for parsing inf files.
+//
+// That part of the inf file that we're interested in has a fairly
+// easy format.  Tags are strings that are enclosed in brackets.
+// We are only interested in [MANUFACTURERS] and models.
+//
+// The only potentially opaque thing about this function is the 
+// checkForDuplicateModels flag.  The problem here is that ntprint.inf
+// doesn't contain duplicate models, and it has hundreds of models
+// listed.  You wouldn't check for duplicates there.  But oftentimes,
+// loading different windows print driver files contain multiple
+// entries for the same printer.  You don't want the UI to display
+// the same printer multiple times, so in that case, you would ask
+// this function to check for multiple models.
+
+OSStatus
+CThirdPage::LoadPrintDriverDefsFromFile(Manufacturers & manufacturers, const CString & filename, bool checkForDuplicateModels )
+{
+	PrinterParsingState		state		= Looking;
+	Manufacturers::iterator iter		= manufacturers.end();
+	CStdioFileEx			file;
+	CFileException			feError;
+	CString					s;
+	OSStatus				err;
+	BOOL					ok;
+
+	typedef std::map<CString, CString> StringMap;
+
+	StringMap				strings;
+ 
+	ok = file.Open( filename,  CFile::modeRead|CFile::typeText, &feError);
+	err = translate_errno( ok, errno_compat(), kUnknownErr );
+	require_noerr( err, exit );
+
+	check ( state == Looking );
+	check ( iter == manufacturers.end() );
+
+	//
+	// first, parse the file looking for string sections
+	//
+	while (file.ReadString(s))
+	{
+		//
+		// check for comment
+		//
+		if (s.Find(';') == 0)
+		{
+			continue;
+		}
+
+		//
+		// check for tag
+		//
+		else if (s.Find('[') == 0)
+		{
+			//
+			// handle any capitalization issues here
+			//
+			CString tag = s;
+
+			tag.MakeLower();
+
+			if (tag == L"[strings]")
+			{
+				state = ParsingStrings;
+			}
+			else
+			{
+				state = Looking;
+			}
+		}
+		else
+		{
+			switch (state)
+			{
+				case ParsingStrings:
+				{
+					int	curPos = 0;
+
+					if (s.GetLength() > 0)
+					{
+						CString key = s.Tokenize(L"=",curPos);
+						CString val = s.Tokenize(L"=",curPos);
+
+						//
+						// get rid of all delimiters
+						//
+						val.Remove('"');
+	
+						//
+						// and store it
+						//
+						strings[key] = val;
+					}
+				}
+				break;
+			}
+		}
+	}
+
+	file.Close();
+
+	ok = file.Open( filename,  CFile::modeRead|CFile::typeText, &feError);
+	err = translate_errno( ok, errno_compat(), kUnknownErr );
+	require_noerr( err, exit );
+
+	state = Looking;
+
+	check ( iter == manufacturers.end() );
+
+	while (file.ReadString(s))
+	{
+		//
+		// check for comment
+		//
+		if (s.Find(';') == 0)
+		{
+			continue;
+		}
+
+		//
+		// check for tag
+		//
+		else if (s.Find('[') == 0)
+		{
+			//
+			// handle any capitalization issues here
+			//
+			CString tag = s;
+
+			tag.MakeLower();
+
+			if (tag == L"[manufacturer]")
+			{
+				state = ParsingManufacturers;
+			}
+			else
+			{
+				// remove the leading and trailing delimiters
+				//
+				s.Remove('[');
+				s.Remove(']');
+
+				// check to see if this is a printer entry
+				//
+				iter = manufacturers.find(s);
+
+				if (iter != manufacturers.end())
+				{
+					state = ParsingModels;
+				}
+				else
+				{
+					state = Looking;
+				}
+			}
+		}
+		//
+		// only look at this if the line isn't empty, or
+		// if it isn't a comment
+		//
+		else if ((s.GetLength() > 0) && (s.Find(';') != 0))
+		{
+			switch (state)
+			{
+				//
+				// if we're parsing manufacturers, then we will parse
+				// an entry of the form key=val, where key is a delimited
+				// string specifying a manufacturer name, and val is
+				// a tag that is used later in the file.  the key is 
+				// delimited by either '"' (quotes) or '%' (percent sign).
+				//
+				// the tag is used further down the file when models are
+				// declared.  this allows multiple manufacturers to exist
+				// in a single inf file.
+				//
+				case ParsingManufacturers:
+				{
+					Manufacturer	*	manufacturer;
+					int					curPos = 0;
+
+					CString key = s.Tokenize(L"=",curPos);
+					CString val = s.Tokenize(L"=",curPos);
+
+					try
+					{
+						manufacturer = new Manufacturer;
+					}
+					catch (...)
+					{
+						manufacturer = NULL;
+					}
+
+					require_action( manufacturer, exit, err = kNoMemoryErr );
+
+					//
+					// if it's a variable, look it up
+					//
+					if (key.Find('%') == 0)
+					{
+						StringMap::iterator it;
+
+						key.Remove('%');
+
+						it = strings.find(key);
+
+						if (it != strings.end())
+						{
+							key = it->second;
+						}
+					}
+					else
+					{
+						key.Remove('"');
+					}
+
+					val.TrimLeft();
+					val.TrimRight();
+
+					//
+					// why is there no consistency in inf files?
+					//
+					if (val.GetLength() == 0)
+					{
+						val = key;
+					}
+
+					//
+					// fix the manufacturer name if necessary
+					//
+					curPos	=	0;
+					val		=	val.Tokenize(L",", curPos);
+
+					manufacturer->name = NormalizeManufacturerName( key );
+					manufacturer->tag  = val;
+
+					manufacturers[val] = manufacturer;
+				}
+				break;
+
+				case ParsingModels:
+				{
+					check( iter != manufacturers.end() );
+
+					Model	*	model;
+					int			curPos = 0;
+
+					CString name		= s.Tokenize(L"=",curPos);
+					CString description = s.Tokenize(L"=",curPos);
+					
+					name.Remove('"');
+					name.Trim();
+					description.Trim();
+					
+					//
+					// If true, see if we've seen this guy before
+					//
+					if (checkForDuplicateModels == true)
+					{
+						if ( MatchModel( iter->second, name ) != NULL )
+						{
+							continue;
+						}
+					}
+
+					try
+					{
+						model = new Model;
+					}
+					catch (...)
+					{
+						model = NULL;
+					}
+
+					require_action( model, exit, err = kNoMemoryErr );
+
+					model->infFileName		=	filename;
+					model->name				=	name;
+					model->driverInstalled	=	false;
+
+					iter->second->models.push_back(model);
+				}
+				break;
+
+				default:
+				{
+					// pay no attention if we are in any other state
+				}
+				break;
+			}
+		}
+	}
+
+exit:
+
+	file.Close();
+
+	return (err);
+}
+
+
+// -------------------------------------------------------
+// LoadPrintDriverDefs
+//
+// This function is responsible for loading the print driver
+// definitions of all print drivers that have been installed
+// on this machine.
+// -------------------------------------------------------
+OSStatus
+CThirdPage::LoadPrintDriverDefs( Manufacturers & manufacturers )
+{
+	BYTE	*	buffer			=	NULL;
+	DWORD		bytesReceived	=	0;
+	DWORD		numPrinters		=	0;
+	OSStatus	err				=	0;
+	BOOL		ok;
+
+	//
+	// like a lot of win32 calls, we call this first to get the
+	// size of the buffer we need.
+	//
+	EnumPrinterDrivers(NULL, L"all", 6, NULL, 0, &bytesReceived, &numPrinters);
+
+	if (bytesReceived > 0)
+	{
+		try
+		{
+			buffer = new BYTE[bytesReceived];
+		}
+		catch (...)
+		{
+			buffer = NULL;
+		}
+	
+		require_action( buffer, exit, err = kNoMemoryErr );
+		
+		//
+		// this call gets the real info
+		//
+		ok = EnumPrinterDrivers(NULL, L"all", 6, buffer, bytesReceived, &bytesReceived, &numPrinters);
+		err = translate_errno( ok, errno_compat(), kUnknownErr );
+		require_noerr( err, exit );
+	
+		DRIVER_INFO_6 * info = (DRIVER_INFO_6*) buffer;
+	
+		for (DWORD i = 0; i < numPrinters; i++)
+		{
+			Manufacturer	*	manufacturer;
+			Model			*	model;
+			CString				name;
+	
+			//
+			// skip over anything that doesn't have a manufacturer field.  This
+			// fixes a bug that I noticed that occurred after I installed 
+			// ProComm.  This program add a print driver with no manufacturer
+			// that screwed up this wizard.
+			//
+			if (info[i].pszMfgName == NULL)
+			{
+				continue;
+			}
+	
+			//
+			// look for manufacturer
+			//
+			Manufacturers::iterator iter;
+	
+			//
+			// save the name
+			//
+			name = NormalizeManufacturerName( info[i].pszMfgName );
+	
+			iter = manufacturers.find(name);
+	
+			if (iter != manufacturers.end())
+			{
+				manufacturer = iter->second;
+			}
+			else
+			{
+				try
+				{
+					manufacturer = new Manufacturer;
+				}
+				catch (...)
+				{
+					manufacturer = NULL;
+				}
+	
+				require_action( manufacturer, exit, err = kNoMemoryErr );
+	
+				manufacturer->name	=	name;
+	
+				manufacturers[name]	=	manufacturer;
+			}
+	
+			//
+			// now look to see if we have already seen this guy.  this could
+			// happen if we have already installed printers that are described
+			// in ntprint.inf.  the extant drivers will show up in EnumPrinterDrivers
+			// but we have already loaded their info
+			//
+			//
+			if ( MatchModel( manufacturer, ConvertToModelName( info[i].pName ) ) == NULL )
+			{
+				try
+				{
+					model = new Model;
+				}
+				catch (...)
+				{
+					model = NULL;
+				}
+	
+				require_action( model, exit, err = kNoMemoryErr );
+	
+				model->name				=	info[i].pName;
+				model->driverInstalled	=	true;
+	
+				manufacturer->models.push_back(model);
+			}
+		}
+	}
+
+exit:
+
+	if (buffer != NULL)
+	{
+		delete [] buffer;
+	}
+
+	return err;
+}
+
+
+// ------------------------------------------------------
+// ConvertToManufacturerName
+//
+// This function is responsible for tweaking the 
+// name so that subsequent string operations won't fail because
+// of capitalizations/different names for the same manufacturer
+// (i.e.  Hewlett-Packard/HP/Hewlett Packard)
+//
+CString
+CThirdPage::ConvertToManufacturerName( const CString & name )
+{
+	//
+	// first we're going to convert all the characters to lower
+	// case
+	//
+	CString lower = name;
+	lower.MakeLower();
+
+	//
+	// now we're going to check to see if the string says "hewlett-packard",
+	// because sometimes they refer to themselves as "hewlett-packard", and
+	// sometimes they refer to themselves as "hp".
+	//
+	if ( lower == L"hewlett-packard")
+	{
+		lower = "hp";
+	}
+
+	//
+	// tweak for Xerox Phaser, which doesn't announce itself
+	// as a xerox
+	//
+	else if ( lower.Find( L"phaser", 0 ) != -1 )
+	{
+		lower = "xerox";
+	}
+
+	return lower;
+}
+
+
+// ------------------------------------------------------
+// ConvertToModelName
+//
+// This function is responsible for ensuring that subsequent
+// string operations don't fail because of differing capitalization
+// schemes and the like
+// ------------------------------------------------------
+
+CString
+CThirdPage::ConvertToModelName( const CString & name )
+{
+	//
+	// convert it to lowercase
+	//
+	CString lower = name;
+	lower.MakeLower();
+
+	return lower;
+}
+
+
+// ------------------------------------------------------
+// NormalizeManufacturerName
+//
+// This function is responsible for tweaking the manufacturer
+// name so that there are no aliases for vendors
+//
+CString
+CThirdPage::NormalizeManufacturerName( const CString & name )
+{
+	CString normalized = name;
+
+	//
+	// now we're going to check to see if the string says "hewlett-packard",
+	// because sometimes they refer to themselves as "hewlett-packard", and
+	// sometimes they refer to themselves as "hp".
+	//
+	if ( normalized == L"Hewlett-Packard")
+	{
+		normalized = "HP";
+	}
+
+	return normalized;
+}
+
+
+// -------------------------------------------------------
+// MatchPrinter
+//
+// This function is responsible for matching a printer
+// to a list of manufacturers and models.  It calls
+// MatchManufacturer and MatchModel in turn.
+//
+
+OSStatus CThirdPage::MatchPrinter(Manufacturers & manufacturers, Printer * printer)
+{
+	CString					normalizedProductName;
+	Manufacturer		*	manufacturer	=	NULL;
+	Model				*	model			=	NULL;
+	bool					found			=	false;
+	CString					text;
+	OSStatus				err				=	kNoErr;
+
+	//
+	// first look to see if we have a usb_MFG descriptor
+	//
+	if (printer->usb_MFG.GetLength() > 0)
+	{
+		manufacturer = MatchManufacturer( manufacturers, ConvertToManufacturerName ( printer->usb_MFG ) );
+	}
+
+	if ( manufacturer == NULL )
+	{
+		printer->product.Remove('(');
+		printer->product.Remove(')');
+
+		manufacturer = MatchManufacturer( manufacturers, ConvertToManufacturerName ( printer->product ) );
+	}
+	
+	//
+	// if we found the manufacturer, then start looking for the model
+	//
+	if ( manufacturer != NULL )
+	{
+		if (printer->usb_MDL.GetLength() > 0)
+		{
+			model = MatchModel ( manufacturer, ConvertToModelName ( printer->usb_MDL ) );
+		}
+
+		if ( model == NULL )
+		{
+			printer->product.Remove('(');
+			printer->product.Remove(')');
+
+			model = MatchModel ( manufacturer, ConvertToModelName ( printer->product ) );
+		}
+
+		if ( model != NULL )
+		{
+			SelectMatch(printer, manufacturer, model);
+			found = true;
+		}
+	}
+
+	//
+	// display a message to the user based on whether we could match
+	// this printer
+	//
+	if (found)
+	{
+		text.LoadString(IDS_PRINTER_MATCH_GOOD);
+	}
+	else
+	{
+		text.LoadString(IDS_PRINTER_MATCH_BAD);
+
+		//
+		// if there was any crud in this list from before, get rid of it now
+		//
+		m_modelListCtrl.DeleteAllItems();
+		
+		//
+		// select the manufacturer if we found one
+		//
+		if (manufacturer != NULL)
+		{
+			LVFINDINFO	info;
+			int			nIndex;
+
+			//
+			// select the manufacturer
+			//
+			info.flags	= LVFI_STRING;
+			info.psz	= manufacturer->name;
+
+			nIndex = m_manufacturerListCtrl.FindItem(&info);
+	
+			if (nIndex != -1)
+			{
+				m_manufacturerListCtrl.SetItemState(nIndex, LVIS_SELECTED, LVIS_SELECTED);
+				m_manufacturerListCtrl.EnsureVisible(nIndex, FALSE);
+			}
+		}
+	}
+
+	m_printerSelectionText.SetWindowText(text);
+
+	return err;
+}
+
+
+// ------------------------------------------------------
+// MatchManufacturer
+//
+// This function is responsible for finding a manufacturer
+// object from a string name.  It does a CString::Find, which
+// is like strstr, so it doesn't have to do an exact match
+//
+// If it can't find a match, NULL is returned
+// ------------------------------------------------------
+
+Manufacturer*
+CThirdPage::MatchManufacturer( Manufacturers & manufacturers, const CString & name)
+{
+	Manufacturers::iterator iter;
+
+	for (iter = manufacturers.begin(); iter != manufacturers.end(); iter++)
+	{
+		//
+		// we're going to convert all the manufacturer names to lower case,
+		// so we match the name passed in.
+		//
+		CString lower = iter->second->name;
+		lower.MakeLower();
+
+		//
+		// now try and find the lowered string in the name passed in.
+		// 
+		if (name.Find(lower) == 0)
+		{
+			return iter->second;
+		}
+	}
+
+	return NULL;
+}
+
+
+// -------------------------------------------------------
+// MatchModel
+//
+// This function is responsible for matching a model from
+// a name.  It does a CString::Find(), which works like strstr,
+// so it doesn't rely on doing an exact string match.
+//
+
+Model*
+CThirdPage::MatchModel(Manufacturer * manufacturer, const CString & name)
+{
+	Models::iterator iter;
+
+	iter = manufacturer->models.begin();
+
+	for (iter = manufacturer->models.begin(); iter != manufacturer->models.end(); iter++)
+	{
+		Model * model = *iter;
+
+		//
+		// convert the model name to lower case
+		//
+		CString lowered = model->name;
+		lowered.MakeLower();
+
+		if (lowered.Find( name ) != -1)
+		{
+			return model;
+		}
+	}
+
+	return NULL;
+}
+
+
+
+// -----------------------------------------------------------
+// OnInitPage
+//
+// This function is responsible for doing initialization that
+// only occurs once during a run of the wizard
+//
+
+OSStatus CThirdPage::OnInitPage()
+{
+	static const int		bufferSize	= 32768;
+	TCHAR					windowsDirectory[bufferSize];
+	CString					header;
+	CString					ntPrint;
+	OSStatus				err;
+	BOOL					ok;
+	
+
+	//
+	// The CTreeCtrl widget automatically sends a selection changed
+	// message which initially we want to ignore, because the user
+	// hasn't selected anything
+	//
+	// this flag gets reset in the message handler.  Every subsequent
+	// message gets handled.
+	//
+
+	//
+	// we have to make sure that we only do this once.  Typically, 
+	// we would do this in something like OnInitDialog, but we don't
+	// have this in Wizards, because the window is a PropertySheet.
+	// We're considered fully initialized when we receive the first
+	// selection notice
+	//
+	header.LoadString(IDS_MANUFACTURER_HEADING);
+	m_manufacturerListCtrl.InsertColumn(0, header, LVCFMT_LEFT, 138);
+	m_manufacturerSelected = NULL;
+
+	header.LoadString(IDS_MODEL_HEADING);
+	m_modelListCtrl.InsertColumn(0, header, LVCFMT_LEFT, 247);
+	m_modelSelected = NULL;
+
+	//
+	// load printers from ntprint.inf
+	//
+	ok = GetWindowsDirectory( windowsDirectory, bufferSize );
+	err = translate_errno( ok, errno_compat(), kUnknownErr );
+	require_noerr( err, exit );
+ 
+	ntPrint.Format(L"%s\\%s", windowsDirectory, kNTPrintFile);
+	err = LoadPrintDriverDefsFromFile( m_manufacturers, ntPrint, false );
+	require_noerr(err, exit);
+
+	//
+	// load printer drivers that have been installed on this machine
+	//
+	err = LoadPrintDriverDefs( m_manufacturers );
+	require_noerr(err, exit);
+
+exit:
+
+	return (err);
+}
+
+
+void CThirdPage::DoDataExchange(CDataExchange* pDX)
+{
+	CPropertyPage::DoDataExchange(pDX);
+	DDX_Control(pDX, IDC_PRINTER_MANUFACTURER, m_manufacturerListCtrl);
+	DDX_Control(pDX, IDC_PRINTER_MODEL, m_modelListCtrl);
+	DDX_Control(pDX, IDC_PRINTER_NAME, m_printerName);
+	DDX_Control(pDX, IDC_DEFAULT_PRINTER, m_defaultPrinterCtrl);
+	DDX_Control(pDX, IDC_PRINTER_SELECTION_TEXT, m_printerSelectionText);
+}
+
+
+// ----------------------------------------------------------
+// OnSetActive
+//
+// This function is called by MFC after the window has been
+// activated.
+//
+
+BOOL
+CThirdPage::OnSetActive()
+{
+	CPrinterSetupWizardSheet	*	psheet;
+	Printer						*	printer;
+
+	psheet = reinterpret_cast<CPrinterSetupWizardSheet*>(GetParent());
+	require_quiet( psheet, exit );
+   
+	if ((m_manufacturerListCtrl.GetFirstSelectedItemPosition() != NULL) &&
+	    (m_modelListCtrl.GetFirstSelectedItemPosition() != NULL))
+	{
+		psheet->SetWizardButtons( PSWIZB_BACK|PSWIZB_NEXT );
+	}
+	else
+	{
+		psheet->SetWizardButtons( PSWIZB_BACK );
+	}
+
+	printer = psheet->GetSelectedPrinter();
+	require_quiet( printer, exit );
+
+	//
+	// call OnInitPage once
+	//
+	if (!m_initialized)
+	{
+		OnInitPage();
+		m_initialized = true;
+	}
+
+	//
+	// update the UI with the printer name
+	//
+	m_printerName.SetWindowText(printer->displayName);
+
+	//
+	// populate the list controls with the manufacturers and models
+	// from ntprint.inf
+	//
+	PopulateUI( m_manufacturers );
+
+	//
+	// and try and match the printer
+	//
+	MatchPrinter( m_manufacturers, printer );
+
+exit:
+
+	return CPropertyPage::OnSetActive();
+}
+
+
+// -------------------------------------------------------
+// PopulateUI
+//
+// This function is called to populate the list of manufacturers
+//
+OSStatus
+CThirdPage::PopulateUI(Manufacturers & manufacturers)
+{
+	Manufacturers::iterator iter;
+	
+	m_manufacturerListCtrl.DeleteAllItems();
+
+	for (iter = manufacturers.begin(); iter != manufacturers.end(); iter++)
+	{
+		int nIndex;
+
+		Manufacturer * manufacturer = iter->second;
+
+		nIndex = m_manufacturerListCtrl.InsertItem(0, manufacturer->name);
+
+		m_manufacturerListCtrl.SetItemData(nIndex, (DWORD_PTR) manufacturer);
+	}
+
+	return 0;
+}
+
+
+BEGIN_MESSAGE_MAP(CThirdPage, CPropertyPage)
+	ON_NOTIFY(LVN_ITEMCHANGED, IDC_PRINTER_MANUFACTURER, OnLvnItemchangedManufacturer)
+	ON_NOTIFY(LVN_ITEMCHANGED, IDC_PRINTER_MODEL, OnLvnItemchangedPrinterModel)
+	ON_BN_CLICKED(IDC_DEFAULT_PRINTER, OnBnClickedDefaultPrinter)
+	ON_BN_CLICKED(IDC_HAVE_DISK, OnBnClickedHaveDisk)
+END_MESSAGE_MAP()
+
+
+// CThirdPage message handlers
+void CThirdPage::OnLvnItemchangedManufacturer(NMHDR *pNMHDR, LRESULT *pResult)
+{
+	LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
+
+	POSITION p = m_manufacturerListCtrl.GetFirstSelectedItemPosition();
+	int nSelected = m_manufacturerListCtrl.GetNextSelectedItem(p);
+
+	if (nSelected != -1)
+	{
+		m_manufacturerSelected = (Manufacturer*) m_manufacturerListCtrl.GetItemData(nSelected);
+
+		m_modelListCtrl.SetRedraw(FALSE);
+		
+		m_modelListCtrl.DeleteAllItems();
+		m_modelSelected = NULL;
+
+		Models::iterator iter;
+
+		for (iter = m_manufacturerSelected->models.begin(); iter != m_manufacturerSelected->models.end(); iter++)
+		{
+			Model * model = *iter;
+
+			int nItem = m_modelListCtrl.InsertItem(0, model->name);
+
+			m_modelListCtrl.SetItemData(nItem, (DWORD_PTR) model);
+		}
+
+		m_modelListCtrl.SetRedraw(TRUE);
+	}
+
+	*pResult = 0;
+}
+
+void CThirdPage::OnLvnItemchangedPrinterModel(NMHDR *pNMHDR, LRESULT *pResult)
+{
+	LPNMLISTVIEW					pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
+	
+	CPrinterSetupWizardSheet	*	psheet;
+	Printer						*	printer;
+
+	psheet = reinterpret_cast<CPrinterSetupWizardSheet*>(GetParent());
+	require_quiet( psheet, exit );
+
+	printer = psheet->GetSelectedPrinter();
+	require_quiet( printer, exit );
+
+	check ( m_manufacturerSelected );
+
+	POSITION p = m_modelListCtrl.GetFirstSelectedItemPosition();
+	int nSelected = m_modelListCtrl.GetNextSelectedItem(p);
+
+	if (nSelected != -1)
+	{
+		m_modelSelected = (Model*) m_modelListCtrl.GetItemData(nSelected);
+
+		CopyPrinterSettings( printer, m_manufacturerSelected, m_modelSelected );
+
+		psheet->SetWizardButtons(PSWIZB_BACK|PSWIZB_NEXT);
+	}
+	else
+	{
+		psheet->SetWizardButtons(PSWIZB_BACK);
+	}
+
+exit:
+
+	*pResult = 0;
+}
+
+
+void CThirdPage::OnBnClickedDefaultPrinter()
+{
+	CPrinterSetupWizardSheet	*	psheet;
+	Printer						*	printer;
+
+	psheet = reinterpret_cast<CPrinterSetupWizardSheet*>(GetParent());
+	require_quiet( psheet, exit );
+
+	printer = psheet->GetSelectedPrinter();
+	require_quiet( printer, exit );
+
+	printer->deflt = m_defaultPrinterCtrl.GetState() ? true : false;
+
+exit:
+
+	return;
+}
+
+void CThirdPage::OnBnClickedHaveDisk()
+{
+	CPrinterSetupWizardSheet	*	psheet;
+	Printer						*	printer;
+
+	CFileDialog dlg(TRUE, NULL, NULL, OFN_HIDEREADONLY|OFN_FILEMUSTEXIST, L"Setup Information (*.inf)|*.inf||", this);
+
+	psheet = reinterpret_cast<CPrinterSetupWizardSheet*>(GetParent());
+	require_quiet( psheet, exit );
+
+	printer = psheet->GetSelectedPrinter();
+	require_quiet( printer, exit );
+	
+	if ( dlg.DoModal() == IDOK )
+	{
+		Manufacturers	manufacturers;
+		CString			filename = dlg.GetPathName();
+
+		LoadPrintDriverDefsFromFile( manufacturers, filename, true );
+   
+		PopulateUI( manufacturers );
+
+		MatchPrinter( manufacturers, printer );
+	}
+
+exit:
+
+	return;
+}
diff --git a/Clients/PrinterSetupWizard/ThirdPage.h b/Clients/PrinterSetupWizard/ThirdPage.h
new file mode 100644
index 0000000..dfdb69d
--- /dev/null
+++ b/Clients/PrinterSetupWizard/ThirdPage.h
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+    
+$Log: ThirdPage.h,v $
+Revision 1.1  2004/06/18 04:36:58  rpantos
+First checked in
+
+
+*/
+
+#pragma once
+#include "afxcmn.h"
+#include "UtilTypes.h"
+#include <CommonServices.h>
+#include <DebugServices.h>
+#include <dns_sd.h>
+#include <map>
+#include "afxwin.h"
+
+
+// CThirdPage dialog
+
+class CThirdPage : public CPropertyPage
+{
+	DECLARE_DYNAMIC(CThirdPage)
+
+public:
+	CThirdPage();
+	virtual ~CThirdPage();
+
+// Dialog Data
+	enum { IDD = IDD_THIRD_PAGE };
+
+protected:
+	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
+	virtual BOOL OnSetActive();
+
+	DECLARE_MESSAGE_MAP()
+
+private:
+
+	typedef std::map<CString, Manufacturer*> Manufacturers;
+
+	//
+	// LoadPrintDriverDefsFromFile
+	//
+	// Parses INF file and populates manufacturers
+	//
+	OSStatus LoadPrintDriverDefsFromFile(Manufacturers & manufacturers, const CString & filename, bool checkForDuplicateModels );
+	
+	//
+	// LoadPrintDriverDefs
+	//
+	// Loads extant print driver definitions
+	//
+	OSStatus LoadPrintDriverDefs(Manufacturers & manufacturers);
+
+	//
+	// PopulateUI
+	//
+	// Load print driver defs into UI for browsing/selection
+	//
+	OSStatus PopulateUI(Manufacturers & manufacturers);
+
+	//
+	// MatchPrinter
+	//
+	// Tries to match printer based on manufacturer and model
+	//
+	OSStatus MatchPrinter(Manufacturers & manufacturers, Printer * printer);
+
+	//
+	// OnInitPage
+	//
+	// Called first time page is activated.
+	OSStatus OnInitPage();
+
+	//
+	// these functions will tweak the names so that everything is
+	// consistent
+	//
+	CString				ConvertToManufacturerName( const CString & name );
+	CString				ConvertToModelName( const CString & name );
+	CString				NormalizeManufacturerName( const CString & name );
+
+	Manufacturer	*	MatchManufacturer( Manufacturers & manufacturer, const CString & name );
+	Model			*	MatchModel( Manufacturer * manufacturer, const CString & name );
+	void				SelectMatch(Printer * printer, Manufacturer * manufacturer, Model * model);
+	void				CopyPrinterSettings(Printer * printer, Manufacturer * manufacturer, Model * model);
+
+	Manufacturers		m_manufacturers;
+	
+	CListCtrl			m_manufacturerListCtrl;
+	Manufacturer	*	m_manufacturerSelected;
+	
+	CListCtrl			m_modelListCtrl;
+	Model			*	m_modelSelected;
+
+	bool				m_initialized;
+
+public:
+
+	afx_msg void OnLvnItemchangedManufacturer(NMHDR *pNMHDR, LRESULT *pResult);
+	CStatic m_printerName;
+	afx_msg void OnLvnItemchangedPrinterModel(NMHDR *pNMHDR, LRESULT *pResult);
+	afx_msg void OnBnClickedDefaultPrinter();
+private:
+	CButton m_defaultPrinterCtrl;
+public:
+	CStatic m_printerSelectionText;
+	afx_msg void OnBnClickedHaveDisk();
+};
diff --git a/Clients/PrinterSetupWizard/UtilTypes.h b/Clients/PrinterSetupWizard/UtilTypes.h
new file mode 100644
index 0000000..f702ebc
--- /dev/null
+++ b/Clients/PrinterSetupWizard/UtilTypes.h
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+    
+$Log: UtilTypes.h,v $
+Revision 1.4  2004/09/13 21:22:44  shersche
+<rdar://problem/3796483> Add moreComing argument to OnAddPrinter and OnRemovePrinter callbacks
+Bug #: 3796483
+
+Revision 1.3  2004/06/26 23:27:12  shersche
+support for installing multiple printers of the same name
+
+Revision 1.2  2004/06/25 02:25:59  shersche
+Remove item field from manufacturer and model structures
+Submitted by: herscher
+
+Revision 1.1  2004/06/18 04:36:58  rpantos
+First checked in
+
+
+*/
+
+#pragma once
+
+#include <dns_sd.h>
+#include <list>
+
+class CPrinterSetupWizardSheet;
+
+namespace PrinterSetupWizard
+{
+	struct Printer;
+	struct Manufacturer;
+	struct Model;
+	
+	typedef std::list<CString>	TextRecord;
+	typedef std::list<Model*>	Models;
+
+	struct Printer
+	{
+		DNSServiceRef					serviceRef;
+		CPrinterSetupWizardSheet	*	window;
+		HTREEITEM						item;
+		DWORD							refs;
+
+		//
+		// these are from the browse reply
+		//
+		uint32_t						ifi;
+		std::string						name;
+		CString							displayName;
+		CString							actualName;
+		std::string						type;
+		std::string						domain;
+
+		//
+		// these are from the resolve
+		//
+		CString							hostname;
+		unsigned short					portNumber;
+		CString							usb_MFG;
+		CString							usb_MDL;
+		CString							description;
+		CString							product;
+
+		//
+		// these are derived from the printer matching code
+		//
+		// if driverInstalled is false, then infFileName should
+		// have an absolute path to the printers inf file.  this
+		// is used to install the printer from printui.dll
+		//
+		// if driverInstalled is true, then model is the name
+		// of the driver to use in AddPrinter
+		// 
+		bool							driverInstalled;
+		CString							infFileName;
+		CString							manufacturer;
+		CString							model;
+		CString							portName;
+		bool							deflt;
+
+		//
+		// state
+		//
+		bool							installed;
+	};
+
+
+	struct Manufacturer
+	{
+		CString		name;
+		CString		tag;
+		Models		models;
+	};
+
+
+	struct Model
+	{
+		bool		driverInstalled;
+		CString		infFileName;
+		CString		name;
+	};
+
+
+	class EventHandler
+	{
+	public:
+
+		virtual void
+		OnAddPrinter(
+				Printer	*	printer,
+				bool			moreComing) = 0;
+
+		virtual void
+		OnRemovePrinter(
+				Printer	*	printer,
+				bool			moreComing) = 0;
+
+		virtual void
+		OnResolvePrinter(
+				Printer * printer) = 0;
+	};
+}
diff --git a/Clients/PrinterSetupWizard/res/Info.ico b/Clients/PrinterSetupWizard/res/Info.ico
new file mode 100644
index 0000000000000000000000000000000000000000..1a5321892cd0a0ba55a7a9a828242064d9644940
GIT binary patch
literal 23558
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
BmIMF*

literal 0
HcmV?d00001

diff --git a/Clients/PrinterSetupWizard/res/NetworkPrinter.ico b/Clients/PrinterSetupWizard/res/NetworkPrinter.ico
new file mode 100644
index 0000000000000000000000000000000000000000..22130b3de3ee242e78b347bc07d177cf3cd44a10
GIT binary patch
literal 77214
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

literal 0
HcmV?d00001

diff --git a/Clients/PrinterSetupWizard/res/Print.ico b/Clients/PrinterSetupWizard/res/Print.ico
new file mode 100644
index 0000000000000000000000000000000000000000..22130b3de3ee242e78b347bc07d177cf3cd44a10
GIT binary patch
literal 77214
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

literal 0
HcmV?d00001

diff --git a/Clients/PrinterSetupWizard/res/PrinterSetupWizard.ico b/Clients/PrinterSetupWizard/res/PrinterSetupWizard.ico
new file mode 100644
index 0000000000000000000000000000000000000000..22130b3de3ee242e78b347bc07d177cf3cd44a10
GIT binary patch
literal 77214
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

literal 0
HcmV?d00001

diff --git a/Clients/PrinterSetupWizard/res/PrinterSetupWizard.manifest b/Clients/PrinterSetupWizard/res/PrinterSetupWizard.manifest
new file mode 100644
index 0000000..90a067e
--- /dev/null
+++ b/Clients/PrinterSetupWizard/res/PrinterSetupWizard.manifest
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> 
+<assemblyIdentity 
+    version="1.0.0.0" 
+    processorArchitecture="X86" 
+    name="Microsoft.Windows.Wiz97_3"
+    type="win32" 
+/> 
+<description>Your app description here</description> 
+<dependency> 
+    <dependentAssembly> 
+        <assemblyIdentity 
+            type="win32" 
+            name="Microsoft.Windows.Common-Controls" 
+            version="6.0.0.0" 
+            processorArchitecture="X86" 
+            publicKeyToken="6595b64144ccf1df" 
+            language="*" 
+        /> 
+    </dependentAssembly> 
+</dependency> 
+</assembly>
diff --git a/Clients/PrinterSetupWizard/res/PrinterSetupWizard.rc2 b/Clients/PrinterSetupWizard/res/PrinterSetupWizard.rc2
new file mode 100644
index 0000000..27e049a
--- /dev/null
+++ b/Clients/PrinterSetupWizard/res/PrinterSetupWizard.rc2
@@ -0,0 +1,13 @@
+//
+// Wiz97_3.RC2 - resources Microsoft Visual C++ does not edit directly
+//
+
+#ifdef APSTUDIO_INVOKED
+#error this file is not editable by Microsoft Visual C++
+#endif //APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+// Add manually edited resources here...
+
+/////////////////////////////////////////////////////////////////////////////
diff --git a/Clients/PrinterSetupWizard/res/Thumbs.db b/Clients/PrinterSetupWizard/res/Thumbs.db
new file mode 100644
index 0000000000000000000000000000000000000000..f9f63303f0eed979076b3fdbf3beed6e2930de75
GIT binary patch
literal 6144
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

literal 0
HcmV?d00001

diff --git a/Clients/PrinterSetupWizard/res/about.bmp b/Clients/PrinterSetupWizard/res/about.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..83e0bb08f30df508c5417ccfd0d9094355357dbb
GIT binary patch
literal 254802
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
XN`L?Y{sqV?|3<8V00Q9`h>H4uC#$U`

literal 0
HcmV?d00001

diff --git a/Clients/PrinterSetupWizard/res/banner_icon.bmp b/Clients/PrinterSetupWizard/res/banner_icon.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..8e62c35c4da70559ff1c79cc3ca21a9811a6aa24
GIT binary patch
literal 7308
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
SFYnO1FW(`(N2wh+cI-dnTqX1X

literal 0
HcmV?d00001

diff --git a/Clients/PrinterSetupWizard/res/watermark.bmp b/Clients/PrinterSetupWizard/res/watermark.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..e76046b64272f10609ca113e73cfc768aa9a7ec7
GIT binary patch
literal 162908
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

literal 0
HcmV?d00001

diff --git a/Clients/PrinterSetupWizard/resource.h b/Clients/PrinterSetupWizard/resource.h
new file mode 100644
index 0000000..8c2a6ca
--- /dev/null
+++ b/Clients/PrinterSetupWizard/resource.h
@@ -0,0 +1,74 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by PrinterSetupWizard.rc
+//
+#define IDR_MANIFEST                    1
+#define IDM_ABOUTBOX                    0x0010
+#define IDD_ABOUTBOX                    100
+#define IDS_ABOUTBOX                    101
+#define IDD_PRINTERSETUPWIZARD_DIALOG   102
+#define IDS_GOODBYE                     102
+#define IDS_GREETING                    103
+#define IDS_BROWSE_TITLE                104
+#define IDS_BROWSE_SUBTITLE             105
+#define IDS_CAPTION                     106
+#define IDD_FIRST_PAGE                  107
+#define IDS_GOODBYE_GOOD1               107
+#define IDS_SEARCHING                   108
+#define IDD_SECOND_PAGE                 109
+#define IDS_GOODBYTE_GOOD2              109
+#define IDS_INSTALL_TITLE               110
+#define IDS_INSTALL_SUBTITLE            111
+#define IDS_ERROR_SELECTING_PRINTER_TEXT       112
+#define IDS_ERROR_SELECTING_PRINTER_CAPTION    113
+#define IDS_INSTALL_ERROR_CAPTION       114
+#define IDS_INSTALL_ERROR_MESSAGE       115
+#define IDS_MANUFACTURER_HEADING        116
+#define IDS_MODEL_HEADING               117
+#define IDS_NO_RENDEZVOUS_PRINTERS      118
+#define IDS_NO_MDNSRESPONDER_SERVICE_TEXT      119
+#define IDS_NO_MDNSRESPONDER_SERVICE_CAPTION   120
+#define IDS_PRINTER_MATCH_GOOD          121
+#define IDS_PRINTER_MATCH_BAD           122
+#define IDS_YES                         123
+#define IDS_NO                          124
+#define IDS_LARGE_FONT                  125
+#define IDR_MAINFRAME                   128
+#define IDB_BANNER_ICON                 129
+#define IDD_THIRD_PAGE                  130
+#define IDB_WATERMARK                   131
+#define IDD_FOURTH_PAGE                 132
+#define IDI_INFO                        136
+#define IDB_ABOUT                       138
+#define IDD_DIALOG1                     139
+#define IDI_ICON2                       141
+#define IDI_PRINTER                     141
+#define IDC_BUTTON1                     1000
+#define IDC_LIST1                       1000
+#define IDC_BROWSE_LIST                 1000
+#define IDC_RADIO1                      1001
+#define IDC_COMBO1                      1001
+#define IDC_RADIO2                      1002
+#define IDC_GREETING                    1003
+#define IDC_CHECK1                      1016
+#define IDC_DEFAULT_PRINTER             1016
+#define IDC_PRINTER_IMAGE               1017
+#define IDC_PRINTER_NAME                1018
+#define IDC_PRINTER_MANUFACTURER        1019
+#define IDC_PRINTER_MODEL               1020
+#define IDC_GOODBYE                     1021
+#define IDC_PRINTER_PORT                1022
+#define IDC_PRINTER_DEFAULT             1023
+#define IDC_PRINTER_SELECTION_TEXT      1024
+#define IDC_HAVE_DISK                   1025
+
+// Next default values for new objects
+// 
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE        142
+#define _APS_NEXT_COMMAND_VALUE         32771
+#define _APS_NEXT_CONTROL_VALUE         1026
+#define _APS_NEXT_SYMED_VALUE           101
+#endif
+#endif
diff --git a/Clients/PrinterSetupWizard/stdafx.cpp b/Clients/PrinterSetupWizard/stdafx.cpp
new file mode 100644
index 0000000..53abf25
--- /dev/null
+++ b/Clients/PrinterSetupWizard/stdafx.cpp
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+    
+$Log: stdafx.cpp,v $
+Revision 1.1  2004/06/18 04:36:58  rpantos
+First checked in
+
+
+*/
+
+#include "stdafx.h"
+
+
diff --git a/Clients/PrinterSetupWizard/stdafx.h b/Clients/PrinterSetupWizard/stdafx.h
new file mode 100644
index 0000000..160644b
--- /dev/null
+++ b/Clients/PrinterSetupWizard/stdafx.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+    
+$Log: stdafx.h,v $
+Revision 1.1  2004/06/18 04:36:58  rpantos
+First checked in
+
+
+*/
+
+#pragma once
+
+#ifndef VC_EXTRALEAN
+#define VC_EXTRALEAN		// Exclude rarely-used stuff from Windows headers
+#endif
+
+// Modify the following defines if you have to target a platform prior to the ones specified below.
+// Refer to MSDN for the latest info on corresponding values for different platforms.
+#ifndef WINVER				// Allow use of features specific to Windows 95 and Windows NT 4 or later.
+#define WINVER 0x0400		// Change this to the appropriate value to target Windows 98 and Windows 2000 or later.
+#endif
+
+#ifndef _WIN32_WINNT		// Allow use of features specific to Windows NT 4 or later.
+#define _WIN32_WINNT 0x0400	// Change this to the appropriate value to target Windows 98 and Windows 2000 or later.
+#endif						
+
+#ifndef _WIN32_WINDOWS		// Allow use of features specific to Windows 98 or later.
+#define _WIN32_WINDOWS 0x0410 // Change this to the appropriate value to target Windows Me or later.
+#endif
+
+// Step 3: We want to see one image, but not a tile
+#ifndef _WIN32_IE			// Allow use of features specific to IE 4.0 or later.
+#define _WIN32_IE 0x0500	// Change this to the appropriate value to target IE 5.0 or later.
+#endif
+
+#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS	// some CString constructors will be explicit
+
+// turns off MFC's hiding of some common and often safely ignored warning messages
+#define _AFX_ALL_WARNINGS
+
+#include <afxwin.h>         // MFC core and standard components
+#include <afxext.h>         // MFC extensions
+#include <afxdisp.h>        // MFC Automation classes
+
+#include <afxdtctl.h>		// MFC support for Internet Explorer 4 Common Controls
+#ifndef _AFX_NO_AFXCMN_SUPPORT
+#include <afxcmn.h>			// MFC support for Windows Common Controls
+#endif // _AFX_NO_AFXCMN_SUPPORT
+#include <afxdlgs.h>
+
diff --git a/Clients/SimpleChat.NET/App.ico b/Clients/SimpleChat.NET/App.ico
new file mode 100755
index 0000000000000000000000000000000000000000..3a5525fd794f7a7c5c8e6187f470ea3af38cd2b6
GIT binary patch
literal 1078
zcmeHHJr05}7=1t!Hp3A*8IHkVf+j?-!eHY14Gtcw1Eb*_9>Bq^zETJ@GKj{_2j4$w
zo9}xCh!8{T3=X##Skq>ikMjsvB|y%crWBM2iW(4pI}c%z6%lW!=~4v77#3{z!dmB1
z__&l)-{KUYR+|8|;wB^R|9ET$J@(@=#rd^=)qs85?vAy(PSF5CyNkus435LVkZ$rj
zNw|JG-P7^hF<(;#o*Vk}5R#e|^13tBbQkeF?djULtvqyxd3<cQetc!+$5J+aVZ&1f
Qa92%&%o_p!1^%7_Ps0Y#2><{9

literal 0
HcmV?d00001

diff --git a/Clients/SimpleChat.NET/AssemblyInfo.cs b/Clients/SimpleChat.NET/AssemblyInfo.cs
new file mode 100755
index 0000000..a778420
--- /dev/null
+++ b/Clients/SimpleChat.NET/AssemblyInfo.cs
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+    
+$Log: AssemblyInfo.cs,v $
+Revision 1.1  2004/07/19 07:57:08  shersche
+Initial revision
+
+
+
+*/
+
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+//
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+//
+[assembly: AssemblyTitle("")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("")]
+[assembly: AssemblyCopyright("")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]		
+
+//
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Revision and Build Numbers 
+// by using the '*' as shown below:
+
+[assembly: AssemblyVersion("1.0.*")]
+
+//
+// In order to sign your assembly you must specify a key to use. Refer to the 
+// Microsoft .NET Framework documentation for more information on assembly signing.
+//
+// Use the attributes below to control which key is used for signing. 
+//
+// Notes: 
+//   (*) If no key is specified, the assembly is not signed.
+//   (*) KeyName refers to a key that has been installed in the Crypto Service
+//       Provider (CSP) on your machine. KeyFile refers to a file which contains
+//       a key.
+//   (*) If the KeyFile and the KeyName values are both specified, the 
+//       following processing occurs:
+//       (1) If the KeyName can be found in the CSP, that key is used.
+//       (2) If the KeyName does not exist and the KeyFile does exist, the key 
+//           in the KeyFile is installed into the CSP and used.
+//   (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility.
+//       When specifying the KeyFile, the location of the KeyFile should be
+//       relative to the project output directory which is
+//       %Project Directory%\obj\<configuration>. For example, if your KeyFile is
+//       located in the project directory, you would specify the AssemblyKeyFile 
+//       attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")]
+//   (*) Delay Signing is an advanced option - see the Microsoft .NET Framework
+//       documentation for more information on this.
+//
+[assembly: AssemblyDelaySign(false)]
+[assembly: AssemblyKeyFile("")]
+[assembly: AssemblyKeyName("")]
diff --git a/Clients/SimpleChat.NET/SimpleChat.NET.csproj b/Clients/SimpleChat.NET/SimpleChat.NET.csproj
new file mode 100755
index 0000000..2165beb
--- /dev/null
+++ b/Clients/SimpleChat.NET/SimpleChat.NET.csproj
@@ -0,0 +1,116 @@
+<VisualStudioProject>
+    <CSHARP
+        ProjectType = "Local"
+        ProductVersion = "7.0.9466"
+        SchemaVersion = "1.0"
+        ProjectGuid = "{726DED99-34D0-45F3-9F4D-C7068DF4BCDA}"
+    >
+        <Build>
+            <Settings
+                ApplicationIcon = "App.ico"
+                AssemblyKeyContainerName = ""
+                AssemblyName = "SimpleChat.NET"
+                AssemblyOriginatorKeyFile = ""
+                DefaultClientScript = "JScript"
+                DefaultHTMLPageLayout = "Grid"
+                DefaultTargetSchema = "IE50"
+                DelaySign = "false"
+                OutputType = "WinExe"
+                RootNamespace = "SimpleChat.NET"
+                StartupObject = ""
+            >
+                <Config
+                    Name = "Debug"
+                    AllowUnsafeBlocks = "false"
+                    BaseAddress = "285212672"
+                    CheckForOverflowUnderflow = "false"
+                    ConfigurationOverrideFile = ""
+                    DefineConstants = "DEBUG;TRACE"
+                    DocumentationFile = ""
+                    DebugSymbols = "true"
+                    FileAlignment = "4096"
+                    IncrementalBuild = "true"
+                    Optimize = "false"
+                    OutputPath = "bin\Debug\"
+                    RegisterForComInterop = "false"
+                    RemoveIntegerChecks = "false"
+                    TreatWarningsAsErrors = "false"
+                    WarningLevel = "4"
+                />
+                <Config
+                    Name = "Release"
+                    AllowUnsafeBlocks = "false"
+                    BaseAddress = "285212672"
+                    CheckForOverflowUnderflow = "false"
+                    ConfigurationOverrideFile = ""
+                    DefineConstants = "TRACE"
+                    DocumentationFile = ""
+                    DebugSymbols = "false"
+                    FileAlignment = "4096"
+                    IncrementalBuild = "false"
+                    Optimize = "true"
+                    OutputPath = "bin\Release\"
+                    RegisterForComInterop = "false"
+                    RemoveIntegerChecks = "false"
+                    TreatWarningsAsErrors = "false"
+                    WarningLevel = "4"
+                />
+            </Settings>
+            <References>
+                <Reference
+                    Name = "System"
+                    AssemblyName = "System"
+                    HintPath = "..\..\..\..\..\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.dll"
+                />
+                <Reference
+                    Name = "System.Data"
+                    AssemblyName = "System.Data"
+                    HintPath = "..\..\..\..\..\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.Data.dll"
+                />
+                <Reference
+                    Name = "System.Drawing"
+                    AssemblyName = "System.Drawing"
+                    HintPath = "..\..\..\..\..\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.Drawing.dll"
+                />
+                <Reference
+                    Name = "System.Windows.Forms"
+                    AssemblyName = "System.Windows.Forms"
+                    HintPath = "..\..\..\..\..\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.Windows.Forms.dll"
+                />
+                <Reference
+                    Name = "System.XML"
+                    AssemblyName = "System.XML"
+                    HintPath = "..\..\..\..\..\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.XML.dll"
+                />
+                <Reference
+                    Name = "dnssd.NET"
+                    AssemblyName = "dnssd.NET"
+                    HintPath = "..\..\mDNSWindows\DLL.NET\Release\dnssd.NET.dll"
+                />
+            </References>
+        </Build>
+        <Files>
+            <Include>
+                <File
+                    RelPath = "App.ico"
+                    BuildAction = "Content"
+                />
+                <File
+                    RelPath = "AssemblyInfo.cs"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "SimpleChat.cs"
+                    SubType = "Form"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "SimpleChat.resx"
+                    DependentUpon = "SimpleChat.cs"
+                    BuildAction = "EmbeddedResource"
+                />
+            </Include>
+        </Files>
+    </CSHARP>
+</VisualStudioProject>
+
diff --git a/Clients/SimpleChat.NET/SimpleChat.cs b/Clients/SimpleChat.NET/SimpleChat.cs
new file mode 100755
index 0000000..fb841f2
--- /dev/null
+++ b/Clients/SimpleChat.NET/SimpleChat.cs
@@ -0,0 +1,757 @@
+/*
+ * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+    
+$Log: SimpleChat.cs,v $
+Revision 1.5  2004/09/13 19:37:42  shersche
+Change code to reflect namespace and type changes to dnssd.NET library
+
+Revision 1.4  2004/09/11 05:42:56  shersche
+don't reset SelectedIndex in OnRemove
+
+Revision 1.3  2004/09/11 00:38:58  shersche
+DNSService APIs now expect port in host format
+
+Revision 1.2  2004/07/19 22:08:53  shersche
+Fixed rdata->int conversion problem in QueryRecordReply
+
+Revision 1.1  2004/07/19 07:57:08  shersche
+Initial revision
+
+
+
+*/
+
+using System;
+using System.Drawing;
+using System.Collections;
+using System.ComponentModel;
+using System.Windows.Forms;
+using System.Net;
+using System.Net.Sockets;
+using System.Data;
+using System.Text;
+using Apple.DNSSD;
+
+namespace SimpleChat.NET
+{
+	/// <summary>
+	/// Summary description for Form1.
+	/// </summary>
+	/// 
+
+	//
+	// PeerData
+	//
+	// Holds onto the information associated with a peer on the network
+	//
+	public class PeerData
+	{
+		public int			InterfaceIndex;
+		public String		Name;
+		public String		Type;
+		public String		Domain;
+		public IPAddress	Address;
+		public int			Port;
+
+		public override String
+		ToString()
+		{
+			return Name;
+		}
+
+		public override bool
+		Equals(object other)
+		{
+			bool result = false;
+
+			if (other != null)
+			{
+				if ((object) this == other)
+				{
+					result = true;
+				}
+				else if (other is PeerData)
+				{
+					PeerData otherPeerData = (PeerData) other;
+
+					result = (this.Name == otherPeerData.Name);
+				}
+			}
+
+			return result;
+		}
+	
+		public override int
+		GetHashCode()
+		{
+			return Name.GetHashCode();
+		}
+	};
+
+	//
+	// ResolveData
+	//
+	// Holds onto the information associated with the resolution
+	// of a DNSService
+	//
+	public class ResolveData
+	{
+		public int		InterfaceIndex;
+		public String	FullName;
+		public String	HostName;
+		public int		Port;
+		public Byte[]	TxtRecord;
+
+		public override String
+		ToString()
+		{
+			return FullName;
+		}
+	};
+
+
+	//
+	// SocketStateObject
+	//
+	// Holds onto the data associated with an asynchronous
+	// socket operation
+	//
+	class SocketStateObject
+	{
+		public const int		BUFFER_SIZE = 1024;
+		private Socket			m_socket;
+		public byte[]			m_buffer;
+		public bool				m_complete;
+		public StringBuilder	m_sb = new StringBuilder();
+
+		public SocketStateObject(Socket socket)
+		{
+			m_buffer	= new byte[BUFFER_SIZE];
+			m_complete	= false;
+			m_socket	= socket;
+		}
+
+		public Socket
+		WorkSocket
+		{
+			get
+			{
+				return m_socket;
+			}
+		}
+	}
+	public class Form1 : System.Windows.Forms.Form
+	{
+		private System.Windows.Forms.ComboBox comboBox1;
+		private System.Windows.Forms.TextBox textBox2;
+		private System.Windows.Forms.Button button1;
+		private System.Windows.Forms.Label label1;
+		private ServiceRef registrar = null;
+		private ServiceRef browser = null;
+		private ServiceRef resolver = null;
+		private String					myName;
+		/// <summary>
+		/// Required designer variable.
+		/// </summary>
+		private System.ComponentModel.Container components = null;
+		
+		//
+		// These all of our callbacks.  These are invoked in the context
+		// of the main (GUI) thread.  The DNSService callbacks Invoke()
+		// them
+		delegate void RegisterServiceCallback(String name);
+		delegate void AddPeerCallback(PeerData data);
+		delegate void RemovePeerCallback(PeerData data);
+		delegate void ResolveServiceCallback(ResolveData data);
+		delegate void ResolveAddressCallback(System.Net.IPAddress address);
+		delegate void ReadMessageCallback(String data);
+
+		RegisterServiceCallback	registerServiceCallback;
+		AddPeerCallback			addPeerCallback;
+		RemovePeerCallback		removePeerCallback;
+		ResolveServiceCallback  resolveServiceCallback;
+		ResolveAddressCallback	resolveAddressCallback;
+		ReadMessageCallback		readMessageCallback;
+		private System.Windows.Forms.RichTextBox richTextBox1;
+
+		//
+		// The socket that we will be reading data from
+		//
+		Socket socket = null;
+
+		//
+		// OnRegisterService
+		//
+		// The name that we are passed might be different than the
+		// name we called Register with.  So we hold onto this name
+		// rather than the name we Register with.
+		//
+		// This is called (indirectly) from OnRegisterReply().
+		//
+		private void
+		OnRegisterService
+				(
+				String name
+				)
+		{
+			myName = name;
+		}
+
+		//
+		// OnAddPeer
+		//
+		// Called when DNSServices detects a new P2P Chat peer has
+		// joined.
+		//
+		// This is called (indirectly) from OnBrowseReply()
+		//
+		private void
+		OnAddPeer
+				(
+				PeerData  peer
+				)
+		{
+			comboBox1.Items.Add(peer);
+
+			if (comboBox1.Items.Count == 1)
+			{
+				comboBox1.SelectedIndex = 0;
+			}
+		}
+
+		//
+		// OnRemovePeer
+		//
+		// Called when DNSServices detects a P2P peer has left
+		// the network
+		//
+		// This is called (indirectly) from OnBrowseReply()
+		//
+		private void
+		OnRemovePeer
+				(
+				PeerData  peer
+				)
+		{
+			comboBox1.Items.Remove(peer);
+		}
+
+		//
+		// OnResolveService
+		//
+		// Called when DNSServices has resolved a service.
+		//
+		// This is called (indirectly) from OnResolveService()
+		//
+		private void
+		OnResolveService
+				(
+				ResolveData data
+				)
+		{
+			resolver.Dispose();
+
+			PeerData peer = (PeerData) comboBox1.SelectedItem;
+
+			peer.Port = data.Port;
+
+			try
+			{
+				resolver = DNSService.QueryRecord(0, 0, data.HostName, /* ns_t_a */ 1, /* ns_t_c */ 1, new DNSService.QueryRecordReply(OnQueryRecordReply));
+			}
+			catch
+			{
+				MessageBox.Show("QueryRecord Failed", "Error");
+				Application.Exit();
+			}
+		}
+
+		//
+		// OnResolveAddress
+		//
+		// Called when DNSServices has finished a query operation
+		//
+		// This is called (indirectly) from OnQueryRecordReply()
+		//
+		private void
+		OnResolveAddress
+				(
+				System.Net.IPAddress address
+				)
+		{
+			resolver.Dispose();
+
+			PeerData peer = (PeerData) comboBox1.SelectedItem;
+
+			peer.Address = address;
+		}
+
+		//
+		// OnReadMessage
+		//
+		// Called when there is data to be read on a socket
+		//
+		// This is called (indirectly) from OnReadSocket()
+		//
+		private void
+		OnReadMessage
+				(
+				String msg
+				)
+		{
+			int rgb = 0;
+
+			for (int i = 0; i < msg.Length && msg[i] != ':'; i++)
+			{
+				rgb = rgb ^ ((int) msg[i] << (i % 3 + 2) * 8);
+			}
+
+			Color color = Color.FromArgb(rgb & 0x007F7FFF);
+
+			richTextBox1.SelectionColor = color;
+			
+			richTextBox1.AppendText(msg + "\n");
+		}
+
+		//
+		// OnRegisterReply
+		//
+		// Called by DNSServices core as a result of DNSService.Register()
+		// call
+		//
+		// This is called from a worker thread by DNSService core.
+		//
+		private void
+		OnRegisterReply
+					(
+					ServiceRef		sdRef,
+					ServiceFlags	flags,
+					ErrorCode		errorCode,
+					String			name,
+					String			regtype,
+					String			domain)
+		{
+			if (errorCode == ErrorCode.NoError)
+			{
+				Invoke(registerServiceCallback, new Object[]{name});
+			}
+			else
+			{
+				MessageBox.Show("OnRegisterReply returned an error code " + errorCode, "Error");
+			}
+		}
+
+
+		//
+		// OnBrowseReply
+		//
+		// Called by DNSServices core as a result of DNSService.Browse()
+		// call
+		//
+		// This is called from a worker thread by DNSService core.
+		//
+		private void
+		OnBrowseReply
+					(
+					ServiceRef		sdRef,
+					ServiceFlags	flags,
+					int				interfaceIndex,
+					ErrorCode		errorCode,
+					String			name,
+					String			type,
+					String			domain)
+		{
+			if (errorCode == ErrorCode.NoError)
+			{
+				PeerData peer = new PeerData();
+
+				peer.InterfaceIndex = interfaceIndex;
+				peer.Name = name;
+				peer.Type = type;
+				peer.Domain = domain;
+				peer.Address = null;
+
+				if ((flags & ServiceFlags.Add) != 0)
+				{
+					Invoke(addPeerCallback, new Object[]{peer});
+				}
+				else if ((flags == 0) || ((flags & ServiceFlags.MoreComing) != 0))
+				{
+					Invoke(removePeerCallback, new Object[]{peer});
+				}
+			}
+			else
+			{
+				MessageBox.Show("OnBrowseReply returned an error code " + errorCode, "Error");
+			}
+		}
+
+		//
+		// OnResolveReply
+		//
+		// Called by DNSServices core as a result of DNSService.Resolve()
+		// call
+		//
+		// This is called from a worker thread by DNSService core.
+		//
+		private void
+		OnResolveReply
+			(
+			ServiceRef		sdRef,
+			ServiceFlags	flags,
+			int				interfaceIndex,
+			ErrorCode		errorCode,
+			String			fullName,
+			String			hostName,
+			int				port,
+			Byte[]			txtRecord
+			)
+		{
+			if (errorCode == ErrorCode.NoError)
+			{
+				ResolveData data = new ResolveData();
+
+				data.InterfaceIndex = interfaceIndex;
+				data.FullName		= fullName;
+				data.HostName		= hostName;
+				data.Port			= port;
+				data.TxtRecord		= txtRecord;
+
+				Invoke(resolveServiceCallback, new Object[]{data});
+			}
+			else
+			{
+				MessageBox.Show("OnResolveReply returned an error code: " + errorCode, "Error");
+			}
+		}
+
+		//
+		// OnQueryRecordReply
+		//
+		// Called by DNSServices core as a result of DNSService.QueryRecord()
+		// call
+		//
+		// This is called from a worker thread by DNSService core.
+		//
+		private void
+		OnQueryRecordReply
+			(
+			ServiceRef		sdRef,
+			ServiceFlags	flags,
+			int				interfaceIndex,
+			ErrorCode		errorCode,	
+			String			fullName,
+			int				rrtype,
+			int				rrclass,
+			Byte[]			rdata,
+			int				ttl
+			)
+		{
+			if (errorCode == ErrorCode.NoError)
+			{
+				uint bits					= BitConverter.ToUInt32(rdata, 0);
+				System.Net.IPAddress data	= new System.Net.IPAddress(bits);
+		
+				Invoke(resolveAddressCallback, new Object[]{data});
+			}
+			else
+			{
+				MessageBox.Show("OnQueryRecordReply returned an error code: " + errorCode, "Error");
+			}
+		}
+
+		//
+		// OnReadSocket
+		//
+		// Called by the .NET core when there is data to be read on a socket
+		//
+		// This is called from a worker thread by the .NET core
+		//
+		private void
+		OnReadSocket
+				(
+				IAsyncResult ar
+				)
+		{
+			SocketStateObject so = (SocketStateObject) ar.AsyncState;
+			Socket s = so.WorkSocket;
+
+			try
+			{
+				if (s == null)
+				{
+					return;
+				}
+
+				int read = s.EndReceive(ar);
+
+				if (read > 0)
+				{
+					String msg = Encoding.UTF8.GetString(so.m_buffer, 0, read);
+					
+					Invoke(readMessageCallback, new Object[]{msg});
+				}
+
+				s.BeginReceive(so.m_buffer, 0, SocketStateObject.BUFFER_SIZE, 0, new AsyncCallback(OnReadSocket), so);
+			}
+			catch
+			{
+			}
+		}
+
+
+		public Form1()
+		{
+			//
+			// Required for Windows Form Designer support
+			//
+			InitializeComponent();
+
+			registerServiceCallback	= new RegisterServiceCallback(OnRegisterService);
+			addPeerCallback			= new AddPeerCallback(OnAddPeer);
+			removePeerCallback		= new RemovePeerCallback(OnRemovePeer);
+			resolveServiceCallback	= new ResolveServiceCallback(OnResolveService);
+			resolveAddressCallback	= new ResolveAddressCallback(OnResolveAddress);
+			readMessageCallback		= new ReadMessageCallback(OnReadMessage);
+
+			this.Load += new System.EventHandler(this.Form1_Load);
+
+			this.AcceptButton = button1;
+		}
+
+		/// <summary>
+		/// Clean up any resources being used.
+		/// </summary>
+		protected override void
+		Dispose( bool disposing )
+		{
+			if( disposing )
+			{
+				if (components != null) 
+				{
+					components.Dispose();
+				}
+
+				if (registrar != null)
+				{
+					registrar.Dispose();
+				}
+
+				if (browser != null)
+				{
+					browser.Dispose();
+				}
+			}
+			base.Dispose( disposing );
+		}
+
+		#region Windows Form Designer generated code
+		/// <summary>
+		/// Required method for Designer support - do not modify
+		/// the contents of this method with the code editor.
+		/// </summary>
+		private void InitializeComponent()
+		{
+			this.comboBox1 = new System.Windows.Forms.ComboBox();
+			this.textBox2 = new System.Windows.Forms.TextBox();
+			this.button1 = new System.Windows.Forms.Button();
+			this.label1 = new System.Windows.Forms.Label();
+			this.richTextBox1 = new System.Windows.Forms.RichTextBox();
+			this.SuspendLayout();
+			// 
+			// comboBox1
+			// 
+			this.comboBox1.Anchor = ((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) 
+				| System.Windows.Forms.AnchorStyles.Right);
+			this.comboBox1.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
+			this.comboBox1.Location = new System.Drawing.Point(59, 208);
+			this.comboBox1.Name = "comboBox1";
+			this.comboBox1.Size = new System.Drawing.Size(224, 21);
+			this.comboBox1.Sorted = true;
+			this.comboBox1.TabIndex = 5;
+			this.comboBox1.SelectedIndexChanged += new System.EventHandler(this.comboBox1_SelectedIndexChanged);
+			// 
+			// textBox2
+			// 
+			this.textBox2.Anchor = ((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) 
+				| System.Windows.Forms.AnchorStyles.Right);
+			this.textBox2.Location = new System.Drawing.Point(8, 248);
+			this.textBox2.Name = "textBox2";
+			this.textBox2.ScrollBars = System.Windows.Forms.ScrollBars.Horizontal;
+			this.textBox2.Size = new System.Drawing.Size(192, 20);
+			this.textBox2.TabIndex = 2;
+			this.textBox2.Text = "";
+			this.textBox2.TextChanged += new System.EventHandler(this.textBox2_TextChanged);
+			// 
+			// button1
+			// 
+			this.button1.Anchor = (System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right);
+			this.button1.Enabled = false;
+			this.button1.Location = new System.Drawing.Point(208, 248);
+			this.button1.Name = "button1";
+			this.button1.TabIndex = 3;
+			this.button1.Text = "Send";
+			this.button1.Click += new System.EventHandler(this.button1_Click);
+			// 
+			// label1
+			// 
+			this.label1.Anchor = (System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left);
+			this.label1.Location = new System.Drawing.Point(8, 210);
+			this.label1.Name = "label1";
+			this.label1.Size = new System.Drawing.Size(48, 16);
+			this.label1.TabIndex = 4;
+			this.label1.Text = "Talk To:";
+			// 
+			// richTextBox1
+			// 
+			this.richTextBox1.Anchor = (((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 
+				| System.Windows.Forms.AnchorStyles.Left) 
+				| System.Windows.Forms.AnchorStyles.Right);
+			this.richTextBox1.Location = new System.Drawing.Point(8, 8);
+			this.richTextBox1.Name = "richTextBox1";
+			this.richTextBox1.ReadOnly = true;
+			this.richTextBox1.Size = new System.Drawing.Size(272, 184);
+			this.richTextBox1.TabIndex = 1;
+			this.richTextBox1.Text = "";
+			// 
+			// Form1
+			// 
+			this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
+			this.ClientSize = new System.Drawing.Size(292, 273);
+			this.Controls.AddRange(new System.Windows.Forms.Control[] {
+																		  this.richTextBox1,
+																		  this.label1,
+																		  this.button1,
+																		  this.textBox2,
+																		  this.comboBox1});
+			this.Name = "Form1";
+			this.Text = "SimpleChat.NET";
+			this.ResumeLayout(false);
+
+		}
+		#endregion
+
+		private void Form1_Load(object sender, EventArgs e) 
+		{
+			IPEndPoint localEP = new IPEndPoint(System.Net.IPAddress.Any, 0);
+			
+			//
+			// create the socket and bind to INADDR_ANY
+			//
+			socket	= new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
+			socket.Bind(localEP);
+			localEP = (IPEndPoint) socket.LocalEndPoint;
+
+			//
+			// start asynchronous read
+			//
+			SocketStateObject so = new SocketStateObject(socket);
+			socket.BeginReceive(so.m_buffer, 0, SocketStateObject.BUFFER_SIZE, 0, new AsyncCallback(this.OnReadSocket), so);   
+
+			try
+			{
+				//
+				// start the register and browse operations
+				//
+				registrar	=	DNSService.Register(0, 0, System.Environment.UserName, "_p2pchat._udp", null, null, localEP.Port, null, new DNSService.RegisterReply(OnRegisterReply));
+				browser		=	DNSService.Browse(0, 0, "_p2pchat._udp", null, new DNSService.BrowseReply(OnBrowseReply));			
+			}
+			catch
+			{
+				MessageBox.Show("DNSServices Not Available", "Error");
+				Application.Exit();
+			}
+		}
+
+		/// <summary>
+		/// The main entry point for the application.
+		/// </summary>
+		[STAThread]
+		static void Main() 
+		{
+			Application.Run(new Form1());
+		}
+
+		//
+		// send the message to a peer
+		//
+		private void button1_Click(object sender, System.EventArgs e)
+		{
+			PeerData peer = (PeerData) comboBox1.SelectedItem;
+
+			String message = myName + ": " + textBox2.Text;
+
+			Byte[] bytes = Encoding.UTF8.GetBytes(message);
+			
+			UdpClient udpSocket = new UdpClient(peer.Address.ToString(), peer.Port);
+
+			udpSocket.Send(bytes, bytes.Length);
+
+			richTextBox1.SelectionColor = Color.Black;
+
+			richTextBox1.AppendText(textBox2.Text + "\n");
+
+			textBox2.Text = "";
+		}
+
+		//
+		// called when typing in message box
+		//
+		private void textBox2_TextChanged(object sender, System.EventArgs e)
+		{
+			PeerData peer = (PeerData) comboBox1.SelectedItem;
+
+			if ((peer.Address != null) && (textBox2.Text.Length > 0))
+			{
+				button1.Enabled = true;
+			}
+			else
+			{
+				button1.Enabled = false;
+			}
+		}
+
+		//
+		// called when peer target changes
+		//
+		/// <summary>
+		/// </summary>
+		/// <param name="sender"></param>
+		/// <param name="e"></param>
+		private void comboBox1_SelectedIndexChanged(object sender, System.EventArgs e)
+		{
+			PeerData peer = (PeerData) comboBox1.SelectedItem;
+
+			try
+			{
+				resolver = DNSService.Resolve(0, 0, peer.Name, peer.Type, peer.Domain, new DNSService.ResolveReply(OnResolveReply));
+			}
+			catch
+			{
+				MessageBox.Show("Unable to Resolve service", "Error");
+				Application.Exit();
+			}
+		}
+	}
+}
diff --git a/Clients/SimpleChat.NET/SimpleChat.resx b/Clients/SimpleChat.NET/SimpleChat.resx
new file mode 100755
index 0000000..e5b5a11
--- /dev/null
+++ b/Clients/SimpleChat.NET/SimpleChat.resx
@@ -0,0 +1,102 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+            Microsoft ResX Schema 
+        
+            Version 1.3
+                
+            The primary goals of this format is to allow a simple XML format 
+            that is mostly human readable. The generation and parsing of the 
+            various data types are done through the TypeConverter classes 
+            associated with the data types.
+        
+            Example:
+        
+                ... ado.net/XML headers & schema ...
+                <resheader name="resmimetype">text/microsoft-resx</resheader>
+                <resheader name="version">1.3</resheader>
+                <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+                <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+                <data name="Name1">this is my long string</data>
+                <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+                <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+                    [base64 mime encoded serialized .NET Framework object]
+                </data>
+                <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+                    [base64 mime encoded string representing a byte array form of the .NET Framework object]
+                </data>
+        
+            There are any number of "resheader" rows that contain simple 
+            name/value pairs.
+            
+            Each data row contains a name, and value. The row also contains a 
+            type or mimetype. Type corresponds to a .NET class that support 
+            text/value conversion through the TypeConverter architecture. 
+            Classes that don't support this are serialized and stored with the 
+            mimetype set.
+                     
+            The mimetype is used for serialized objects, and tells the 
+            ResXResourceReader how to depersist the object. This is currently not 
+            extensible. For a given mimetype the value must be set accordingly:
+        
+            Note - application/x-microsoft.net.object.binary.base64 is the format 
+                   that the ResXResourceWriter will generate, however the reader can 
+                   read any of the formats listed below.
+        
+            mimetype: application/x-microsoft.net.object.binary.base64
+            value   : The object must be serialized with 
+                    : System.Serialization.Formatters.Binary.BinaryFormatter
+                    : and then encoded with base64 encoding.
+        
+            mimetype: application/x-microsoft.net.object.soap.base64
+            value   : The object must be serialized with 
+                    : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+                    : and then encoded with base64 encoding.
+            mimetype: application/x-microsoft.net.object.bytearray.base64
+            value   : The object must be serialized into a byte array 
+                    : using a System.ComponentModel.TypeConverter
+                    : and then encoded with base64 encoding.
+        -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>1.3</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <data name="$this.Name">
+    <value>Form1</value>
+  </data>
+</root>
\ No newline at end of file
diff --git a/Clients/dns-sd.c b/Clients/dns-sd.c
index 1fb02d0..17c4a76 100644
--- a/Clients/dns-sd.c
+++ b/Clients/dns-sd.c
@@ -1,26 +1,40 @@
 /*
  * 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@
+ * Disclaimer: IMPORTANT:  This Apple software is supplied to you by Apple Computer, Inc.
+ * ("Apple") in consideration of your agreement to the following terms, and your
+ * use, installation, modification or redistribution of this Apple software
+ * constitutes acceptance of these terms.  If you do not agree with these terms,
+ * please do not use, install, modify or redistribute this Apple software.
+ *
+ * In consideration of your agreement to abide by the following terms, and subject
+ * to these terms, Apple grants you a personal, non-exclusive license, under Apple's
+ * copyrights in this original Apple software (the "Apple Software"), to use,
+ * reproduce, modify and redistribute the Apple Software, with or without
+ * modifications, in source and/or binary forms; provided that if you redistribute
+ * the Apple Software in its entirety and without modifications, you must retain
+ * this notice and the following text and disclaimers in all such redistributions of
+ * the Apple Software.  Neither the name, trademarks, service marks or logos of
+ * Apple Computer, Inc. may be used to endorse or promote products derived from the
+ * Apple Software without specific prior written permission from Apple.  Except as
+ * expressly stated in this notice, no other rights or licenses, express or implied,
+ * are granted by Apple herein, including but not limited to any patent rights that
+ * may be infringed by your derivative works or by other works in which the Apple
+ * Software may be incorporated.
+ *
+ * The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO
+ * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+ * WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
+ * COMBINATION WITH YOUR PRODUCTS.
+ *
+ * IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
+ * OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
+ * (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  * Formatting notes:
  * This code follows the "Whitesmiths style" C indentation rules. Plenty of discussion
@@ -35,42 +49,39 @@
  * 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
+To build this tool, copy and paste the following into a command line:
 
-Revision 1.5  2004/05/21 17:39:27  cheshire
-Include extra headers to fix Xcode build
+OS X:
+gcc dns-sd.c -o dns-sd
 
-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
+POSIX systems:
+gcc dns-sd.c -o dns-sd -I../mDNSShared -ldns_sd
 
+Windows:
+cl dns-sd.c -I../mDNSShared -DNOT_HAVE_GETOPT -DNOT_HAVE_SETLINEBUF ws2_32.lib ..\mDNSWindows\DLL\Release\dnssd.lib
+(may require that you run a Visual Studio script such as vsvars32.bat first)
 */
 
+#include "dns_sd.h"
+#include <ctype.h>
 #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 <string.h>			// For strlen(), strcpy(), bzero()
 #include <errno.h>          // For errno, EINTR
-#define BIND_8_COMPAT
-#include <arpa/nameser.h>	// For T_HINFO, etc.
+#include <time.h>
+
+#ifdef _WIN32
+#include <process.h>
+typedef	int	pid_t;
+#define	getpid	_getpid
+#define	strcasecmp	_stricmp
+#define snprintf _snprintf
+#else
 #include <sys/time.h>		// For struct timeval
-#include <dns_sd.h>
+#include <unistd.h>         // For getopt() and optind
+#include <arpa/inet.h>		// For inet_addr()
+#endif
+
 
 //*************************************************************************************************************
 // Globals
@@ -78,76 +89,199 @@ Check in code to make command-line "dns-sd" testing tool
 typedef union { unsigned char b[2]; unsigned short NotAnInteger; } Opaque16;
 
 static int operation;
-static DNSServiceRef client = NULL;
+static DNSServiceRef client  = NULL;
+static DNSServiceRef client2 = NULL;
 static int num_printed;
 static char addtest = 0;
 static DNSRecordRef record = NULL;
-static char myhinfo9[11] = "\003Mac\006OS 9.2";
+static char myhinfoW[14] = "\002PC\012Windows XP";
 static char myhinfoX[ 9] = "\003Mac\004OS X";
 static char updatetest[3] = "\002AA";
 static char bigNULL[4096];
 
-#define LONG_TIME 0x4000000
+// Note: the select() implementation on Windows (Winsock2) fails with any timeout much larger than this
+#define LONG_TIME 100000000
+
 static volatile int stopNow = 0;
 static volatile int timeOut = LONG_TIME;
 
 //*************************************************************************************************************
 // Supporting Utility Function
 
+static uint16_t GetRRType(const char *s)
+	{
+	if      (!strcasecmp(s, "A"       )) return(kDNSServiceType_A);
+	else if (!strcasecmp(s, "NS"      )) return(kDNSServiceType_NS);
+	else if (!strcasecmp(s, "MD"      )) return(kDNSServiceType_MD);
+	else if (!strcasecmp(s, "MF"      )) return(kDNSServiceType_MF);
+	else if (!strcasecmp(s, "CNAME"   )) return(kDNSServiceType_CNAME);
+	else if (!strcasecmp(s, "SOA"     )) return(kDNSServiceType_SOA);
+	else if (!strcasecmp(s, "MB"      )) return(kDNSServiceType_MB);
+	else if (!strcasecmp(s, "MG"      )) return(kDNSServiceType_MG);
+	else if (!strcasecmp(s, "MR"      )) return(kDNSServiceType_MR);
+	else if (!strcasecmp(s, "NULL"    )) return(kDNSServiceType_NULL);
+	else if (!strcasecmp(s, "WKS"     )) return(kDNSServiceType_WKS);
+	else if (!strcasecmp(s, "PTR"     )) return(kDNSServiceType_PTR);
+	else if (!strcasecmp(s, "HINFO"   )) return(kDNSServiceType_HINFO);
+	else if (!strcasecmp(s, "MINFO"   )) return(kDNSServiceType_MINFO);
+	else if (!strcasecmp(s, "MX"      )) return(kDNSServiceType_MX);
+	else if (!strcasecmp(s, "TXT"     )) return(kDNSServiceType_TXT);
+	else if (!strcasecmp(s, "RP"      )) return(kDNSServiceType_RP);
+	else if (!strcasecmp(s, "AFSDB"   )) return(kDNSServiceType_AFSDB);
+	else if (!strcasecmp(s, "X25"     )) return(kDNSServiceType_X25);
+	else if (!strcasecmp(s, "ISDN"    )) return(kDNSServiceType_ISDN);
+	else if (!strcasecmp(s, "RT"      )) return(kDNSServiceType_RT);
+	else if (!strcasecmp(s, "NSAP"    )) return(kDNSServiceType_NSAP);
+	else if (!strcasecmp(s, "NSAP_PTR")) return(kDNSServiceType_NSAP_PTR);
+	else if (!strcasecmp(s, "SIG"     )) return(kDNSServiceType_SIG);
+	else if (!strcasecmp(s, "KEY"     )) return(kDNSServiceType_KEY);
+	else if (!strcasecmp(s, "PX"      )) return(kDNSServiceType_PX);
+	else if (!strcasecmp(s, "GPOS"    )) return(kDNSServiceType_GPOS);
+	else if (!strcasecmp(s, "AAAA"    )) return(kDNSServiceType_AAAA);
+	else if (!strcasecmp(s, "LOC"     )) return(kDNSServiceType_LOC);
+	else if (!strcasecmp(s, "NXT"     )) return(kDNSServiceType_NXT);
+	else if (!strcasecmp(s, "EID"     )) return(kDNSServiceType_EID);
+	else if (!strcasecmp(s, "NIMLOC"  )) return(kDNSServiceType_NIMLOC);
+	else if (!strcasecmp(s, "SRV"     )) return(kDNSServiceType_SRV);
+	else if (!strcasecmp(s, "ATMA"    )) return(kDNSServiceType_ATMA);
+	else if (!strcasecmp(s, "NAPTR"   )) return(kDNSServiceType_NAPTR);
+	else if (!strcasecmp(s, "KX"      )) return(kDNSServiceType_KX);
+	else if (!strcasecmp(s, "CERT"    )) return(kDNSServiceType_CERT);
+	else if (!strcasecmp(s, "A6"      )) return(kDNSServiceType_A6);
+	else if (!strcasecmp(s, "DNAME"   )) return(kDNSServiceType_DNAME);
+	else if (!strcasecmp(s, "SINK"    )) return(kDNSServiceType_SINK);
+	else if (!strcasecmp(s, "OPT"     )) return(kDNSServiceType_OPT);
+	else if (!strcasecmp(s, "TKEY"    )) return(kDNSServiceType_TKEY);
+	else if (!strcasecmp(s, "TSIG"    )) return(kDNSServiceType_TSIG);
+	else if (!strcasecmp(s, "IXFR"    )) return(kDNSServiceType_IXFR);
+	else if (!strcasecmp(s, "AXFR"    )) return(kDNSServiceType_AXFR);
+	else if (!strcasecmp(s, "MAILB"   )) return(kDNSServiceType_MAILB);
+	else if (!strcasecmp(s, "MAILA"   )) return(kDNSServiceType_MAILA);
+	else if (!strcasecmp(s, "ANY"     )) return(kDNSServiceType_ANY);
+	else                                 return(atoi(s));
+	}
+
 //*************************************************************************************************************
 // Sample callback functions for each of the operation types
 
 static void printtimestamp(void)
 	{
-	struct timeval tv;
 	struct tm tm;
+	int ms;
+#ifdef _WIN32
+	SYSTEMTIME sysTime;
+	time_t uct = time(NULL);
+	tm = *localtime(&uct);
+	GetLocalTime(&sysTime);
+	ms = sysTime.wMilliseconds;
+#else
+	struct timeval tv;
 	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);
+	ms = tv.tv_usec/1000;
+#endif
+	printf("%2d:%02d:%02d.%03d  ", tm.tm_hour, tm.tm_min, tm.tm_sec, ms);
 	}
 
 #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)
+static const char *GetNextLabel(const char *cstr, char label[64])
 	{
-	(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");
+	char *ptr = label;
+	while (*cstr && *cstr != '.')								// While we have characters in the label...
+		{
+		char c = *cstr++;
+		if (c == '\\')
+			{
+			c = *cstr++;
+			if (isdigit(cstr[-1]) && isdigit(cstr[0]) && isdigit(cstr[1]))
+				{
+				int v0 = cstr[-1] - '0';						// then interpret as three-digit decimal
+				int v1 = cstr[ 0] - '0';
+				int v2 = cstr[ 1] - '0';
+				int val = v0 * 100 + v1 * 10 + v2;
+				if (val <= 255) { c = (char)val; cstr += 2; }	// If valid three-digit decimal value, use it
+				}
+			}
+		*ptr++ = c;
+		if (ptr >= label+64) return(NULL);
+		}
+	if (*cstr) cstr++;											// Skip over the trailing dot (if present)
+	*ptr++ = 0;
+	return(cstr);
 	}
 
-static void browsedom_reply(DNSServiceRef client, DNSServiceFlags flags, uint32_t interface,
+static void DNSSD_API enum_reply(DNSServiceRef client, DNSServiceFlags flags, uint32_t ifIndex,
 	DNSServiceErrorType errorCode, const char *replyDomain, void *context)
 	{
+	int labels = 0, depth = 0, i, initial = 0;
+	char text[64];
+	const char *label[128];
+	
 	(void)client;       // Unused
-	(void)interface;    // Unused
+	(void)ifIndex;      // Unused
 	(void)errorCode;    // Unused
 	(void)context;      // Unused
+	
+	if (!*replyDomain) return;
+
+	// 1. Print the header
+	if (num_printed++ == 0) printf("Timestamp     Recommended %s domain\n", operation == 'E' ? "Registration" : "Browsing");
 	printtimestamp();
-	printf("Recommended Browsing Domain %s %s", replyDomain, DomainMsg(flags));
-	if (flags) printf(" Flags: %X", flags);
+	printf("%-10s", DomainMsg(flags));
+	printf("%-8s", (flags & kDNSServiceFlagsMoreComing) ? "(More)" : "");
+	flags &= ~kDNSServiceFlagsMoreComing;
+	flags &= ~kDNSServiceFlagsAdd;
+	flags &= ~kDNSServiceFlagsDefault;
+	if (flags) printf("Flags: %4X  ", flags);
+	else printf("             ");
+	
+	// 2. Count the labels
+	while (*replyDomain)
+		{
+		label[labels++] = replyDomain;
+		replyDomain = GetNextLabel(replyDomain, text);
+		}
+	
+	// 3. Decide if we're going to clump the last two or three labels (e.g. "apple.com", or "nicta.com.au")
+	if      (labels >= 3 && replyDomain - label[labels-1] <= 3 && label[labels-1] - label[labels-2] <= 4) initial = 3;
+	else if (labels >= 2 && replyDomain - label[labels-1] <= 4) initial = 2;
+	else initial = 1;
+	labels -= initial;
+
+	// 4. Print the initial one-, two- or three-label clump
+	for (i=0; i<initial; i++)
+		{
+		GetNextLabel(label[labels+i], text);
+		if (i>0) printf(".");
+		printf("%s", text);
+		}
 	printf("\n");
+
+	// 5. Print the remainder of the hierarchy
+	for (depth=0; depth<labels; depth++)
+		{
+		printf("                                             ");
+		for (i=0; i<=depth; i++) printf("- ");
+		GetNextLabel(label[labels-1-depth], text);
+		printf("> %s\n", text);
+		}
 	}
 
-static void browse_reply(DNSServiceRef client, DNSServiceFlags flags, uint32_t interface, DNSServiceErrorType errorCode,
+static void DNSSD_API browse_reply(DNSServiceRef client, DNSServiceFlags flags, uint32_t ifIndex, DNSServiceErrorType errorCode,
 	const char *replyName, const char *replyType, const char *replyDomain, void *context)
 	{
 	char *op = (flags & kDNSServiceFlagsAdd) ? "Add" : "Rmv";
 	(void)client;       // Unused
-	(void)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);
+	printf("%s%6X%3d %-24s %-24s %s\n", op, flags, ifIndex, replyDomain, replyType, replyName);
 	}
 
-static void resolve_reply(DNSServiceRef client, DNSServiceFlags flags, uint32_t interface, DNSServiceErrorType errorCode,
+static void DNSSD_API resolve_reply(DNSServiceRef client, DNSServiceFlags flags, uint32_t ifIndex, DNSServiceErrorType errorCode,
 	const char *fullname, const char *hosttarget, uint16_t opaqueport, uint16_t txtLen, const char *txtRecord, void *context)
 	{
 	const char *src = txtRecord;
@@ -155,8 +289,9 @@ static void resolve_reply(DNSServiceRef client, DNSServiceFlags flags, uint32_t
 	uint16_t PortAsNumber = ((uint16_t)port.b[0]) << 8 | port.b[1];
 
 	(void)client;       // Unused
-	(void)interface;    // Unused
+	(void)ifIndex;      // Unused
 	(void)errorCode;    // Unused
+	(void)txtLen;       // Unused
 	(void)context;      // Unused
 
 	printtimestamp();
@@ -195,7 +330,7 @@ static void resolve_reply(DNSServiceRef client, DNSServiceFlags flags, uint32_t
 
 static void myTimerCallBack(void)
 	{
-	DNSServiceErrorType err;
+	DNSServiceErrorType err = kDNSServiceErr_Unknown;
 
 	switch (operation)
 		{
@@ -204,11 +339,11 @@ static void myTimerCallBack(void)
 			switch (addtest)
 				{
 				case 0: printf("Adding Test HINFO record\n");
-						err = DNSServiceAddRecord(client, &record, 0, T_HINFO, sizeof(myhinfo9), &myhinfo9[0], 120);
+						err = DNSServiceAddRecord(client, &record, 0, kDNSServiceType_HINFO, sizeof(myhinfoW), &myhinfoW[0], 0);
 						addtest = 1;
 						break;
 				case 1: printf("Updating Test HINFO record\n");
-						err = DNSServiceUpdateRecord(client, record, 0, sizeof(myhinfoX), &myhinfoX[0], 120);
+						err = DNSServiceUpdateRecord(client, record, 0, sizeof(myhinfoX), &myhinfoX[0], 0);
 						addtest = 2;
 						break;
 				case 2: printf("Removing Test HINFO record\n");
@@ -226,14 +361,14 @@ static void myTimerCallBack(void)
 			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);
+			err = DNSServiceUpdateRecord(client, NULL, 0, 1+updatetest[0], &updatetest[0], 0);
 			}
 			break;
 
 		case 'N':
 			{
 			printf("Adding big NULL record\n");
-			err = DNSServiceAddRecord(client, &record, 0, T_NULL, sizeof(bigNULL), &bigNULL[0], 120);
+			err = DNSServiceAddRecord(client, &record, 0, kDNSServiceType_NULL, sizeof(bigNULL), &bigNULL[0], 0);
 			timeOut = LONG_TIME;
 			}
 			break;
@@ -246,7 +381,7 @@ static void myTimerCallBack(void)
 		}
 	}
 
-static void reg_reply(DNSServiceRef client, DNSServiceFlags flags, DNSServiceErrorType errorCode,
+static void DNSSD_API reg_reply(DNSServiceRef client, DNSServiceFlags flags, DNSServiceErrorType errorCode,
 	const char *name, const char *regtype, const char *domain, void *context)
 	{
 	(void)client;   // Unused
@@ -264,17 +399,33 @@ static void reg_reply(DNSServiceRef client, DNSServiceFlags flags, DNSServiceErr
 	if (operation == 'A' || operation == 'U' || operation == 'N') timeOut = 5;
 	}
 
-void qr_reply(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode,
+static void DNSSD_API qr_reply(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t ifIndex, DNSServiceErrorType errorCode,
 	const char *fullname, uint16_t rrtype, uint16_t rrclass, uint16_t rdlen, const void *rdata, uint32_t ttl, void *context)
 	{
-	const unsigned char *rd = rdata;
+	char *op = (flags & kDNSServiceFlagsAdd) ? "Add" : "Rmv";
+	const unsigned char *rd  = rdata;
+	const unsigned char *end = (const unsigned char *) rdata + rdlen;
 	char rdb[1000];
+	char *p = rdb;
+	const char * const lim = rdb + sizeof(rdb);
+
+	(void)sdRef;    // Unused
+	(void)flags;    // Unused
+	(void)ifIndex;  // Unused
+	(void)errorCode;// Unused
+	(void)ttl;      // Unused
+	(void)context;  // Unused
+
 	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;
+		case kDNSServiceType_A: sprintf(rdb, "%d.%d.%d.%d", rd[0], rd[1], rd[2], rd[3]); break;
+		default :	p += snprintf(p, lim-p, "%d bytes%s", rdlen, rdlen ? ":" : "");
+					while (rd < end && p < lim) p += snprintf(p, lim-p, " %02X", *rd++);
+					break;
 		}
-	printf("%-30s%4d%4d  %s\n", fullname, rrtype, rrclass, rdb);
+	if (num_printed++ == 0) printf("Timestamp     A/R Flags if %-30s%4s%4s Rdata\n", "Name", "T", "C");
+	printtimestamp();
+	printf("%s%6X%3d %-30s%4d%4d %s\n", op, flags, ifIndex, fullname, rrtype, rrclass, rdb);
 	}
 
 //*************************************************************************************************************
@@ -282,11 +433,14 @@ void qr_reply(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceInde
 
 static void HandleEvents(void)
 	{
-	int dns_sd_fd = DNSServiceRefSockFD(client);
+	int dns_sd_fd  = client  ? DNSServiceRefSockFD(client ) : -1;
+	int dns_sd_fd2 = client2 ? DNSServiceRefSockFD(client2) : -1;
 	int nfds = dns_sd_fd + 1;
 	fd_set readfds;
 	struct timeval tv;
 	int result;
+	
+	if (dns_sd_fd2 > dns_sd_fd) nfds = dns_sd_fd2 + 1;
 
 	while (!stopNow)
 		{
@@ -296,7 +450,8 @@ static void HandleEvents(void)
 		FD_ZERO(&readfds);
 
 		// 2. Add the fd for our client(s) to the fd_set
-		FD_SET(dns_sd_fd, &readfds);
+		if (client ) FD_SET(dns_sd_fd , &readfds);
+		if (client2) FD_SET(dns_sd_fd2, &readfds);
 
 		// 3. Set up the timeout.
 		tv.tv_sec = timeOut;
@@ -305,7 +460,10 @@ static void HandleEvents(void)
 		result = select(nfds, &readfds, (fd_set*)NULL, (fd_set*)NULL, &tv);
 		if (result > 0)
 			{
-			if (FD_ISSET(dns_sd_fd, &readfds)) DNSServiceProcessResult(client);
+			DNSServiceErrorType err = kDNSServiceErr_NoError;
+			if      (client  && FD_ISSET(dns_sd_fd , &readfds)) err = DNSServiceProcessResult(client );
+			else if (client2 && FD_ISSET(dns_sd_fd2, &readfds)) err = DNSServiceProcessResult(client2);
+			if (err) { fprintf(stderr, "DNSServiceProcessResult returned %d\n", err); stopNow = 1; }
 			}
 		else if (result == 0)
 			myTimerCallBack();
@@ -317,24 +475,114 @@ static void HandleEvents(void)
 		}
 	}
 
+static int getfirstoption( int argc, char **argv, const char *optstr, int *pOptInd)
+// Return the recognized option in optstr and the option index of the next arg.
+#if NOT_HAVE_GETOPT
+	{
+	int	i;
+	for ( i=1; i < argc; i++)
+		{
+		if ( argv[i][0] == '-' && &argv[i][1] && 
+			 NULL != strchr( optstr, argv[i][1]))
+			{
+			*pOptInd = i + 1;
+			return argv[i][1];
+			}
+		}
+	return -1;
+	}
+#else
+	{
+	int	operation = getopt(argc, (char * const *)argv, optstr);
+	*pOptInd = optind;
+	return operation;
+	}
+#endif
+
+static void DNSSD_API MyRegisterRecordCallback(DNSServiceRef service, DNSRecordRef record, DNSServiceFlags flags,
+    DNSServiceErrorType errorCode, void * context)
+	{
+	char *name = (char *)context;
+	
+	(void)service;	// Unused
+	(void)record;	// Unused
+	(void)flags;	// Unused
+	
+	printf("Got a reply for %s: ", name);
+	switch (errorCode)
+		{
+		case kDNSServiceErr_NoError:      printf("Name now registered and active\n"); break;
+		case kDNSServiceErr_NameConflict: printf("Name in use, please choose another\n"); exit(-1);
+		default:                          printf("Error %d\n", errorCode); return;
+		}
+	}
+
+static DNSServiceErrorType RegisterProxyAddressRecord(DNSServiceRef *sdRef, const char *host, const char *ip)
+	{
+	unsigned long addr = inet_addr(ip);
+	DNSServiceErrorType err = DNSServiceCreateConnection(sdRef);
+	if (err) { fprintf(stderr, "DNSServiceCreateConnection returned %d\n", err); return(err); }
+	return(DNSServiceRegisterRecord(*sdRef, &record, kDNSServiceFlagsUnique, kDNSServiceInterfaceIndexAny, host,
+		kDNSServiceType_A, kDNSServiceClass_IN, sizeof(addr), &addr, 240, MyRegisterRecordCallback, (void*)host));
+	}
+
+static DNSServiceErrorType RegisterService(DNSServiceRef *sdRef,
+	const char *nam, const char *typ, const char *dom, const char *host, const char *port, int argc, char **argv)
+	{
+	uint16_t PortAsNumber = atoi(port);
+	Opaque16 registerPort = { { PortAsNumber >> 8, PortAsNumber & 0xFF } };
+	char txt[2048] = "";
+	char *ptr = txt;
+	int i;
+	
+	if (nam[0] == '.' && nam[1] == 0) nam = "";   // We allow '.' on the command line as a synonym for empty string
+	if (dom[0] == '.' && dom[1] == 0) dom = "";   // We allow '.' on the command line as a synonym for empty string
+	
+	for (i = 0; i < argc; i++)
+		{
+		char *len = ptr++;
+		*len = strlen(argv[i]);
+		strcpy(ptr, argv[i]);
+		ptr += *len;
+		}
+	
+	printf("Registering Service %s.%s%s", nam, typ, dom);
+	if (host && *host) printf(" host %s", host);
+	printf(" port %s %s\n", port, txt);
+	return(DNSServiceRegister(sdRef, /* kDNSServiceFlagsAllowRemoteQuery */ 0, 0, nam, typ, dom, host, registerPort.NotAnInteger, ptr-txt, txt, reg_reply, NULL));
+	}
+
 int main(int argc, char **argv)
 	{
+#ifdef _WIN32
+	const char	kFilePathSep = '\\';
+#else
+	const char	kFilePathSep = '/';
+#endif
 	DNSServiceErrorType err;
 	char *dom;
+	int	optind;
+	const char *progname = strrchr(argv[0], kFilePathSep) ? strrchr(argv[0], kFilePathSep) + 1 : argv[0];
+#ifndef NOT_HAVE_SETLINEBUF
 	setlinebuf(stdout);             // Want to see lines as they appear, not block buffered
+#endif
 
 	if (argc < 2) goto Fail;        // Minimum command line is the command name and one argument
-	operation = getopt(argc, (char * const *)argv, "EFBLQRAUNTMI");
+	operation = getfirstoption( argc, argv, "EFBLQRPAUNTMI", &optind);
 	if (operation == -1) goto Fail;
 
 	switch (operation)
 		{
 		case 'E':	printf("Looking for recommended registration domains:\n");
-					err = DNSServiceEnumerateDomains(&client, kDNSServiceFlagsRegistrationDomains, 0, regdom_reply, NULL);
+					err = DNSServiceEnumerateDomains(&client, kDNSServiceFlagsRegistrationDomains, 0, enum_reply, NULL);
 					break;
 
 		case 'F':	printf("Looking for recommended browsing domains:\n");
-					err = DNSServiceEnumerateDomains(&client, kDNSServiceFlagsBrowseDomains, 0, browsedom_reply, NULL);
+					err = DNSServiceEnumerateDomains(&client, kDNSServiceFlagsBrowseDomains, 0, enum_reply, NULL);
+					//enum_reply(client, kDNSServiceFlagsAdd, 0, 0, "nicta.com.au.", NULL);
+					//enum_reply(client, kDNSServiceFlagsAdd, 0, 0, "rendezvous.nicta.com.au.", NULL);
+					//enum_reply(client, kDNSServiceFlagsAdd, 0, 0, "ibm.com.", NULL);
+					//enum_reply(client, kDNSServiceFlagsAdd, 0, 0, "dns-sd.ibm.com.", NULL);
 					break;
 
 		case 'B':	if (argc < optind+1) goto Fail;
@@ -352,37 +600,23 @@ int main(int argc, char **argv)
 					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;
-						}
+					err = RegisterService(&client, argv[optind+0], argv[optind+1], argv[optind+2], NULL, argv[optind+3], argc-(optind+4), argv+(optind+4));
+					break;
 
-					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);
+		case 'P':	if (argc < optind+6) goto Fail;
+					err = RegisterProxyAddressRecord(&client2, argv[optind+4], argv[optind+5]);
+					if (err) break;
+					err = RegisterService(&client, argv[optind+0], argv[optind+1], argv[optind+2], argv[optind+4], argv[optind+3], argc-(optind+6), argv+(optind+6));
 					break;
-					}
 
 		case 'Q':	{
+					uint16_t rrtype, rrclass;
+					DNSServiceFlags flags = 0;
 					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);
+					rrtype = (argc <= optind+1) ? kDNSServiceType_A  : GetRRType(argv[optind+1]);
+					rrclass = (argc <= optind+2) ? kDNSServiceClass_IN : atoi(argv[optind+2]);
+					if (rrtype == kDNSServiceType_TXT || rrtype == kDNSServiceType_PTR) flags |= kDNSServiceFlagsLongLivedQuery;
+					err = DNSServiceQueryRecord(&client, flags, 0, argv[optind+0], rrtype, rrclass, qr_reply, NULL);
 					break;
 					}
 
@@ -414,7 +648,7 @@ int main(int argc, char **argv)
 					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);
+					if (!err) err = DNSServiceAddRecord(client, &record, 0, kDNSServiceType_TXT, sizeof(TXT2)-1, TXT2, 0);
 					break;
 					}
 
@@ -424,7 +658,7 @@ int main(int argc, char **argv)
 					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);
+					if (!err) err = DNSServiceUpdateRecord(client, NULL, 0, sizeof(TXT)-1, TXT, 0);
 					break;
 					}
 
@@ -435,21 +669,23 @@ int main(int argc, char **argv)
 	HandleEvents();
 
 	// Be sure to deallocate the DNSServiceRef when you're finished
-	DNSServiceRefDeallocate(client);
+	if (client ) DNSServiceRefDeallocate(client );
+	if (client2) DNSServiceRefDeallocate(client2);
 	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]);
+	fprintf(stderr, "%s -E                  (Enumerate recommended registration domains)\n", progname);
+	fprintf(stderr, "%s -F                      (Enumerate recommended browsing domains)\n", progname);
+	fprintf(stderr, "%s -B        <Type> <Domain>        (Browse for services instances)\n", progname);
+	fprintf(stderr, "%s -L <Name> <Type> <Domain>           (Look up a service instance)\n", progname);
+	fprintf(stderr, "%s -R <Name> <Type> <Domain> <Port> [<TXT>...] (Register a service)\n", progname);
+	fprintf(stderr, "%s -P <Name> <Type> <Domain> <Port> <Host> <IP> [<TXT>...]  (Proxy)\n", progname);
+	fprintf(stderr, "%s -Q <FQDN> <rrtype> <rrclass> (Generic query for any record type)\n", progname);
+	fprintf(stderr, "%s -A                      (Test Adding/Updating/Deleting a record)\n", progname);
+	fprintf(stderr, "%s -U                                  (Test updating a TXT record)\n", progname);
+	fprintf(stderr, "%s -N                             (Test adding a large NULL record)\n", progname);
+	fprintf(stderr, "%s -T                            (Test creating a large TXT record)\n", progname);
+	fprintf(stderr, "%s -M      (Test creating a registration with multiple TXT records)\n", progname);
+	fprintf(stderr, "%s -I   (Test registering and then immediately updating TXT record)\n", progname);
 	return 0;
 	}
diff --git a/Makefile b/Makefile
index 6535aa1..20adec5 100644
--- a/Makefile
+++ b/Makefile
@@ -16,7 +16,7 @@
 
 include /Developer/Makefiles/pb_makefiles/platform.make
 
-MVERS = "mDNSResponder-66.3"
+MVERS = "mDNSResponder-87"
 
 install:
 	cd "$(SRCROOT)/mDNSMacOSX"; xcodebuild install     OBJROOT=$(OBJROOT) SYMROOT=$(SYMROOT) DSTROOT=$(DSTROOT) MVERS=$(MVERS)
diff --git a/README.txt b/README.txt
index fa70ecf..5f17866 100644
--- a/README.txt
+++ b/README.txt
@@ -141,3 +141,26 @@ 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.
+
+
+Compiling on Older C Compilers
+------------------------------
+
+We go to some lengths to make the code portable, but //-style comments
+are one of the modern conveniences we can't live without.
+
+If your C compiler doesn't understand these comments, you can transform
+them into classical K&R /* style */ comments with a quick GREP
+search-and-replace pattern.
+
+In BBEdit on the Mac:
+1. Open the "Find" dialog window and make sure "Use Grep" is selected
+2. Search For  : ([^:])//(.*)
+3. Replace With: \1/*\2 */
+4. Drag your mDNSResponder source code folder to the Multi-File search pane
+5. Click "Replace All"
+
+For the more command-line oriented, cd into your mDNSResponder source code
+directory and execute the following command (all one line):
+
+find mDNSResponder \( -name \*.c\* -or -name \*.h \) -exec sed -i .orig -e 's,^//\(.*\),/*\1 */,' -e '/\/\*/\!s,\([^:]\)//\(.*\),\1/*\2 */,' {} \;
diff --git a/mDNSCore/DNSCommon.c b/mDNSCore/DNSCommon.c
index 6e317a9..13319c1 100644
--- a/mDNSCore/DNSCommon.c
+++ b/mDNSCore/DNSCommon.c
@@ -3,8 +3,6 @@
  *
  * @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
@@ -25,6 +23,135 @@
     Change History (most recent first):
 
 $Log: DNSCommon.c,v $
+Revision 1.74  2004/12/09 22:49:15  ksekar
+<rdar://problem/3913653> Wide-Area Goodbyes broken
+
+Revision 1.73  2004/12/07 22:49:06  cheshire
+<rdar://problem/3908850> BIND doesn't like zero-length rdata
+
+Revision 1.72  2004/12/06 21:15:20  ksekar
+<rdar://problem/3884386> mDNSResponder crashed in CheckServiceRegistrations
+
+Revision 1.71  2004/12/04 02:12:45  cheshire
+<rdar://problem/3517236> mDNSResponder puts LargeCacheRecord on the stack
+
+Revision 1.70  2004/12/03 19:52:44  ksekar
+Use PutResourceRecordTTLJumbo for putDeletionRecord()
+
+Revision 1.69  2004/12/03 07:20:50  ksekar
+<rdar://problem/3674208> Wide-Area: Registration of large TXT record fails
+
+Revision 1.68  2004/11/24 00:10:43  cheshire
+<rdar://problem/3869241> For unicast operations, verify that service types are legal
+
+Revision 1.67  2004/10/26 03:52:02  cheshire
+Update checkin comments
+
+Revision 1.66  2004/10/23 01:16:00  cheshire
+<rdar://problem/3851677> uDNS operations not always reliable on multi-homed hosts
+
+Revision 1.65  2004/10/20 02:15:09  cheshire
+Add case in GetRRDisplayString() to display NS rdata
+
+Revision 1.64  2004/10/13 00:24:02  cheshire
+Disable "array is too small to include a terminating null character" warning on Windows
+
+Revision 1.63  2004/10/10 06:57:14  cheshire
+Change definition of "localdomain" to make code compile a little smaller
+
+Revision 1.62  2004/10/06 01:44:19  cheshire
+<rdar://problem/3813936> Resolving too quickly sometimes returns stale TXT record
+
+Revision 1.61  2004/09/30 00:24:56  ksekar
+<rdar://problem/3695802> Dynamically update default registration domains on config change
+
+Revision 1.60  2004/09/27 23:25:30  cheshire
+Fix compiler warning: soa.serial is signed, not unsigned
+
+Revision 1.59  2004/09/27 22:53:45  ksekar
+Fixed getLargeResourceRecord for SOA rdata.
+
+Revision 1.58  2004/09/25 02:41:39  cheshire
+<rdar://problem/3637266> Deliver near-pending "remove" events before new "add" events
+
+Revision 1.57  2004/09/25 02:24:27  cheshire
+Removed unused rr->UseCount
+
+Revision 1.56  2004/09/24 20:57:39  cheshire
+<rdar://problem/3680902> Eliminate inappropriate casts that cause misaligned-address errors
+
+Revision 1.55  2004/09/17 01:08:48  cheshire
+Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
+  The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
+  declared in that file are ONLY appropriate to single-address-space embedded applications.
+  For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
+
+Revision 1.54  2004/09/17 00:49:51  cheshire
+Get rid of now-unused GetResourceRecord -- the correct (safe) routine to use
+is GetLargeResourceRecord
+
+Revision 1.53  2004/09/17 00:31:51  cheshire
+For consistency with ipv6, renamed rdata field 'ip' to 'ipv4'
+
+Revision 1.52  2004/09/17 00:19:10  cheshire
+For consistency with AllDNSLinkGroupv6, rename AllDNSLinkGroup to AllDNSLinkGroupv4
+
+Revision 1.51  2004/09/16 02:29:39  cheshire
+Moved mDNS_Lock/mDNS_Unlock to DNSCommon.c; Added necessary locking around
+uDNS_ReceiveMsg, uDNS_StartQuery, uDNS_UpdateRecord, uDNS_RegisterService
+
+Revision 1.50  2004/09/16 01:58:14  cheshire
+Fix compiler warnings
+
+Revision 1.49  2004/09/14 23:42:35  cheshire
+<rdar://problem/3801296> Need to seed random number generator from platform-layer data
+
+Revision 1.48  2004/09/14 23:27:46  cheshire
+Fix compile errors
+
+Revision 1.47  2004/08/25 02:50:04  cheshire
+<rdar://problem/3561220> Browses are no longer piggybacking on other browses
+Make mDNSSameAddress() recognise that two mDNSAddrType_None addresses are necessarily equal
+
+Revision 1.46  2004/08/18 17:35:40  ksekar
+<rdar://problem/3651443>: Feature #9586: Need support for Legacy NAT gateways
+
+Revision 1.45  2004/08/15 18:26:00  cheshire
+Don't use strcpy() on "struct domainname" objects; use AssignDomainName() instead
+(A "struct domainname" is a collection of packed pascal strings, not a C string.)
+
+Revision 1.44  2004/08/13 23:46:58  cheshire
+"asyncronous" -> "asynchronous"
+
+Revision 1.43  2004/08/12 02:55:46  ksekar
+Fix param order error moving putPrereqNameNotInUse from uDNS.c using
+ustrcpy macro to DNSCommon.c using mDNSPlatformStrCopy().
+
+Revision 1.42  2004/08/10 23:19:14  ksekar
+<rdar://problem/3722542>: DNS Extension daemon for Wide Area Rendezvous
+Moved routines/constants to allow extern access for garbage collection daemon
+
+Revision 1.41  2004/08/10 01:10:01  cheshire
+<rdar://problem/3588761> Current method of doing subtypes causes name collisions
+Minor revision from Roger Pantos
+
+Revision 1.40  2004/08/04 22:10:46  cheshire
+<rdar://problem/3588761> Current method of doing subtypes causes name collisions
+Change to use "._sub." instead of ".s." to mark subtypes.
+
+Revision 1.39  2004/07/13 21:24:24  rpantos
+Fix for <rdar://problem/3701120>.
+
+Revision 1.38  2004/06/18 21:08:58  cheshire
+<rdar://problem/3540040> Applications are registering invalid records
+Attempts to create domain names like "www..apple.com." now logged to aid debugging
+
+Revision 1.37  2004/06/18 20:25:42  cheshire
+<rdar://problem/3488547> Add a syslog message if someone tries to use "local.arpa".
+
+Revision 1.36  2004/06/18 19:09:59  cheshire
+<rdar://problem/3588761> Current method of doing subtypes causes name collisions
+
 Revision 1.35  2004/06/05 00:14:44  cheshire
 Fix signed/unsigned and other compiler warnings
 
@@ -105,9 +232,9 @@ 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
+Added an asynchronous state machine mechanism to uDNS.c, including
 calls to find the parent zone for a domain name.  Changes include code
-in repository previously dissabled via "#if 0 //incomplete".  Codepath
+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
@@ -142,7 +269,7 @@ Revision 1.1  2003/12/13 03:05:27  ksekar
 
  */
 
-// Set mDNS_InstantiateInlines to tell mDNSClientAPI.h to instantiate inline functions, if necessary
+// Set mDNS_InstantiateInlines to tell mDNSEmbeddedAPI.h to instantiate inline functions, if necessary
 #define mDNS_InstantiateInlines 1
 #include "DNSCommon.h"
 
@@ -152,6 +279,9 @@ Revision 1.1  2003/12/13 03:05:27  ksekar
 	// 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)
+	// Disable "array is too small to include a terminating null character" warning
+	// -- domain labels have an initial length byte, not a terminating null character
+	#pragma warning(disable:4295)
 #endif
 
 // ***************************************************************************
@@ -169,7 +299,7 @@ mDNSexport DNameListElem *mDNS_CopyDNameList(const DNameListElem *orig)
 		{
 		newelem = (DNameListElem*)mDNSPlatformMemAllocate(sizeof(DNameListElem));
 		if (!newelem) { LogMsg("ERROR: malloc"); return mDNSNULL; }
-		mDNSPlatformStrCopy(ptr->name.c, newelem->name.c);
+		AssignDomainName(newelem->name, ptr->name);
 		newelem->next = copy;
 		copy = newelem;
 		}
@@ -194,6 +324,19 @@ mDNSexport void mDNS_FreeDNameList(DNameListElem *list)
 #pragma mark - General Utility Functions
 #endif
 
+// return true for RFC1918 private addresses
+mDNSexport mDNSBool IsPrivateV4Addr(mDNSAddr *addr)
+	{
+	mDNSu8 *b;
+
+	if (addr->type != mDNSAddrType_IPv4) return mDNSfalse;
+	b = addr->ip.v4.b;
+		
+	return ((b[0] == 10) ||                              // 10/8 prefix
+			(b[0] == 172 && b[1] > 15 && b[1] < 32) ||   // 172.16/12 
+			(b[0] == 192 && b[1] == 168));               // 192.168/16
+	}
+
 mDNSexport const NetworkInterfaceInfo *GetFirstActiveInterface(const NetworkInterfaceInfo *intf)
 	{
 	while (intf && !intf->InterfaceActive) intf = intf->next;
@@ -237,24 +380,27 @@ mDNSexport char *DNSTypeName(mDNSu16 rrtype)
 		}
 	}
 
-mDNSexport char *GetRRDisplayString_rdb(mDNS *const m, const ResourceRecord *rr, RDataBody *rd)
+mDNSexport char *GetRRDisplayString_rdb(const ResourceRecord *rr, RDataBody *rd, char *buffer)
 	{
-	char *ptr = m->MsgBuffer;
-	mDNSu32 length = mDNS_snprintf(m->MsgBuffer, 79, "%4d %##s %s ", rr->rdlength, rr->name.c, DNSTypeName(rr->rrtype));
+	char *ptr = buffer;
+	mDNSu32 length = mDNS_snprintf(buffer, 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_A:	mDNS_snprintf(buffer+length, 79-length, "%.4a", &rd->ipv4);          break;
+
+		case kDNSType_NS:	// Same as PTR
 		case kDNSType_CNAME:// Same as PTR
-		case kDNSType_PTR:	mDNS_snprintf(m->MsgBuffer+length, 79-length, "%##s", &rd->name);       break;
+		case kDNSType_PTR:	mDNS_snprintf(buffer+length, 79-length, "%##s", rd->name.c);       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;
+		case kDNSType_TXT:  mDNS_snprintf(buffer+length, 79-length, "%#s", rd->txt.c);         break;
+
+		case kDNSType_AAAA:	mDNS_snprintf(buffer+length, 79-length, "%.16a", &rd->ipv6);       break;
+		case kDNSType_SRV:	mDNS_snprintf(buffer+length, 79-length, "%##s", rd->srv.target.c); break;
+		default:			mDNS_snprintf(buffer+length, 79-length, "RDLen %d: %s", rr->rdlength, rd->data);  break;
 		}
-	for (ptr = m->MsgBuffer; *ptr; ptr++) if (*ptr < ' ') *ptr='.';
-	return(m->MsgBuffer);
+	for (ptr = buffer; *ptr; ptr++) if (*ptr < ' ') *ptr='.';
+	return(buffer);
 	}
 
 mDNSexport mDNSu32 mDNSRandom(mDNSu32 max)
@@ -262,7 +408,12 @@ mDNSexport mDNSu32 mDNSRandom(mDNSu32 max)
 	static mDNSu32 seed = 0;
 	mDNSu32 mask = 1;
 
-	if (!seed) seed = (mDNSu32)mDNSPlatformTimeNow();
+	if (!seed)
+		{
+		int i;
+		seed = mDNSPlatformRandomSeed();				// Pick an initial seed
+		for (i=0; i<100; i++) seed = seed * 21 + 1;		// And mix it up a bit
+		}
 	while (mask < max) mask = (mask << 1) | 1;
 	do seed = seed * 21 + 1; while ((seed & mask) > max);
 	return (seed & mask);
@@ -274,6 +425,7 @@ mDNSexport mDNSBool mDNSSameAddress(const mDNSAddr *ip1, const mDNSAddr *ip2)
 		{
 		switch (ip1->type)
 			{
+			case mDNSAddrType_None : return(mDNStrue); // Empty addresses have no data and are therefore always equal
 			case mDNSAddrType_IPv4 : return(mDNSBool)(mDNSSameIPv4Address(ip1->ip.v4, ip2->ip.v4));
 			case mDNSAddrType_IPv6 : return(mDNSBool)(mDNSSameIPv6Address(ip1->ip.v6, ip2->ip.v6));
 			}
@@ -285,7 +437,7 @@ mDNSexport mDNSBool mDNSAddrIsDNSMulticast(const mDNSAddr *ip)
 	{
 	switch(ip->type)
 		{
-		case mDNSAddrType_IPv4: return(mDNSBool)(ip->ip.v4.NotAnInteger == AllDNSLinkGroup.NotAnInteger);
+		case mDNSAddrType_IPv4: return(mDNSBool)(ip->ip.v4.NotAnInteger == AllDNSLinkGroupv4.NotAnInteger);
 		case mDNSAddrType_IPv6: return(mDNSBool)(ip->ip.v6.l[0] == AllDNSLinkGroupv6.l[0] &&
 												 ip->ip.v6.l[1] == AllDNSLinkGroupv6.l[1] &&
 												 ip->ip.v6.l[2] == AllDNSLinkGroupv6.l[2] &&
@@ -429,13 +581,15 @@ mDNSexport mDNSu8 *AppendLiteralLabelString(domainname *const name, const char *
 // 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)
+mDNSexport mDNSu8 *AppendDNSNameString(domainname *const name, const char *cstring)
 	{
+	const char   *cstr      = cstring;
 	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
+		if (*cstr == '.') { LogMsg("AppendDNSNameString: Illegal empty label in name \"%s\"", cstring); return(mDNSNULL); }
 		while (*cstr && *cstr != '.' && ptr < lim)					// While we have characters in the label...
 			{
 			mDNSu8 c = (mDNSu8)*cstr++;								// Read the character
@@ -605,15 +759,6 @@ mDNSexport void ConvertUTF8PstringToRFC1034HostLabel(const mDNSu8 UTF8Name[], do
 	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)
 	{
@@ -624,15 +769,31 @@ mDNSexport mDNSu8 *ConstructServiceName(domainname *const fqdn,
 
 	// In the case where there is no name (and ONLY in that case),
 	// a single-label subtype is allowed as the first label of a three-part "type"
-	if (!name)
+	if (!name && type)
 		{
-		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)
+		const mDNSu8 *s0 = type->c;
+		if (s0[0] && s0[0] < 0x40)		// If legal first label (at least one character, and no more than 63)
 			{
-			name = (domainlabel *)type;
-			type = (domainname  *)s2;
+			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);
+					}
+				}
 			}
 		}
 
@@ -648,13 +809,11 @@ mDNSexport mDNSu8 *ConstructServiceName(domainname *const fqdn,
 
 	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 (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] != '_')
@@ -665,13 +824,15 @@ mDNSexport mDNSu8 *ConstructServiceName(domainname *const fqdn,
 	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; }
+		{ 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;
 	if (!domain->c[0]) { errormsg="Service domain must be non-empty"; goto fail; }
+	if (SameDomainName(domain, (domainname*)"\x05" "local" "\x04" "arpa"))
+		{ errormsg="Illegal domain \"local.arpa.\" Use \"local.\" (or empty string)"; goto fail; }
 	dst = AppendDomainName(fqdn, domain);
 	if (!dst) { errormsg="Service domain too long"; goto fail; }
 	return(dst);
@@ -864,6 +1025,14 @@ mDNSexport mDNSBool SameRData(const ResourceRecord *const r1, const ResourceReco
 		}
 	}
 
+mDNSexport mDNSBool SameResourceRecord(ResourceRecord *r1, ResourceRecord *r2)
+	{
+	return (r1->namehash == r2->namehash &&
+			r1->rrtype == r2->rrtype && 
+			SameDomainName(&r1->name, &r2->name) &&
+			SameRData(r1, r2));
+	}
+
 mDNSexport mDNSBool ResourceRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q)
 	{
 	if (rr->InterfaceID &&
@@ -878,11 +1047,11 @@ mDNSexport mDNSBool ResourceRecordAnswersQuestion(const ResourceRecord *const rr
 
 mDNSexport mDNSu16 GetRDLength(const ResourceRecord *const rr, mDNSBool estimate)
 	{
-	RDataBody *rd = &rr->rdata->u;
+	const 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_A:	return(sizeof(rd->ipv4));
 		case kDNSType_CNAME:// Same as PTR
 		case kDNSType_NS:   // Same as PTR
 		case kDNSType_PTR:	return(CompressedDomainNameLength(&rd->name, name));
@@ -903,6 +1072,11 @@ mDNSexport mDNSu16 GetRDLength(const ResourceRecord *const rr, mDNSBool estimate
 mDNSexport mDNSBool ValidateRData(const mDNSu16 rrtype, const mDNSu16 rdlength, const RData *const rd)
 	{
 	mDNSu16 len;
+	// Some (or perhaps all) versions of BIND named (name daemon) don't allow updates
+	// with zero-length rdata, so for consistency we don't allow them for mDNS either.
+	// Otherwise we risk having applications that work with mDNS but not with uDNS.
+	if (!rdlength) return(mDNSfalse);
+
 	switch(rrtype)
 		{
 		case kDNSType_A:	return(rdlength == sizeof(mDNSv4Addr));
@@ -1067,6 +1241,15 @@ mDNSlocal mDNSu8 *putVal16(mDNSu8 *ptr, mDNSu16 val)
 	return ptr + sizeof(mDNSOpaque16);
 	}
 
+mDNSlocal mDNSu8 *putVal32(mDNSu8 *ptr, mDNSu32 val)
+	{
+	ptr[0] = (mDNSu8)((val >> 24) & 0xFF);
+	ptr[1] = (mDNSu8)((val >> 16) & 0xFF);
+	ptr[2] = (mDNSu8)((val >>  8) & 0xFF);
+	ptr[3] = (mDNSu8)((val      ) & 0xFF);
+	return ptr + sizeof(mDNSu32);
+	}
+
 mDNSlocal mDNSu8 *putOptRData(mDNSu8 *ptr, const mDNSu8 *limit, ResourceRecord *rr)
 	{
 	int nput = 0;
@@ -1088,15 +1271,13 @@ mDNSlocal mDNSu8 *putOptRData(mDNSu8 *ptr, const mDNSu8 *limit, ResourceRecord *
 			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);
+			ptr = putVal32(ptr, opt->OptData.llq.lease);
 			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);
+			ptr = putVal32(ptr, opt->OptData.lease);
 			nput += sizeof(mDNSs32);
 			}
 		else { LogMsg("putOptRData - unknown option %d", opt->opt); return mDNSNULL; }
@@ -1174,10 +1355,10 @@ mDNSexport mDNSu8 *putRData(const DNSMessage *const msg, mDNSu8 *ptr, const mDNS
 								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];
+							*ptr++ = rr->rdata->u.ipv4.b[0];
+							*ptr++ = rr->rdata->u.ipv4.b[1];
+							*ptr++ = rr->rdata->u.ipv4.b[2];
+							*ptr++ = rr->rdata->u.ipv4.b[3];
 							return(ptr);
 
 		case kDNSType_CNAME:// Same as PTR
@@ -1212,16 +1393,10 @@ mDNSexport mDNSu8 *putRData(const DNSMessage *const msg, mDNSu8 *ptr, const mDNS
 		}
 	}
 
-mDNSexport mDNSu8 *PutResourceRecordTTL(DNSMessage *const msg, mDNSu8 *ptr, mDNSu16 *count, ResourceRecord *rr, mDNSu32 ttl)
+mDNSexport mDNSu8 *PutResourceRecordTTLWithLimit(DNSMessage *const msg, mDNSu8 *ptr, mDNSu16 *count, ResourceRecord *rr, mDNSu32 ttl, const mDNSu8 *limit)
 	{
 	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)
 		{
@@ -1287,6 +1462,90 @@ mDNSexport mDNSu8 *putQuestion(DNSMessage *const msg, mDNSu8 *ptr, const mDNSu8
 	return(ptr+4);
 	}
 
+// for dynamic updates
+mDNSexport 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 mDNSNULL;		// If we're out-of-space, return NULL
+	*ptr++ = (mDNSu8)(kDNSType_SOA  >> 8);
+	*ptr++ = (mDNSu8)(kDNSType_SOA  &  0xFF);
+	*ptr++ = zoneClass.b[0];
+	*ptr++ = zoneClass.b[1];
+	msg->h.mDNS_numZones++;
+	return ptr;
+	}
+
+// for dynamic updates
+mDNSexport mDNSu8 *putPrereqNameNotInUse(domainname *name, DNSMessage *msg, mDNSu8 *ptr, mDNSu8 *end)
+	{
+	AuthRecord prereq;
+
+	mDNSPlatformMemZero(&prereq, sizeof(AuthRecord));
+	AssignDomainName(prereq.resrec.name, *name);
+	prereq.resrec.rrtype = kDNSQType_ANY;
+	prereq.resrec.rrclass = kDNSClass_NONE;
+	ptr = putEmptyResourceRecord(msg, ptr, end, &msg->h.mDNS_numPrereqs, &prereq);
+	return ptr;
+	}
+
+// for dynamic updates
+mDNSexport mDNSu8 *putDeletionRecord(DNSMessage *msg, mDNSu8 *ptr, ResourceRecord *rr)
+	{
+	mDNSu16 origclass;
+	// deletion: specify record w/ TTL 0, class NONE
+
+	origclass = rr->rrclass;
+	rr->rrclass = kDNSClass_NONE;
+	ptr = PutResourceRecordTTLJumbo(msg, ptr, &msg->h.mDNS_numUpdates, rr, 0);
+	rr->rrclass = origclass;
+	return ptr;
+	}
+
+// for dynamic updates
+mDNSexport mDNSu8 *putDeleteAllRRSets(DNSMessage *msg, mDNSu8 *ptr, const domainname *name)
+	{
+	const mDNSu8 *limit = msg->data + AbsoluteMaxDNSMessageData;;
+	mDNSu16 class = kDNSQClass_ANY;
+	mDNSu16 rrtype = kDNSQType_ANY;
+	
+	ptr = putDomainNameAsLabels(msg, ptr, limit, name);
+	if (!ptr || ptr + 10 >= limit) return mDNSNULL;	// If we're out-of-space, return mDNSNULL
+	ptr[0] = (mDNSu8)(rrtype  >> 8);
+	ptr[1] = (mDNSu8)(rrtype  &  0xFF);
+	ptr[2] = (mDNSu8)(class >> 8);
+	ptr[3] = (mDNSu8)(class &  0xFF);
+	ptr[4] = ptr[5] = ptr[6] = ptr[7] = 0; // zero ttl
+	ptr[8] = ptr[9] = 0; // zero rdlength/rdata
+
+	msg->h.mDNS_numUpdates++;
+	return ptr + 10;
+	}
+
+// for dynamic updates
+mDNSexport mDNSu8 *putUpdateLease(DNSMessage *msg, mDNSu8 *end, mDNSu32 lease)
+	{
+	AuthRecord rr;
+	ResourceRecord *opt = &rr.resrec; 
+	rdataOpt *optRD;
+
+	mDNSPlatformMemZero(&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 = lease;
+	end = PutResourceRecordTTLJumbo(msg, end, &msg->h.numAdditionals, opt, 0);
+	if (!end) { LogMsg("ERROR: putUpdateLease - PutResourceRecordTTL"); return mDNSNULL; }
+
+	return end;
+	}
+
 // ***************************************************************************
 #if COMPILER_LIKES_PRAGMA_MARK
 #pragma mark -
@@ -1418,19 +1677,23 @@ mDNSexport const mDNSu8 *skipResourceRecord(const DNSMessage *msg, const mDNSu8
 	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)
+mDNSexport const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage * const msg, const mDNSu8 *ptr,
+    const mDNSu8 *end, const mDNSInterfaceID InterfaceID, mDNSu8 RecordType, LargeCacheRecord *largecr)
 	{
+	CacheRecord *rr = &largecr->r;
 	mDNSu16 pktrdlength;
+	
+	if (largecr == &m->rec && rr->resrec.RecordType)
+		LogMsg("GetLargeResourceRecord: m->rec appears to be already in use");
 
 	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->TimeRcvd          = m ? m->timenow : 0;
+	rr->DelayDelivery     = 0;
+	rr->NextRequiredQuery = m ? m->timenow : 0;		// Will be updated to the real value when we call SetNextCacheCheckTime()
+	rr->LastUsed          = m ? m->timenow : 0;
 	rr->CRActiveQuestion  = mDNSNULL;
 	rr->UnansweredQueries = 0;
 	rr->LastUnansweredTime= 0;
@@ -1458,21 +1721,19 @@ mDNSexport const mDNSu8 *GetResourceRecord(mDNS *const m, const DNSMessage * con
 		rr->resrec.RecordType |= kDNSRecordTypePacketUniqueMask;
 	ptr += 10;
 	if (ptr + pktrdlength > end) { debugf("GetResourceRecord: RDATA exceeds end of packet"); return(mDNSNULL); }
+	end = ptr + pktrdlength;		// Adjust end to indicate the end of the rdata for this resource record
 
-	if (RDataStorage)
-		rr->resrec.rdata = RDataStorage;
-	else
-		{
-		rr->resrec.rdata = (RData*)&rr->rdatastorage;
-		rr->resrec.rdata->MaxRDLength = sizeof(RDataBody);
-		}
+	rr->resrec.rdata = (RData*)&rr->rdatastorage;
+	rr->resrec.rdata->MaxRDLength = MaximumRDSize;
+
+	if (!RecordType) LogMsg("GetLargeResourceRecord: No RecordType for %##s", rr->resrec.name.c);
 
 	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];
+		case kDNSType_A:	rr->resrec.rdata->u.ipv4.b[0] = ptr[0];
+							rr->resrec.rdata->u.ipv4.b[1] = ptr[1];
+							rr->resrec.rdata->u.ipv4.b[2] = ptr[2];
+							rr->resrec.rdata->u.ipv4.b[3] = ptr[3];
 							break;
 
 		case kDNSType_CNAME:// Same as PTR
@@ -1506,16 +1767,16 @@ mDNSexport const mDNSu8 *GetResourceRecord(mDNS *const m, const DNSMessage * con
 							//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;
+		case kDNSType_SOA:  ptr = getDomainName(msg, ptr, end, &rr->resrec.rdata->u.soa.mname);
+							if (!ptr) { debugf("GetResourceRecord: Malformed SOA RDATA mname"); return mDNSNULL; }
+							ptr = getDomainName(msg, ptr, end, &rr->resrec.rdata->u.soa.rname);
+							if (!ptr) { debugf("GetResourceRecord: Malformed SOA RDATA rname"); return mDNSNULL; }
+			                if (ptr + 0x14 != end) { debugf("GetResourceRecord: Malformed SOA RDATA"); return mDNSNULL; }
+                			rr->resrec.rdata->u.soa.serial  = (mDNSs32) ((mDNSs32)ptr[0x00] << 24 | (mDNSs32)ptr[0x01] << 16 | (mDNSs32)ptr[0x02] << 8 | ptr[0x03]);
+			                rr->resrec.rdata->u.soa.refresh = (mDNSu32) ((mDNSu32)ptr[0x04] << 24 | (mDNSu32)ptr[0x05] << 16 | (mDNSu32)ptr[0x06] << 8 | ptr[0x07]);
+			                rr->resrec.rdata->u.soa.retry   = (mDNSu32) ((mDNSu32)ptr[0x08] << 24 | (mDNSu32)ptr[0x09] << 16 | (mDNSu32)ptr[0x0A] << 8 | ptr[0x0B]);
+			                rr->resrec.rdata->u.soa.expire  = (mDNSu32) ((mDNSu32)ptr[0x0C] << 24 | (mDNSu32)ptr[0x0D] << 16 | (mDNSu32)ptr[0x0E] << 8 | ptr[0x0F]);
+			                rr->resrec.rdata->u.soa.min     = (mDNSu32) ((mDNSu32)ptr[0x10] << 24 | (mDNSu32)ptr[0x11] << 16 | (mDNSu32)ptr[0x12] << 8 | ptr[0x13]);
 			                break;
 
 		case kDNSType_OPT:  getOptRdata(ptr, end, &rr->resrec, pktrdlength); break;
@@ -1597,7 +1858,7 @@ mDNSexport const mDNSu8 *LocateAdditionals(const DNSMessage *const msg, const mD
 #pragma mark - Packet Sending Functions
 #endif
 
-mDNSlocal mStatus sendDNSMessage(const mDNS *const m, DNSMessage *const msg, mDNSu8 *end,
+mDNSexport mStatus mDNSSendDNSMessage(const mDNS *const m, DNSMessage *const msg, mDNSu8 *end,
     mDNSInterfaceID InterfaceID, const mDNSAddr *dst, mDNSIPPort dstport, int sd, uDNS_AuthInfo *authInfo)
 	{
 	mStatus status;
@@ -1654,31 +1915,96 @@ mDNSlocal mStatus sendDNSMessage(const mDNS *const m, DNSMessage *const msg, mDN
 	return(status);
 
 	tcp_error:
-	LogMsg("sendDNSMessage: error sending message over tcp");
+	LogMsg("mDNSSendDNSMessage: 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);
-	}
+// ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - RR List Management & Task Management
+#endif
 
-mDNSexport mStatus mDNSSendDNSMessage(const mDNS *const m, DNSMessage *const msg, mDNSu8 * end,
-	mDNSInterfaceID InterfaceID, const mDNSAddr *dst, mDNSIPPort dstport)
+mDNSexport void mDNS_Lock(mDNS *const m)
 	{
-	return sendDNSMessage(m, msg, end, InterfaceID, dst, dstport, -1, mDNSNULL);
+	// MUST grab the platform lock FIRST!
+	mDNSPlatformLock(m);
+
+	// Normally, mDNS_reentrancy is zero and so is mDNS_busy
+	// However, when we call a client callback mDNS_busy is one, and we increment mDNS_reentrancy too
+	// If that client callback does mDNS API calls, mDNS_reentrancy and mDNS_busy will both be one
+	// If mDNS_busy != mDNS_reentrancy that's a bad sign
+	if (m->mDNS_busy != m->mDNS_reentrancy)
+		LogMsg("mDNS_Lock: Locking failure! mDNS_busy (%ld) != mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
+
+	// If this is an initial entry into the mDNSCore code, set m->timenow
+	// else, if this is a re-entrant entry into the mDNSCore code, m->timenow should already be set
+	if (m->mDNS_busy == 0)
+		{
+		if (m->timenow)
+			LogMsg("mDNS_Lock: m->timenow already set (%ld/%ld)", m->timenow, mDNSPlatformRawTime() + m->timenow_adjust);
+		m->timenow = mDNSPlatformRawTime() + m->timenow_adjust;
+		if (m->timenow == 0) m->timenow = 1;
+		}
+	else if (m->timenow == 0)
+		{
+		LogMsg("mDNS_Lock: m->mDNS_busy is %ld but m->timenow not set", m->mDNS_busy);
+		m->timenow = mDNSPlatformRawTime() + m->timenow_adjust;
+		if (m->timenow == 0) m->timenow = 1;
+		}
+
+	if (m->timenow_last - m->timenow > 0)
+		{
+		m->timenow_adjust += m->timenow_last - m->timenow;
+		LogMsg("mDNSPlatformRawTime went backwards by %ld ticks; setting correction factor to %ld", m->timenow_last - m->timenow, m->timenow_adjust);
+		m->timenow = m->timenow_last;
+		}
+	m->timenow_last = m->timenow;
+
+	// Increment mDNS_busy so we'll recognise re-entrant calls
+	m->mDNS_busy++;
 	}
 
-mDNSexport mStatus mDNSSendSignedDNSMessage(const mDNS *const m, DNSMessage *const msg, mDNSu8 * end,
-    mDNSInterfaceID InterfaceID, const mDNSAddr *dst, mDNSIPPort dstport, uDNS_AuthInfo *authInfo)
+mDNSlocal mDNSs32 GetNextScheduledEvent(const mDNS *const m)
 	{
-	return sendDNSMessage(m, msg, end, InterfaceID, dst, dstport, -1, authInfo);
+	mDNSs32 e = m->timenow + 0x78000000;
+	if (m->mDNSPlatformStatus != mStatus_NoError || m->SleepState) return(e);
+	if (m->NewQuestions)
+		{
+		if (m->NewQuestions->DelayAnswering) e = m->NewQuestions->DelayAnswering;
+		else return(m->timenow);
+		}
+	if (m->NewLocalOnlyQuestions)   return(m->timenow);
+	if (m->NewLocalOnlyRecords)     return(m->timenow);
+	if (m->DiscardLocalOnlyRecords) return(m->timenow);
+	if (m->SuppressSending)         return(m->SuppressSending);
+#ifndef UNICAST_DISABLED
+	if (e - m->uDNS_info.nextevent   > 0) e = m->uDNS_info.nextevent;
+#endif
+	if (e - m->NextCacheCheck        > 0) e = m->NextCacheCheck;
+	if (e - m->NextScheduledQuery    > 0) e = m->NextScheduledQuery;
+	if (e - m->NextScheduledProbe    > 0) e = m->NextScheduledProbe;
+	if (e - m->NextScheduledResponse > 0) e = m->NextScheduledResponse;
+	return(e);
 	}
 
-mDNSexport mStatus mDNSSendSignedDNSMessage_tcp(const mDNS *const m, DNSMessage *const msg, mDNSu8 * end, int sd, uDNS_AuthInfo *authInfo)
+mDNSexport void mDNS_Unlock(mDNS *const m)
 	{
-	if (sd < 0) { LogMsg("mDNSSendDNSMessage_tcp: invalid desciptor %d", sd); return mStatus_UnknownErr; }
-	return sendDNSMessage(m, msg, end, mDNSInterface_Any, &zeroAddr, zeroIPPort, sd, authInfo);
+	// Decrement mDNS_busy
+	m->mDNS_busy--;
+	
+	// Check for locking failures
+	if (m->mDNS_busy != m->mDNS_reentrancy)
+		LogMsg("mDNS_Unlock: Locking failure! mDNS_busy (%ld) != mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
+
+	// If this is a final exit from the mDNSCore code, set m->NextScheduledEvent and clear m->timenow
+	if (m->mDNS_busy == 0)
+		{
+		m->NextScheduledEvent = GetNextScheduledEvent(m);
+		if (m->timenow == 0) LogMsg("mDNS_Unlock: ERROR! m->timenow aready zero");
+		m->timenow = 0;
+		}
+
+	// MUST release the platform lock LAST!
+	mDNSPlatformUnlock(m);
 	}
diff --git a/mDNSCore/DNSCommon.h b/mDNSCore/DNSCommon.h
index 674bb7a..5466501 100644
--- a/mDNSCore/DNSCommon.h
+++ b/mDNSCore/DNSCommon.h
@@ -3,8 +3,6 @@
  *
  * @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
@@ -25,6 +23,54 @@
     Change History (most recent first):
 
 $Log: DNSCommon.h,v $
+Revision 1.28  2004/12/06 21:15:22  ksekar
+<rdar://problem/3884386> mDNSResponder crashed in CheckServiceRegistrations
+
+Revision 1.27  2004/12/03 07:20:50  ksekar
+<rdar://problem/3674208> Wide-Area: Registration of large TXT record fails
+
+Revision 1.26  2004/12/03 05:18:33  ksekar
+<rdar://problem/3810596> mDNSResponder needs to return more specific TSIG errors
+
+Revision 1.25  2004/10/26 03:52:02  cheshire
+Update checkin comments
+
+Revision 1.24  2004/10/23 01:16:00  cheshire
+<rdar://problem/3851677> uDNS operations not always reliable on multi-homed hosts
+
+Revision 1.23  2004/10/03 23:18:58  cheshire
+Move address comparison macros from DNSCommon.h to mDNSEmbeddedAPI.h
+
+Revision 1.22  2004/09/30 00:24:56  ksekar
+<rdar://problem/3695802> Dynamically update default registration domains on config change
+
+Revision 1.21  2004/09/17 01:08:48  cheshire
+Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
+  The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
+  declared in that file are ONLY appropriate to single-address-space embedded applications.
+  For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
+
+Revision 1.20  2004/09/17 00:49:51  cheshire
+Get rid of now-unused GetResourceRecord -- the correct (safe) routine to use
+is GetLargeResourceRecord
+
+Revision 1.19  2004/09/16 21:59:15  cheshire
+For consistency with zerov6Addr, rename zeroIPAddr to zerov4Addr
+
+Revision 1.18  2004/09/16 02:29:39  cheshire
+Moved mDNS_Lock/mDNS_Unlock to DNSCommon.c; Added necessary locking around
+uDNS_ReceiveMsg, uDNS_StartQuery, uDNS_UpdateRecord, uDNS_RegisterService
+
+Revision 1.17  2004/09/14 23:27:46  cheshire
+Fix compile errors
+
+Revision 1.16  2004/08/13 23:46:58  cheshire
+"asyncronous" -> "asynchronous"
+
+Revision 1.15  2004/08/10 23:19:14  ksekar
+<rdar://problem/3722542>: DNS Extension daemon for Wide Area Rendezvous
+Moved routines/constants to allow extern access for garbage collection daemon
+
 Revision 1.14  2004/05/28 23:42:36  ksekar
 <rdar://problem/3258021>: Feature: DNS server->client notification on record changes (#7805)
 
@@ -48,16 +94,16 @@ 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
+Added an asynchronous state machine mechanism to uDNS.c, including
 calls to find the parent zone for a domain name.  Changes include code
-in repository previously dissabled via "#if 0 //incomplete".  Codepath
+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
+Move mDNSAddrIsDNSMulticast() from DNSCommon.h to mDNSEmbeddedAPI.h so embedded 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"
@@ -77,7 +123,7 @@ Revision 1.1  2003/12/13 03:05:27  ksekar
 #ifndef __DNSCOMMON_H_
 #define __DNSCOMMON_H_
 
-#include "mDNSClientAPI.h"
+#include "mDNSEmbeddedAPI.h"
 
 #ifdef	__cplusplus
 	extern "C" {
@@ -127,6 +173,13 @@ typedef enum
 	kDNSFlag1_RC_NotZone  = 0x0A
 	} DNS_Flags;
 
+typedef enum
+	{
+	TSIG_ErrBadSig  = 16,
+	TSIG_ErrBadKey  = 17,
+	TSIG_ErrBadTime = 18
+	} TSIG_ErrorCode;
+	
 // ***************************************************************************
 #if COMPILER_LIKES_PRAGMA_MARK
 #pragma mark -
@@ -138,41 +191,18 @@ 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);
@@ -196,7 +226,8 @@ extern mDNSBool SameRData(const ResourceRecord *const r1, const ResourceRecord *
 
 extern mDNSBool ResourceRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q);
 
-
+extern mDNSBool SameResourceRecord(ResourceRecord *r1, ResourceRecord *r2);
+	
 extern mDNSu16 GetRDLength(const ResourceRecord *const rr, mDNSBool estimate);
 
 #define GetRRDomainNameTarget(RR) (                                                                          \
@@ -221,13 +252,32 @@ extern mDNSu8 *putDomainNameAsLabels(const DNSMessage *const msg, mDNSu8 *ptr, c
 	
 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);
+// If we have a single large record to put in the packet, then we allow the packet to be up to 9K bytes,
+// but in the normal case we try to keep the packets below 1500 to avoid IP fragmentation on standard Ethernet	
 
+extern mDNSu8 *PutResourceRecordTTLWithLimit(DNSMessage *const msg, mDNSu8 *ptr, mDNSu16 *count, ResourceRecord *rr, mDNSu32 ttl, const mDNSu8 *limit);
+
+#define PutResourceRecordTTL(msg, ptr, count, rr, ttl) PutResourceRecordTTLWithLimit((msg), (ptr), (count), (rr), (ttl), \
+	((msg)->h.numAnswers || (msg)->h.numAuthorities || (msg)->h.numAdditionals) ? (msg)->data + NormalMaxDNSMessageData : (msg)->data + AbsoluteMaxDNSMessageData)
+
+#define PutResourceRecordTTLJumbo(msg, ptr, count, rr, ttl) PutResourceRecordTTLWithLimit((msg), (ptr), (count), (rr), (ttl), \
+	(msg)->data + AbsoluteMaxDNSMessageData)
+			
 extern mDNSu8 *PutResourceRecordCappedTTL(DNSMessage *const msg, mDNSu8 *ptr, mDNSu16 *count, ResourceRecord *rr, mDNSu32 maxttl);
 
 extern mDNSu8 *putEmptyResourceRecord(DNSMessage *const msg, mDNSu8 *ptr, const mDNSu8 *const limit, mDNSu16 *count, const AuthRecord *rr);
 
 extern mDNSu8 *putQuestion(DNSMessage *const msg, mDNSu8 *ptr, const mDNSu8 *const limit, const domainname *const name, mDNSu16 rrtype, mDNSu16 rrclass);
+
+extern mDNSu8 *putZone(DNSMessage *const msg, mDNSu8 *ptr, mDNSu8 *limit, const domainname *zone, mDNSOpaque16 zoneClass);
+
+extern mDNSu8 *putPrereqNameNotInUse(domainname *name, DNSMessage *msg, mDNSu8 *ptr, mDNSu8 *end);
+
+extern mDNSu8 *putDeletionRecord(DNSMessage *msg, mDNSu8 *ptr, ResourceRecord *rr);
+
+extern mDNSu8 *putDeleteAllRRSets(DNSMessage *msg, mDNSu8 *ptr, const domainname *name);
+	
+extern mDNSu8 *putUpdateLease(DNSMessage *msg, mDNSu8 *end, mDNSu32 lease);
 	
 #define PutResourceRecord(MSG, P, C, RR) PutResourceRecordTTL((MSG), (P), (C), (RR), (RR)->rroriginalttl)
 
@@ -250,8 +300,8 @@ extern const mDNSu8 *getDomainName(const DNSMessage *const msg, const mDNSu8 *pt
 	
 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 *GetLargeResourceRecord(mDNS *const m, const DNSMessage * const msg, const mDNSu8 *ptr, 
+    const mDNSu8 * const end, const mDNSInterfaceID InterfaceID, mDNSu8 RecordType, LargeCacheRecord *largecr);
 
 extern const mDNSu8 *skipQuestion(const DNSMessage *msg, const mDNSu8 *ptr, const mDNSu8 *end);
 
@@ -264,9 +314,6 @@ extern const mDNSu8 *LocateAuthorities(const DNSMessage *const msg, const mDNSu8
 
 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 -
@@ -274,11 +321,17 @@ extern const mDNSu8 *LocateAdditionals(const DNSMessage *const msg, const mDNSu8
 #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);
+extern mStatus mDNSSendDNSMessage(const mDNS *const m, DNSMessage *const msg, mDNSu8 *end,
+	mDNSInterfaceID InterfaceID, const mDNSAddr *dst, mDNSIPPort dstport, int sd, uDNS_AuthInfo *authInfo);
+
+// ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - RR List Management & Task Management
+#endif
+
+extern void mDNS_Lock(mDNS *const m);
+extern void mDNS_Unlock(mDNS *const m);
 	
 #ifdef	__cplusplus
 	}
diff --git a/mDNSCore/DNSDigest.c b/mDNSCore/DNSDigest.c
index 370e706..55e304c 100644
--- a/mDNSCore/DNSDigest.c
+++ b/mDNSCore/DNSDigest.c
@@ -3,8 +3,6 @@
  *
  * @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
@@ -25,6 +23,29 @@
     Change History (most recent first):
 
 $Log: DNSDigest.c,v $
+Revision 1.12  2004/12/03 07:20:50  ksekar
+<rdar://problem/3674208> Wide-Area: Registration of large TXT record fails
+
+Revision 1.11  2004/12/02 01:10:27  cheshire
+Fix to compile cleanly on 64-bit x86
+
+Revision 1.10  2004/11/01 20:36:04  ksekar
+<rdar://problem/3802395> mDNSResponder should not receive Keychain Notifications
+
+Revision 1.9  2004/10/26 09:00:12  cheshire
+Save a few bytes by creating HMAC_MD5_AlgName as a C string instead of a 256-byte object
+
+Revision 1.8  2004/09/17 01:08:48  cheshire
+Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
+  The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
+  declared in that file are ONLY appropriate to single-address-space embedded applications.
+  For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
+
+Revision 1.7  2004/08/15 18:36:38  cheshire
+Don't use strcpy() and strlen() on "struct domainname" objects;
+use AssignDomainName() and DomainNameLength() instead
+(A "struct domainname" is a collection of packed pascal strings, not a C string.)
+
 Revision 1.6  2004/06/02 00:17:46  ksekar
 Referenced original OpenSSL license headers in source file description.
 
@@ -53,7 +74,7 @@ Support for TSIG signed dynamic updates.
 extern "C" {
 #endif
 
-#include "mDNSClientAPI.h"
+#include "mDNSEmbeddedAPI.h"
 #include "DNSCommon.h"
 
 // Disable certain benign warnings with Microsoft compilers
@@ -661,7 +682,7 @@ void md5_block_data_order (MD5_CTX *c, const void *p,int num);
  * Time for some action:-)
  */
 
-int HASH_UPDATE (HASH_CTX *c, const void *data_, mDNSu32 len)
+int HASH_UPDATE (HASH_CTX *c, const void *data_, unsigned long len)
 	{
 	const unsigned char *data=(const unsigned char *)data_;
 	register HASH_LONG * p;
@@ -1297,13 +1318,10 @@ mDNSexport mDNSs32 DNSDigest_Base64ToBin(const char *src, mDNSu8 *target, mDNSu3
 #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' } };
+#define HMAC_MD5_AlgName (*(const domainname*) "\010" "hmac-md5" "\007" "sig-alg" "\003" "reg" "\003" "int")
+
 // Adapted from Appendix, RFC 2104
-mDNSexport void DNSDigest_ConstructHMACKey(uDNS_AuthInfo *info, mDNSu8 *key, mDNSu32 len)		
+mDNSexport void DNSDigest_ConstructHMACKey(uDNS_AuthInfo *info, const mDNSu8 *key, mDNSu32 len)		
 	{
 	MD5_CTX k;
 	mDNSu8 buf[MD5_LEN];
@@ -1354,11 +1372,10 @@ mDNSexport mDNSu8 *DNSDigest_SignMessage(DNSMessage *msg, mDNSu8 **end, mDNSu16
 	// 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);
+	AssignDomainName(tsig.resrec.name, info->keyname);
+	MD5_Update(&c, info->keyname.c, DomainNameLength(&info->keyname));
 
 	// class
 	tsig.resrec.rrclass = kDNSQClass_ANY;
@@ -1370,9 +1387,9 @@ mDNSexport mDNSu8 *DNSDigest_SignMessage(DNSMessage *msg, mDNSu8 **end, mDNSu16
 	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;
+	AssignDomainName(tsig.resrec.rdata->u.name, HMAC_MD5_AlgName);
+	len = DomainNameLength(&HMAC_MD5_AlgName);
+	rdata = tsig.resrec.rdata->u.data + len;
 	MD5_Update(&c, HMAC_MD5_AlgName.c, len);
 
 	// time
@@ -1392,7 +1409,8 @@ mDNSexport mDNSu8 *DNSDigest_SignMessage(DNSMessage *msg, mDNSu8 **end, mDNSu16
 
 	// fudge
 	buf = mDNSOpaque16fromIntVal(300);     // 300 sec is fudge recommended in RFC 2485
-	((mDNSOpaque16 *)rdata)->NotAnInteger = buf.NotAnInteger;
+	rdata[0] = buf.b[0];
+	rdata[1] = buf.b[1];
 	rdata += sizeof(mDNSOpaque16);
 	MD5_Update(&c, buf.b, sizeof(mDNSOpaque16));
 
@@ -1411,19 +1429,21 @@ mDNSexport mDNSu8 *DNSDigest_SignMessage(DNSMessage *msg, mDNSu8 **end, mDNSu16
 	MD5_Final(digest, &c);
 
 	// set remaining rdata fields
-	*(mDNSOpaque16 *)rdata = mDNSOpaque16fromIntVal(MD5_LEN);             // MAC size	
+	rdata[0] = (mDNSu8)((MD5_LEN >> 8)  & 0xff);
+	rdata[1] = (mDNSu8)( MD5_LEN        & 0xff);
 	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);
+	rdata[0] = msg->h.id.b[0];                                            // original ID
+	rdata[1] = msg->h.id.b[1];
+	rdata[2] = 0;                                                         // no error
+	rdata[3] = 0;
+	rdata[4] = 0;                                                         // other data len
+	rdata[5] = 0;
+	rdata += 6;
 	
 	tsig.resrec.rdlength = (mDNSu16)(rdata - tsig.resrec.rdata->u.data);
-	*end = PutResourceRecordTTL(msg, ptr, numAdditionals, &tsig.resrec, 0);
+	*end = PutResourceRecordTTLJumbo(msg, ptr, numAdditionals, &tsig.resrec, 0);
 	if (!*end) { LogMsg("ERROR: DNSDigest_SignMessage - could not put TSIG"); return mDNSNULL; }
 
 	// update num additionals
@@ -1433,7 +1453,6 @@ mDNSexport mDNSu8 *DNSDigest_SignMessage(DNSMessage *msg, mDNSu8 **end, mDNSu16
 
 	return *end;
 	}
-	
 
 #ifdef __cplusplus
 }
diff --git a/mDNSCore/mDNS.c b/mDNSCore/mDNS.c
index b5364c2..83f634b 100755
--- a/mDNSCore/mDNS.c
+++ b/mDNSCore/mDNS.c
@@ -1,10 +1,9 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * 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
@@ -46,6 +45,369 @@
     Change History (most recent first):
 
 $Log: mDNS.c,v $
+Revision 1.491  2004/12/11 01:52:11  cheshire
+<rdar://problem/3785820> Support kDNSServiceFlagsAllowRemoteQuery for registering services too
+
+Revision 1.490  2004/12/10 20:06:25  cheshire
+<rdar://problem/3915074> Reduce egregious stack space usage
+Reduced SendDelayedUnicastResponse() stack frame from 9K to 112 bytes
+
+Revision 1.489  2004/12/10 20:03:43  cheshire
+<rdar://problem/3915074> Reduce egregious stack space usage
+Reduced mDNSCoreReceiveQuery() stack frame from 9K to 144 bytes
+
+Revision 1.488  2004/12/10 19:50:41  cheshire
+<rdar://problem/3915074> Reduce egregious stack space usage
+Reduced SendResponses() stack frame from 9K to 176 bytes
+
+Revision 1.487  2004/12/10 19:39:13  cheshire
+<rdar://problem/3915074> Reduce egregious stack space usage
+Reduced SendQueries() stack frame from 18K to 112 bytes
+
+Revision 1.486  2004/12/10 14:16:17  cheshire
+<rdar://problem/3889788> Relax update rate limiting
+We now allow an average rate of ten updates per minute.
+Updates in excess of that are rate limited, but more gently than before.
+
+Revision 1.485  2004/12/10 02:09:24  cheshire
+<rdar://problem/3898376> Modify default TTLs
+
+Revision 1.484  2004/12/09 03:15:40  ksekar
+<rdar://problem/3806610> use _legacy instead of _default to find "empty string" browse domains
+
+Revision 1.483  2004/12/07 23:00:14  ksekar
+<rdar://problem/3908336> DNSServiceRegisterRecord() can crash on deregistration:
+Call RecordProbeFailure even if there is no record callback
+
+Revision 1.482  2004/12/07 22:49:06  cheshire
+<rdar://problem/3908850> BIND doesn't like zero-length rdata
+
+Revision 1.481  2004/12/07 21:26:04  ksekar
+<rdar://problem/3908336> DNSServiceRegisterRecord() can crash on deregistration
+
+Revision 1.480  2004/12/07 20:42:33  cheshire
+Add explicit context parameter to mDNS_RemoveRecordFromService()
+
+Revision 1.479  2004/12/07 17:50:49  ksekar
+<rdar://problem/3908850> BIND doesn't like zero-length rdata
+
+Revision 1.478  2004/12/06 21:15:22  ksekar
+<rdar://problem/3884386> mDNSResponder crashed in CheckServiceRegistrations
+
+Revision 1.477  2004/12/04 02:12:45  cheshire
+<rdar://problem/3517236> mDNSResponder puts LargeCacheRecord on the stack
+
+Revision 1.476  2004/11/29 23:34:31  cheshire
+On platforms with coarse time resolutions, ORing time values with one to ensure they are non-zero
+is crude, and effectively halves the time resolution. The more selective NonZeroTime() function
+only nudges the time value to 1 if the interval calculation happens to result in the value zero.
+
+Revision 1.475  2004/11/29 23:13:31  cheshire
+<rdar://problem/3484552> All unique records in a set should have the cache flush bit set
+Additional check: Make sure we don't unnecessarily send packets containing only additionals.
+(This could occur with multi-packet KA lists, if the answer and additionals were marked
+by the query packet, and then the answer were later suppressed in a subsequent KA packet.)
+
+Revision 1.474  2004/11/29 17:18:12  cheshire
+Remove "Unknown DNS packet type" message for update responses
+
+Revision 1.473  2004/11/25 01:57:52  cheshire
+<rdar://problem/3484552> All unique records in a set should have the cache flush bit set
+
+Revision 1.472  2004/11/25 01:28:09  cheshire
+<rdar://problem/3557050> Need to implement random delay for 'QU' unicast replies (and set cache flush bit too)
+
+Revision 1.471  2004/11/25 01:10:13  cheshire
+Move code to add additional records to a subroutine called AddAdditionalsToResponseList()
+
+Revision 1.470  2004/11/24 21:54:44  cheshire
+<rdar://problem/3894475> mDNSCore not receiving unicast responses properly
+
+Revision 1.469  2004/11/24 04:50:39  cheshire
+Minor tidying
+
+Revision 1.468  2004/11/24 01:47:07  cheshire
+<rdar://problem/3780207> DNSServiceRegisterRecord should call CallBack on success.
+
+Revision 1.467  2004/11/24 01:41:28  cheshire
+Rename CompleteProbing() to AcknowledgeRecord()
+
+Revision 1.466  2004/11/23 21:08:07  ksekar
+Don't use ID to demux multicast/unicast now that unicast uses random IDs
+
+Revision 1.465  2004/11/15 20:09:21  ksekar
+<rdar://problem/3719050> Wide Area support for Add/Remove record
+
+Revision 1.464  2004/11/03 01:44:36  cheshire
+Update debugging messages
+
+Revision 1.463  2004/10/29 02:38:48  cheshire
+Fix Windows compile errors
+
+Revision 1.462  2004/10/28 19:21:07  cheshire
+Guard against registering interface with zero InterfaceID
+
+Revision 1.461  2004/10/28 19:02:16  cheshire
+Remove \n from LogMsg() call
+
+Revision 1.460  2004/10/28 03:24:40  cheshire
+Rename m->CanReceiveUnicastOn as m->CanReceiveUnicastOn5353
+
+Revision 1.459  2004/10/26 22:34:37  cheshire
+<rdar://problem/3468995> Need to protect mDNSResponder from unbounded packet flooding
+
+Revision 1.458  2004/10/26 20:45:28  cheshire
+Show mask in "invalid mask" message
+
+Revision 1.457  2004/10/26 06:28:36  cheshire
+Now that we don't check IP TTL any more, remove associated log message
+
+Revision 1.456  2004/10/26 06:21:42  cheshire
+Adjust mask validity check to allow an all-ones mask (for IPv6 ::1 loopback address)
+
+Revision 1.455  2004/10/26 06:11:40  cheshire
+Add improved logging to aid in diagnosis of <rdar://problem/3842714> mDNSResponder crashed
+
+Revision 1.454  2004/10/23 01:16:00  cheshire
+<rdar://problem/3851677> uDNS operations not always reliable on multi-homed hosts
+
+Revision 1.453  2004/10/22 20:52:06  ksekar
+<rdar://problem/3799260> Create NAT port mappings for Long Lived Queries
+
+Revision 1.452  2004/10/20 01:50:40  cheshire
+<rdar://problem/3844991> Cannot resolve non-local registrations using the mach API
+Implemented ForceMCast mode for AuthRecords as well as for Questions
+
+Revision 1.451  2004/10/19 21:33:15  cheshire
+<rdar://problem/3844991> Cannot resolve non-local registrations using the mach API
+Added flag 'kDNSServiceFlagsForceMulticast'. Passing through an interface id for a unicast name
+doesn't force multicast unless you set this flag to indicate explicitly that this is what you want
+
+Revision 1.450  2004/10/19 17:42:59  ksekar
+Fixed compiler warnings for non-debug builds.
+
+Revision 1.449  2004/10/18 22:57:07  cheshire
+<rdar://problem/3711302> Seen in console: Ignored apparent spoof mDNS Response with TTL 1
+
+Revision 1.448  2004/10/16 00:16:59  cheshire
+<rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check
+
+Revision 1.447  2004/10/15 00:51:21  cheshire
+<rdar://problem/3711302> Seen in console: Ignored apparent spoof mDNS Response with TTL 1
+
+Revision 1.446  2004/10/14 00:43:34  cheshire
+<rdar://problem/3815984> Services continue to announce SRV and HINFO
+
+Revision 1.445  2004/10/12 21:07:09  cheshire
+Set up m->p in mDNS_Init() before calling mDNSPlatformTimeInit()
+
+Revision 1.444  2004/10/11 17:54:16  ksekar
+Changed hashtable pointer output from debugf to verbosedebugf.
+
+Revision 1.443  2004/10/10 07:05:45  cheshire
+For consistency, use symbol "localdomain" instead of literal string
+
+Revision 1.442  2004/10/08 20:25:10  cheshire
+Change of plan for <rdar://problem/3831716> -- we're not going to do that at this time
+
+Revision 1.441  2004/10/08 03:25:01  ksekar
+<rdar://problem/3831716> domain enumeration should use LLQs
+
+Revision 1.440  2004/10/06 01:44:19  cheshire
+<rdar://problem/3813936> Resolving too quickly sometimes returns stale TXT record
+
+Revision 1.439  2004/10/03 23:14:11  cheshire
+Add "mDNSEthAddr" type and "zeroEthAddr" constant
+
+Revision 1.438  2004/09/29 23:07:04  cheshire
+Patch from Pavel Repin to fix compile error on Windows
+
+Revision 1.437  2004/09/28 02:23:50  cheshire
+<rdar://problem/3637266> Deliver near-pending "remove" events before new "add" events
+Don't need to search the entire cache for nearly-expired records -- just the appropriate hash slot
+For records with the cache flush bit set, defer the decision until the end of the packet
+
+Revision 1.436  2004/09/28 01:27:04  cheshire
+Update incorrect log message
+
+Revision 1.435  2004/09/25 02:41:39  cheshire
+<rdar://problem/3637266> Deliver near-pending "remove" events before new "add" events
+
+Revision 1.434  2004/09/25 02:32:06  cheshire
+Update comments
+
+Revision 1.433  2004/09/25 02:24:27  cheshire
+Removed unused rr->UseCount
+
+Revision 1.432  2004/09/24 21:35:17  cheshire
+<rdar://problem/3561220> Browses are no longer piggybacking on other browses
+TargetPort and TargetQID are allowed to be undefined if no question->Target is set
+
+Revision 1.431  2004/09/24 21:33:12  cheshire
+Adjust comment
+
+Revision 1.430  2004/09/24 02:15:49  cheshire
+<rdar://problem/3680865> Late conflicts don't send goodbye packets on other interfaces
+
+Revision 1.429  2004/09/24 00:20:21  cheshire
+<rdar://problem/3483349> Any rrtype is a conflict for unique records
+
+Revision 1.428  2004/09/24 00:12:25  cheshire
+Get rid of unused RRUniqueOrKnownUnique(RR)
+
+Revision 1.427  2004/09/23 20:44:11  cheshire
+<rdar://problem/3813148> Reduce timeout before expiring records on failure
+
+Revision 1.426  2004/09/23 20:21:07  cheshire
+<rdar://problem/3426876> Refine "immediate answer burst; restarting exponential backoff sequence" logic
+Associate a unique sequence number with each received packet, and only increment the count of recent answer
+packets if the packet sequence number for this answer record is not one we've already seen and counted.
+
+Revision 1.425  2004/09/23 20:14:38  cheshire
+Rename "question->RecentAnswers" to "question->RecentAnswerPkts"
+
+Revision 1.424  2004/09/23 00:58:36  cheshire
+<rdar://problem/3781269> Rate limiting interferes with updating TXT records
+
+Revision 1.423  2004/09/23 00:50:53  cheshire
+<rdar://problem/3419452> Don't send a (DE) if a service is unregistered after wake from sleep
+
+Revision 1.422  2004/09/22 02:34:46  cheshire
+Move definitions of default TTL times from mDNS.c to mDNSEmbeddedAPI.h
+
+Revision 1.421  2004/09/21 23:29:49  cheshire
+<rdar://problem/3680045> DNSServiceResolve should delay sending packets
+
+Revision 1.420  2004/09/21 23:01:42  cheshire
+Update debugf messages
+
+Revision 1.419  2004/09/21 19:51:14  cheshire
+Move "Starting time value" message from mDNS.c to mDNSMacOSX/daemon.c
+
+Revision 1.418  2004/09/21 18:40:17  cheshire
+<rdar://problem/3376752> Adjust default record TTLs
+
+Revision 1.417  2004/09/21 17:32:16  cheshire
+<rdar://problem/3809484> Rate limiting imposed too soon
+
+Revision 1.416  2004/09/20 23:52:01  cheshire
+CFSocket{Puma}.c renamed to mDNSMacOSX{Puma}.c
+
+Revision 1.415  2004/09/18 01:14:09  cheshire
+<rdar://problem/3485375> Resolve() should not bother doing AAAA queries on machines with no IPv6 interfaces
+
+Revision 1.414  2004/09/18 01:06:48  cheshire
+Add comments
+
+Revision 1.413  2004/09/17 01:08:48  cheshire
+Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
+  The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
+  declared in that file are ONLY appropriate to single-address-space embedded applications.
+  For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
+
+Revision 1.412  2004/09/17 00:46:33  cheshire
+mDNS_TimeNow should take const mDNS parameter
+
+Revision 1.411  2004/09/17 00:31:51  cheshire
+For consistency with ipv6, renamed rdata field 'ip' to 'ipv4'
+
+Revision 1.410  2004/09/17 00:19:10  cheshire
+For consistency with AllDNSLinkGroupv6, rename AllDNSLinkGroup to AllDNSLinkGroupv4
+
+Revision 1.409  2004/09/16 21:59:15  cheshire
+For consistency with zerov6Addr, rename zeroIPAddr to zerov4Addr
+
+Revision 1.408  2004/09/16 21:36:36  cheshire
+<rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
+Changes to add necessary locking calls around unicast DNS operations
+
+Revision 1.407  2004/09/16 02:29:39  cheshire
+Moved mDNS_Lock/mDNS_Unlock to DNSCommon.c; Added necessary locking around
+uDNS_ReceiveMsg, uDNS_StartQuery, uDNS_UpdateRecord, uDNS_RegisterService
+
+Revision 1.406  2004/09/16 01:58:14  cheshire
+Fix compiler warnings
+
+Revision 1.405  2004/09/16 00:24:48  cheshire
+<rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
+
+Revision 1.404  2004/09/15 21:44:11  cheshire
+<rdar://problem/3681031> Randomize initial timenow_adjust value in mDNS_Init
+Show time value in log to help diagnose errors
+
+Revision 1.403  2004/09/15 00:46:32  ksekar
+Changed debugf to verbosedebugf in CheckCacheExpiration
+
+Revision 1.402  2004/09/14 23:59:55  cheshire
+<rdar://problem/3681031> Randomize initial timenow_adjust value in mDNS_Init
+
+Revision 1.401  2004/09/14 23:27:46  cheshire
+Fix compile errors
+
+Revision 1.400  2004/09/02 03:48:47  cheshire
+<rdar://problem/3709039> Disable targeted unicast query support by default
+1. New flag kDNSServiceFlagsAllowRemoteQuery to indicate we want to allow remote queries for this record
+2. New field AllowRemoteQuery in AuthRecord structure
+3. uds_daemon.c sets AllowRemoteQuery if kDNSServiceFlagsAllowRemoteQuery is set
+4. mDNS.c only answers remote queries if AllowRemoteQuery is set
+
+Revision 1.399  2004/09/02 01:39:40  cheshire
+For better readability, follow consistent convention that QR bit comes first, followed by OP bits
+
+Revision 1.398  2004/09/01 03:59:29  ksekar
+<rdar://problem/3783453>: Conditionally compile out uDNS code on Windows
+
+Revision 1.397  2004/08/25 22:04:25  rpantos
+Fix the standard Windows compile error.
+
+Revision 1.396  2004/08/25 00:37:27  ksekar
+<rdar://problem/3774635>: Cleanup DynDNS hostname registration code
+
+Revision 1.395  2004/08/18 17:21:18  ksekar
+Removed double-call of uDNS_AdvertiseInterface from mDNS_SetFQDNs()
+
+Revision 1.394  2004/08/14 03:22:41  cheshire
+<rdar://problem/3762579> Dynamic DNS UI <-> mDNSResponder glue
+Add GetUserSpecifiedDDNSName() routine
+Convert ServiceRegDomain to domainname instead of C string
+Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs
+
+Revision 1.393  2004/08/13 23:42:52  cheshire
+Removed unused "zeroDomainNamePtr"
+
+Revision 1.392  2004/08/13 23:37:02  cheshire
+Now that we do both uDNS and mDNS, global replace "uDNS_info.hostname" with
+"uDNS_info.UnicastHostname" for clarity
+
+Revision 1.391  2004/08/13 23:25:00  cheshire
+Now that we do both uDNS and mDNS, global replace "m->hostname" with
+"m->MulticastHostname" for clarity
+
+Revision 1.390  2004/08/11 02:17:01  cheshire
+<rdar://problem/3514236> Registering service with port number 0 should create a "No Such Service" record
+
+Revision 1.389  2004/08/10 23:19:14  ksekar
+<rdar://problem/3722542>: DNS Extension daemon for Wide Area Rendezvous
+Moved routines/constants to allow extern access for garbage collection daemon
+
+Revision 1.388  2004/07/30 17:40:06  ksekar
+<rdar://problem/3739115>: TXT Record updates not available for wide-area services
+
+Revision 1.387  2004/07/26 22:49:30  ksekar
+<rdar://problem/3651409>: Feature #9516: Need support for NATPMP in client
+
+Revision 1.386  2004/07/13 21:24:24  rpantos
+Fix for <rdar://problem/3701120>.
+
+Revision 1.385  2004/06/18 19:09:59  cheshire
+<rdar://problem/3588761> Current method of doing subtypes causes name collisions
+
+Revision 1.384  2004/06/15 04:31:23  cheshire
+Make sure to clear m->CurrentRecord at the end of AnswerNewLocalOnlyQuestion()
+
+Revision 1.383  2004/06/11 00:04:59  cheshire
+<rdar://problem/3595602> TTL must be greater than zero for DNSServiceRegisterRecord
+
 Revision 1.382  2004/06/08 04:59:40  cheshire
 Tidy up wording -- log messages are already prefixed with "mDNSResponder", so don't need to repeat it
 
@@ -201,7 +563,7 @@ 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
+Changed runtime checks in mDNS.c to be compile-time checks in mDNSEmbeddedAPI.h
 Thanks to Bob Bradley for suggesting the ingenious compiler trick to make this work.
 
 Revision 1.333  2003/11/20 20:49:53  cheshire
@@ -243,13 +605,13 @@ 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.
+Best solution is just to combine mDNSEmbeddedAPI.h and mDNSPlatformFunctions.h into a single file.
 
 Revision 1.322  2003/11/14 19:47:52  cheshire
 Define symbol MAX_ESCAPED_DOMAIN_NAME to indicate recommended buffer size for ConvertDomainNameToCString
 
 Revision 1.321  2003/11/14 19:18:34  cheshire
-Move AssignDomainName macro to mDNSClientAPI.h to that client layers can use it too
+Move AssignDomainName macro to mDNSEmbeddedAPI.h to that client layers can use it too
 
 Revision 1.320  2003/11/13 06:45:04  cheshire
 Fix compiler warning on certain compilers
@@ -332,7 +694,7 @@ Revision 1.299  2003/09/03 02:33:09  cheshire
 Don't update m->NewQuestions until *after* CheckCacheExpiration();
 
 Revision 1.298  2003/09/03 01:47:01  cheshire
-<rdar://problem/3319418> Rendezvous services always in a state of flux
+<rdar://problem/3319418> Services always in a state of flux
 Change mDNS_Reconfirm_internal() minimum timeout from 5 seconds to 45-60 seconds
 
 Revision 1.297  2003/08/29 19:44:15  cheshire
@@ -410,7 +772,7 @@ Final expiration queries now only mark the question for sending on the particula
 pertaining to the record that's expiring.
 
 Revision 1.278  2003/08/18 22:53:37  cheshire
-<rdar://problem/3382647> mDNSResponder divide by zero in mDNSPlatformTimeNow()
+<rdar://problem/3382647> mDNSResponder divide by zero in mDNSPlatformRawTime()
 
 Revision 1.277  2003/08/18 19:05:44  cheshire
 <rdar://problem/3382423> UpdateRecord not working right
@@ -441,7 +803,7 @@ We want to avoid touching the rdata pages, so we don't page them in.
 
 Revision 1.272  2003/08/14 19:29:04  cheshire
 <rdar://problem/3378473> Include cache records in SIGINFO output
-Moved declarations of DNSTypeName() and GetRRDisplayString to mDNSClientAPI.h so daemon.c can use them
+Moved declarations of DNSTypeName() and GetRRDisplayString to mDNSEmbeddedAPI.h so daemon.c can use them
 
 Revision 1.271  2003/08/14 02:17:05  cheshire
 <rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
@@ -581,7 +943,7 @@ Revision 1.231  2003/07/18 00:06:37  cheshire
 To make code a little easier to read in GetRDLength(), search-and-replace "rr->rdata->u." with "rd->"
 
 Revision 1.230  2003/07/17 18:16:54  cheshire
-<rdar://problem/3319418> Rendezvous services always in a state of flux
+<rdar://problem/3319418> Services always in a state of flux
 In preparation for working on this, made some debugf messages a little more selective
 
 Revision 1.229  2003/07/17 17:35:04  cheshire
@@ -984,7 +1346,7 @@ Fix some warnings
 Revision 1.118  2003/05/14 18:48:40  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
+mDNSMacOSX.c needs to do *all* its mDNS_DeregisterInterface calls before freeing memory
 mDNS_DeregisterInterface revalidates cache record when *any* representative of an interface goes away
 
 Revision 1.117  2003/05/14 07:08:36  cheshire
@@ -996,7 +1358,7 @@ 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.116  2003/05/14 06:51:56  cheshire
-<rdar://problem/3027144> Rendezvous doesn't refresh server info if changed during sleep
+<rdar://problem/3027144> mDNSResponder doesn't refresh server info if changed during sleep
 
 Revision 1.115  2003/05/14 06:44:31  cheshire
 Improve debugging message
@@ -1214,7 +1576,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-existance
+Added mDNS_RegisterNoSuchService() function for assertion of non-existence
 of a particular named service
 
 Revision 1.59  2002/09/19 21:25:34  cheshire
@@ -1232,7 +1594,6 @@ 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 "DNSCommon.h"                  // Defines general DNS untility routines
 #include "uDNS.h"						// Defines entry points into unicast-specific routines
 // Disable certain benign warnings with Microsoft compilers
@@ -1257,15 +1618,15 @@ Merge in license terms from Quinn's copy, in preparation for Darwin release
 #endif
 
 mDNSexport const mDNSIPPort      zeroIPPort        = { { 0 } };
-mDNSexport const mDNSv4Addr      zeroIPAddr        = { { 0 } };
+mDNSexport const mDNSv4Addr      zerov4Addr        = { { 0 } };
 mDNSexport const mDNSv6Addr      zerov6Addr        = { { 0 } };
+mDNSexport const mDNSEthAddr     zeroEthAddr       = { { 0 } };
 mDNSexport const mDNSv4Addr      onesIPv4Addr      = { { 255, 255, 255, 255 } };
 mDNSexport const mDNSv6Addr      onesIPv6Addr      = { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } };
 mDNSexport const mDNSAddr        zeroAddr          = { mDNSAddrType_None, {{{ 0 }}} };
 
 mDNSexport const mDNSInterfaceID mDNSInterface_Any        = 0;
 mDNSexport const mDNSInterfaceID mDNSInterface_LocalOnly  = (mDNSInterfaceID)-1;
-mDNSexport const mDNSInterfaceID mDNSInterface_ForceMCast = (mDNSInterfaceID)-2;
 
 // Note that mDNSInterfaceMark is the same value as mDNSInterface_LocalOnly, but they are used in different contexts
 mDNSlocal  const mDNSInterfaceID mDNSInterfaceMark        = (mDNSInterfaceID)~0;
@@ -1275,7 +1636,7 @@ mDNSlocal  const mDNSInterfaceID mDNSInterfaceMark        = (mDNSInterfaceID)~0;
 mDNSexport const mDNSIPPort UnicastDNSPort     = { { UnicastDNSPortAsNumber   >> 8, UnicastDNSPortAsNumber   & 0xFF } };
 mDNSexport const mDNSIPPort MulticastDNSPort   = { { MulticastDNSPortAsNumber >> 8, MulticastDNSPortAsNumber & 0xFF } };
 mDNSexport const mDNSv4Addr AllDNSAdminGroup   = { { 239, 255, 255, 251 } };
-mDNSexport const mDNSv4Addr AllDNSLinkGroup    = { { 224,   0,   0, 251 } };
+mDNSexport const mDNSv4Addr AllDNSLinkGroupv4  = { { 224,   0,   0, 251 } };
 mDNSexport const mDNSv6Addr AllDNSLinkGroupv6  = { { 0xFF,0x02,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xFB } };
 mDNSexport const mDNSAddr   AllDNSLinkGroup_v4 = { mDNSAddrType_IPv4, { { { 224,   0,   0, 251 } } } };
 mDNSexport const mDNSAddr   AllDNSLinkGroup_v6 = { mDNSAddrType_IPv6, { { { 0xFF,0x02,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xFB } } } };
@@ -1283,27 +1644,28 @@ mDNSexport const mDNSAddr   AllDNSLinkGroup_v6 = { mDNSAddrType_IPv6, { { { 0xFF
 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*)"")
+mDNSexport const mDNSOpaque16 UpdateReqFlags= { { kDNSFlag0_QR_Query    | kDNSFlag0_OP_Update,                  0 } };
+mDNSexport const mDNSOpaque16 UpdateRespFlags={ { kDNSFlag0_QR_Response | kDNSFlag0_OP_Update,                  0 } };
 
 // Any records bigger than this are considered 'large' records
 #define SmallRecordLimit 1024
 
-#define kDefaultTTLforUnique 240
-#define kDefaultTTLforShared (2*3600)
-
 #define kMaxUpdateCredits 10
-#define kUpdateCreditRefreshInterval (mDNSPlatformOneSecond * 50)
+#define kUpdateCreditRefreshInterval (mDNSPlatformOneSecond * 6)
 
 static const char *const mDNS_DomainTypeNames[] =
 	{
 	"_browse._dns-sd._udp.",
 	"_default._browse._dns-sd._udp.",
 	"_register._dns-sd._udp.",
-	"_default._register._dns-sd._udp."
+	"_default._register._dns-sd._udp.",
+	"_legacy._browse._dns-sd._udp."
 	};
 
+#ifdef UNICAST_DISABLED
+#define uDNS_IsActiveQuery(q, u) mDNSfalse
+#endif
+
 // ***************************************************************************
 #if COMPILER_LIKES_PRAGMA_MARK
 #pragma mark -
@@ -1639,20 +2001,10 @@ mDNSlocal void SetNextQueryTime(mDNS *const m, const DNSQuestion *const q)
 	(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
@@ -1689,9 +2041,11 @@ mDNSlocal mDNSBool SameResourceRecordSignature(const ResourceRecord *const r1, c
 	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.  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.
+// PacketRRMatchesSignature behaves as SameResourceRecordSignature, except that types may differ if our
+// authoratative record is unique (as opposed to shared). For unique records, we are supposed to have
+// complete ownership of *all* types for this name, so *any* record type with the same name is a conflict.
+// In addition, when probing we send our questions with the wildcard type kDNSQType_ANY,
+// so a response of any type should match, even if it is not actually the type the client plans to use.
 mDNSlocal mDNSBool PacketRRMatchesSignature(const CacheRecord *const pktrr, const AuthRecord *const authrr)
 	{
 	if (!pktrr)  { LogMsg("PacketRRMatchesSignature ERROR: pktrr is NULL"); return(mDNSfalse); }
@@ -1699,7 +2053,7 @@ mDNSlocal mDNSBool PacketRRMatchesSignature(const CacheRecord *const pktrr, cons
 	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);
+	if (!(authrr->resrec.RecordType & kDNSRecordTypeUniqueMask) && pktrr->resrec.rrtype != authrr->resrec.rrtype) return(mDNSfalse);
 	return(mDNSBool)(pktrr->resrec.rrclass == authrr->resrec.rrclass && pktrr->resrec.namehash == authrr->resrec.namehash && SameDomainName(&pktrr->resrec.name, &authrr->resrec.name));
 	}
 
@@ -1741,7 +2095,7 @@ mDNSlocal void SetNextAnnounceProbeTime(mDNS *const m, const AuthRecord *const r
 	{
 	if (rr->resrec.RecordType == kDNSRecordTypeUnique)
 		{
-		//LogMsg("ProbeCount %d Next %ld %s", rr->ProbeCount, (rr->LastAPTime + rr->ThisAPInterval) - m->timenow, GetRRDisplayString(m, rr));
+		//LogMsg("ProbeCount %d Next %ld %s", rr->ProbeCount, (rr->LastAPTime + rr->ThisAPInterval) - m->timenow, ARDisplayString(m, rr));
 		if (m->NextScheduledProbe - (rr->LastAPTime + rr->ThisAPInterval) >= 0)
 			m->NextScheduledProbe = (rr->LastAPTime + rr->ThisAPInterval);
 		}
@@ -1764,7 +2118,7 @@ mDNSlocal void InitializeLastAPTime(mDNS *const m, AuthRecord *const rr)
 	// If we have no probe suppression time set, or it is in the past, set it now
 	if (m->SuppressProbes == 0 || m->SuppressProbes - m->timenow < 0)
 		{
-		m->SuppressProbes = (m->timenow + DefaultProbeIntervalForTypeUnique) | 1;
+		m->SuppressProbes = NonZeroTime(m->timenow + DefaultProbeIntervalForTypeUnique);
 		// If we already have a probe scheduled to go out sooner, then use that time to get better aggregation
 		if (m->SuppressProbes - m->NextScheduledProbe >= 0)
 			m->SuppressProbes = m->NextScheduledProbe;
@@ -1804,12 +2158,12 @@ mDNSlocal void SetTargetToHostName(mDNS *const m, AuthRecord *const rr)
 
 	if (!target) debugf("SetTargetToHostName: Don't know how to set the target of rrtype %d", rr->resrec.rrtype);
 
-	if (target && SameDomainName(target, &m->hostname))
+	if (target && SameDomainName(target, &m->MulticastHostname))
 		debugf("SetTargetToHostName: Target of %##s is already %##s", rr->resrec.name.c, target->c);
 	
-	if (target && !SameDomainName(target, &m->hostname))
+	if (target && !SameDomainName(target, &m->MulticastHostname))
 		{
-		AssignDomainName(*target, m->hostname);
+		AssignDomainName(*target, m->MulticastHostname);
 		SetNewRData(&rr->resrec, mDNSNULL, 0);
 		
 		// If we're in the middle of probing this record, we need to start again,
@@ -1820,19 +2174,18 @@ mDNSlocal void SetTargetToHostName(mDNS *const m, AuthRecord *const rr)
 		// If we've announced this record, we really should send a goodbye packet for the old rdata before
 		// changing to the new rdata. However, in practice, we only do SetTargetToHostName for unique records,
 		// so when we announce them we'll set the kDNSClass_UniqueRRSet and clear any stale data that way.
-		if (rr->AnnounceCount < InitialAnnounceCount && rr->resrec.RecordType == kDNSRecordTypeShared)
+		if (rr->RequireGoodbye && rr->resrec.RecordType == kDNSRecordTypeShared)
 			debugf("Have announced shared record %##s (%s) at least once: should have sent a goodbye packet before updating", rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype));
 
-		if (rr->AnnounceCount < ReannounceCount)
-			rr->AnnounceCount = ReannounceCount;
+		rr->AnnounceCount  = InitialAnnounceCount;
+		rr->RequireGoodbye = mDNSfalse;
 		rr->ThisAPInterval = DefaultAPIntervalForRecordType(rr->resrec.RecordType);
 		InitializeLastAPTime(m,rr);
 		}
 	}
 
-mDNSlocal void CompleteProbing(mDNS *const m, AuthRecord *const rr)
+mDNSlocal void AcknowledgeRecord(mDNS *const m, AuthRecord *const rr)
 	{
-	verbosedebugf("Probing for %##s (%s) complete", rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype));
 	if (!rr->Acknowledged && rr->RecordCallback)
 		{
 		// CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function
@@ -1855,17 +2208,22 @@ mDNSlocal mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr)
 	AuthRecord **p = &m->ResourceRecords;
 	AuthRecord **d = &m->DuplicateRecords;
 	AuthRecord **l = &m->LocalOnlyRecords;
+
+	mDNSPlatformMemZero(&rr->uDNS_info, sizeof(uDNS_RegInfo));
+
+	if ((mDNSs32)rr->resrec.rroriginalttl <= 0)
+		{ LogMsg("mDNS_Register_internal: TTL must be 1 - 0x7FFFFFFF %s", ARDisplayString(m, rr)); return(mStatus_BadParamErr); }
 	
 #if TEST_LOCALONLY_FOR_EVERYTHING
 	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))
+#ifndef UNICAST_DISABLED
+    if (rr->resrec.InterfaceID == mDNSInterface_LocalOnly || rr->ForceMCast || IsLocalDomain(&rr->resrec.name))
     	rr->uDNS_info.id = zeroID;
     else return uDNS_RegisterRecord(m, rr);
-
+#endif
+	
 	while (*p && *p != rr) p=&(*p)->next;
 	while (*d && *d != rr) d=&(*d)->next;
 	while (*l && *l != rr) l=&(*l)->next;
@@ -1917,6 +2275,7 @@ 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
+//	rr->AllowRemoteQuery  = set to mDNSfalse in mDNS_SetupResourceRecord; may be overridden by client
 	// Make sure target is not uninitialized data, or we may crash writing debugging log messages
 	if (rr->HostTarget && target) target->c[0] = 0;
 
@@ -1924,11 +2283,13 @@ mDNSlocal mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr)
 	rr->Acknowledged      = mDNSfalse;
 	rr->ProbeCount        = DefaultProbeCountForRecordType(rr->resrec.RecordType);
 	rr->AnnounceCount     = InitialAnnounceCount;
+	rr->RequireGoodbye    = mDNSfalse;
 	rr->IncludeInProbe    = mDNSfalse;
 	rr->ImmedAnswer       = mDNSNULL;
+	rr->ImmedUnicast      = mDNSfalse;
 	rr->ImmedAdditional   = mDNSNULL;
 	rr->SendRNow          = mDNSNULL;
-	rr->v4Requester       = zeroIPAddr;
+	rr->v4Requester       = zerov4Addr;
 	rr->v6Requester       = zerov6Addr;
 	rr->NextResponse      = mDNSNULL;
 	rr->NR_AnswerTo       = mDNSNULL;
@@ -1962,11 +2323,15 @@ mDNSlocal mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr)
 		}
 
 	if (!ValidateDomainName(&rr->resrec.name))
-		{ LogMsg("Attempt to register record with invalid name: %s", GetRRDisplayString(m, rr)); return(mStatus_Invalid); }
+		{ LogMsg("Attempt to register record with invalid name: %s", ARDisplayString(m, rr)); return(mStatus_Invalid); }
+
+	// Some (or perhaps all) versions of BIND named (name daemon) don't allow updates with zero-length rdata. It's common for
+	// existing mDNS clients to create empty TXT records, so we silently change those to a TXT record containing a single empty string.
+	if (rr->resrec.rrtype == kDNSType_TXT && rr->resrec.rdlength == 0) { rr->resrec.rdlength = 1; rr->resrec.rdata->u.txt.c[0] = 0; }
 
 	// Don't do this until *after* we've set rr->resrec.rdlength
 	if (!ValidateRData(rr->resrec.rrtype, rr->resrec.rdlength, rr->resrec.rdata))
-		{ LogMsg("Attempt to register record with invalid rdata: %s", GetRRDisplayString(m, rr)); return(mStatus_Invalid); }
+		{ LogMsg("Attempt to register record with invalid rdata: %s", ARDisplayString(m, rr)); return(mStatus_Invalid); }
 
 	rr->resrec.namehash   = DomainNameHashValue(&rr->resrec.name);
 	rr->resrec.rdatahash  = RDataHashValue(rr->resrec.rdlength, &rr->resrec.rdata->u);
@@ -2021,6 +2386,10 @@ mDNSlocal mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr)
 			*p = rr;
 			}
 		}
+
+	// For records that are not going to probe, acknowledge them right away
+	if (rr->resrec.RecordType != kDNSRecordTypeUnique) AcknowledgeRecord(m, rr);
+
 	return(mStatus_NoError);
 	}
 
@@ -2028,12 +2397,17 @@ mDNSlocal void RecordProbeFailure(mDNS *const m, const AuthRecord *const rr)
 	{
 	m->ProbeFailTime = m->timenow;
 	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)
+	// If we've had fifteen or more probe failures, rate-limit to one every five seconds.
+	// If a bunch of hosts have all been configured with the same name, then they'll all
+	// conflict and run through the same series of names: name-2, name-3, name-4, etc.,
+	// up to name-10. After that they'll start adding random increments in the range 1-100,
+	// so they're more likely to branch out in the available namespace and settle on a set of
+	// unique names quickly. If after five more tries the host is still conflicting, then we
+	// may have a serious problem, so we start rate-limiting so we don't melt down the network.
+	if (m->NumFailedProbes >= 15)
 		{
-		m->SuppressProbes = (m->timenow + mDNSPlatformOneSecond * 5) | 1;
-		LogMsg("Excessive name conflicts (%d) for %##s (%s); rate limiting in effect",
+		m->SuppressProbes = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 5);
+		LogMsg("Excessive name conflicts (%lu) for %##s (%s); rate limiting in effect",
 			m->NumFailedProbes, rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype));
 		}
 	}
@@ -2059,8 +2433,10 @@ 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 && !IsLocalDomain(&rr->resrec.name) && rr->uDNS_info.id.NotAnInteger)
+#ifndef UNICAST_DISABLED
+    if (!(rr->resrec.InterfaceID == mDNSInterface_LocalOnly || rr->ForceMCast || IsLocalDomain(&rr->resrec.name)))
 		return uDNS_DeregisterRecord(m, rr);
+#endif
 	
 	if (rr->resrec.InterfaceID == mDNSInterface_LocalOnly) p = &m->LocalOnlyRecords;
 	while (*p && *p != rr) p=&(*p)->next;
@@ -2091,18 +2467,20 @@ mDNSlocal mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr,
 				dup->next = rr->next;		// And then...
 				rr->next  = dup;			// ... splice it in right after the record we're about to delete
 				dup->resrec.RecordType        = rr->resrec.RecordType;
-				dup->ProbeCount        = rr->ProbeCount;
-				dup->AnnounceCount     = rr->AnnounceCount;
-				dup->ImmedAnswer       = rr->ImmedAnswer;
-				dup->ImmedAdditional   = rr->ImmedAdditional;
-				dup->v4Requester       = rr->v4Requester;
-				dup->v6Requester       = rr->v6Requester;
-				dup->ThisAPInterval    = rr->ThisAPInterval;
-				dup->AnnounceUntil     = rr->AnnounceUntil;
-				dup->LastAPTime        = rr->LastAPTime;
-				dup->LastMCTime        = rr->LastMCTime;
-				dup->LastMCInterface   = rr->LastMCInterface;
-				if (RecordType == kDNSRecordTypeShared) rr->AnnounceCount = InitialAnnounceCount;
+				dup->ProbeCount      = rr->ProbeCount;
+				dup->AnnounceCount   = rr->AnnounceCount;
+				dup->RequireGoodbye  = rr->RequireGoodbye;
+				dup->ImmedAnswer     = rr->ImmedAnswer;
+				dup->ImmedUnicast    = rr->ImmedUnicast;
+				dup->ImmedAdditional = rr->ImmedAdditional;
+				dup->v4Requester     = rr->v4Requester;
+				dup->v6Requester     = rr->v6Requester;
+				dup->ThisAPInterval  = rr->ThisAPInterval;
+				dup->AnnounceUntil   = rr->AnnounceUntil;
+				dup->LastAPTime      = rr->LastAPTime;
+				dup->LastMCTime      = rr->LastMCTime;
+				dup->LastMCInterface = rr->LastMCInterface;
+				rr->RequireGoodbye = mDNSfalse;
 				}
 			}
 		}
@@ -2112,7 +2490,7 @@ mDNSlocal mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr,
 		p = &m->DuplicateRecords;
 		while (*p && *p != rr) p=&(*p)->next;
 		// If we found our record on the duplicate list, then make sure we don't send a goodbye for it
-		if (*p && RecordType == kDNSRecordTypeShared) rr->AnnounceCount = InitialAnnounceCount;
+		if (*p) rr->RequireGoodbye = mDNSfalse;
 		if (*p) debugf("DNS_Deregister_internal: Deleting DuplicateRecord %p %##s (%s)", rr, rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype));
 		}
 
@@ -2120,13 +2498,13 @@ mDNSlocal mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr,
 		{
 		// No need to log an error message if we already know this is a potentially repeated deregistration
 		if (drt != mDNS_Dereg_repeat)
-			debugf("mDNS_Deregister_internal: Record %p %##s (%s) not found in list", rr, rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype));
+			LogMsg("mDNS_Deregister_internal: Record %p %##s (%s) not found in list", rr, rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype));
 		return(mStatus_BadReferenceErr);
 		}
 
 	// If this is a shared record and we've announced it at least once,
 	// we need to retract that announcement before we delete the record
-	if (RecordType == kDNSRecordTypeShared && rr->AnnounceCount < InitialAnnounceCount)
+	if (RecordType == kDNSRecordTypeShared && rr->RequireGoodbye)
 		{
 		verbosedebugf("mDNS_Deregister_internal: Sending deregister for %##s (%s)", rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype));
 		rr->resrec.RecordType    = kDNSRecordTypeDeregistering;
@@ -2172,17 +2550,12 @@ mDNSlocal mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr,
 		// 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)
+		if (drt == mDNS_Dereg_conflict)
 			{
 			RecordProbeFailure(m, rr);
-			if (rr->RecordCallback)
-				rr->RecordCallback(m, rr, mStatus_NameConflict);
+			if (rr->RecordCallback) rr->RecordCallback(m, rr, mStatus_NameConflict);
 			}
+		else if (rr->RecordCallback) rr->RecordCallback(m, rr, mStatus_MemFree);
 		m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
 		}
 	return(mStatus_NoError);
@@ -2195,13 +2568,127 @@ mDNSlocal mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr,
 #pragma mark - Packet Sending Functions
 #endif
 
+mDNSlocal void AddRecordToResponseList(AuthRecord ***nrpp, AuthRecord *rr, AuthRecord *add)
+	{
+	if (rr->NextResponse == mDNSNULL && *nrpp != &rr->NextResponse)
+		{
+		**nrpp = rr;
+		// NR_AdditionalTo must point to a record with NR_AnswerTo set (and not NR_AdditionalTo)
+		// If 'add' does not meet this requirement, then follow its NR_AdditionalTo pointer to a record that does
+		// The referenced record will definitely be acceptable (by recursive application of this rule)
+		if (add && add->NR_AdditionalTo) add = add->NR_AdditionalTo;
+		rr->NR_AdditionalTo = add;
+		*nrpp = &rr->NextResponse;
+		}
+	debugf("AddRecordToResponseList: %##s (%s) already in list", rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype));
+	}
+
+mDNSlocal void AddAdditionalsToResponseList(mDNS *const m, AuthRecord *ResponseRecords, AuthRecord ***nrpp, const mDNSInterfaceID InterfaceID)
+	{
+	AuthRecord  *rr, *rr2;
+	for (rr=ResponseRecords; rr; rr=rr->NextResponse)			// For each record we plan to put
+		{
+		// (Note: This is an "if", not a "while". If we add a record, we'll find it again
+		// later in the "for" loop, and we will follow further "additional" links then.)
+		if (rr->Additional1 && ResourceRecordIsValidInterfaceAnswer(rr->Additional1, InterfaceID))
+			AddRecordToResponseList(nrpp, rr->Additional1, rr);
+
+		if (rr->Additional2 && ResourceRecordIsValidInterfaceAnswer(rr->Additional2, InterfaceID))
+			AddRecordToResponseList(nrpp, rr->Additional2, rr);
+		
+		// For SRV records, automatically add the Address record(s) for the target host
+		if (rr->resrec.rrtype == kDNSType_SRV)
+			for (rr2=m->ResourceRecords; rr2; rr2=rr2->next)					// Scan list of resource records
+				if (RRTypeIsAddressType(rr2->resrec.rrtype) &&					// For all address records (A/AAAA) ...
+					ResourceRecordIsValidInterfaceAnswer(rr2, InterfaceID) &&	// ... which are valid for answer ...
+					rr->resrec.rdnamehash == rr2->resrec.namehash &&			// ... whose name is the name of the SRV target
+					SameDomainName(&rr->resrec.rdata->u.srv.target, &rr2->resrec.name))
+					AddRecordToResponseList(nrpp, rr2, rr);
+		}
+	}
+
+mDNSlocal void SendDelayedUnicastResponse(mDNS *const m, const mDNSAddr *const dest, const mDNSInterfaceID InterfaceID)
+	{
+	AuthRecord *rr;
+	AuthRecord  *ResponseRecords = mDNSNULL;
+	AuthRecord **nrp             = &ResponseRecords;
+
+	// Make a list of all our records that need to be unicast to this destination
+	for (rr = m->ResourceRecords; rr; rr=rr->next)
+		{
+		// If we find we can no longer unicast this answer, clear ImmedUnicast
+		if (rr->ImmedAnswer == mDNSInterfaceMark               ||
+			mDNSSameIPv4Address(rr->v4Requester, onesIPv4Addr) ||
+			mDNSSameIPv6Address(rr->v6Requester, onesIPv6Addr)  )
+			rr->ImmedUnicast = mDNSfalse;
+
+		if (rr->ImmedUnicast && rr->ImmedAnswer == InterfaceID)
+			if ((dest->type == mDNSAddrType_IPv4 && mDNSSameIPv4Address(rr->v4Requester, dest->ip.v4)) ||
+				(dest->type == mDNSAddrType_IPv6 && mDNSSameIPv6Address(rr->v6Requester, dest->ip.v6)))
+				{
+				rr->ImmedAnswer  = mDNSNULL;				// Clear the state fields
+				rr->ImmedUnicast = mDNSfalse;
+				rr->v4Requester  = zerov4Addr;
+				rr->v6Requester  = zerov6Addr;
+				if (rr->NextResponse == mDNSNULL && nrp != &rr->NextResponse)	// rr->NR_AnswerTo
+					{ rr->NR_AnswerTo = (mDNSu8*)~0; *nrp = rr; nrp = &rr->NextResponse; }
+				}
+		}
+
+	AddAdditionalsToResponseList(m, ResponseRecords, &nrp, InterfaceID);
+
+	while (ResponseRecords)
+		{
+		mDNSu8 *responseptr = m->omsg.data;
+		mDNSu8 *newptr;
+		InitializeDNSMessage(&m->omsg.h, zeroID, ResponseFlags);
+		
+		// Put answers in the packet
+		while (ResponseRecords && ResponseRecords->NR_AnswerTo)
+			{
+			rr = ResponseRecords;
+			if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
+				rr->resrec.rrclass |= kDNSClass_UniqueRRSet;		// Temporarily set the cache flush bit so PutResourceRecord will set it
+			newptr = PutResourceRecord(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec);
+			rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet;			// Make sure to clear cache flush bit back to normal state
+			if (!newptr && m->omsg.h.numAnswers) break;	// If packet full, send it now
+			if (newptr) responseptr = newptr;
+			ResponseRecords = rr->NextResponse;
+			rr->NextResponse    = mDNSNULL;
+			rr->NR_AnswerTo     = mDNSNULL;
+			rr->NR_AdditionalTo = mDNSNULL;
+			rr->RequireGoodbye  = mDNStrue;
+			}
+		
+		// Add additionals, if there's space
+		while (ResponseRecords && !ResponseRecords->NR_AnswerTo)
+			{
+			rr = ResponseRecords;
+			if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
+				rr->resrec.rrclass |= kDNSClass_UniqueRRSet;		// Temporarily set the cache flush bit so PutResourceRecord will set it
+			newptr = PutResourceRecord(&m->omsg, responseptr, &m->omsg.h.numAdditionals, &rr->resrec);
+			rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet;			// Make sure to clear cache flush bit back to normal state
+			
+			if (newptr) responseptr = newptr;
+			if (newptr && m->omsg.h.numAnswers) rr->RequireGoodbye = mDNStrue;
+			else if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask) rr->ImmedAnswer = mDNSInterfaceMark;
+			ResponseRecords = rr->NextResponse;
+			rr->NextResponse    = mDNSNULL;
+			rr->NR_AnswerTo     = mDNSNULL;
+			rr->NR_AdditionalTo = mDNSNULL;
+			}
+
+		if (m->omsg.h.numAnswers) mDNSSendDNSMessage(m, &m->omsg, responseptr, mDNSInterface_Any, dest, MulticastDNSPort, -1, mDNSNULL);
+		}
+	}
+
 mDNSlocal void CompleteDeregistration(mDNS *const m, AuthRecord *rr)
 	{
-	// Setting AnnounceCount to InitialAnnounceCount signals mDNS_Deregister_internal()
+	// Clearing rr->RequireGoodbye signals mDNS_Deregister_internal()
 	// that it should go ahead and immediately dispose of this registration
-	rr->resrec.RecordType    = kDNSRecordTypeShared;
-	rr->AnnounceCount = InitialAnnounceCount;
-	mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal);
+	rr->resrec.RecordType = kDNSRecordTypeShared;
+	rr->RequireGoodbye    = mDNSfalse;
+	mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal);		// Don't touch rr after this
 	}
 
 // NOTE: DiscardDeregistrations calls mDNS_Deregister_internal which can call a user callback, which may change
@@ -2217,23 +2704,14 @@ mDNSlocal void DiscardDeregistrations(mDNS *const m)
 		AuthRecord *rr = m->CurrentRecord;
 		m->CurrentRecord = rr->next;
 		if (rr->resrec.RecordType == kDNSRecordTypeDeregistering)
-			CompleteDeregistration(m, rr);
+			CompleteDeregistration(m, rr);		// Don't touch rr after this
 		}
 	}
 
 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
-	const AuthRecord *a;
-	for (a = m->ResourceRecords; a; a=a->next)
-		if (a->SendRNow == InterfaceID && a != rr && SameResourceRecordSignature(&a->resrec, &rr->resrec)) break;
-	return (a == mDNSNULL);		// If no more members of this set found, then we should set the cache flush bit
+	else rr->NextUpdateCredit = NonZeroTime(rr->NextUpdateCredit + kUpdateCreditRefreshInterval);
 	}
 
 // Note about acceleration of announcements to facilitate automatic coalescing of
@@ -2261,6 +2739,22 @@ mDNSlocal void SendResponses(mDNS *const m)
 
 	m->NextScheduledResponse = m->timenow + 0x78000000;
 
+	for (rr = m->ResourceRecords; rr; rr=rr->next)
+		if (rr->ImmedUnicast)
+			{
+			mDNSAddr v4 = { mDNSAddrType_IPv4, {{{0}}} };
+			mDNSAddr v6 = { mDNSAddrType_IPv6, {{{0}}} };
+			v4.ip.v4 = rr->v4Requester;
+			v6.ip.v6 = rr->v6Requester;
+			if (!mDNSIPv4AddressIsZero(rr->v4Requester)) SendDelayedUnicastResponse(m, &v4, rr->ImmedAnswer);
+			if (!mDNSIPv6AddressIsZero(rr->v6Requester)) SendDelayedUnicastResponse(m, &v6, rr->ImmedAnswer);
+			if (rr->ImmedUnicast)
+				{
+				LogMsg("SendResponses: ERROR: rr->ImmedUnicast still set: %s", ARDisplayString(m, rr));
+				rr->ImmedUnicast = mDNSfalse;
+				}
+			}
+
 	// ***
 	// *** 1. Setup: Set the SendRNow and ImmedAnswer fields to indicate which interface(s) the records need to be sent on
 	// ***
@@ -2354,7 +2848,7 @@ mDNSlocal void SendResponses(mDNS *const m)
 			rr->LastMCInterface = rr->ImmedAnswer;
 			}
 		SetNextAnnounceProbeTime(m, rr);
-		//if (rr->SendRNow) LogMsg("%-15.4a %s", &rr->v4Requester, GetRRDisplayString(m, rr));
+		//if (rr->SendRNow) LogMsg("%-15.4a %s", &rr->v4Requester, ARDisplayString(m, rr));
 		}
 
 	// ***
@@ -2366,10 +2860,9 @@ mDNSlocal void SendResponses(mDNS *const m)
 		int numDereg    = 0;
 		int numAnnounce = 0;
 		int numAnswer   = 0;
-		DNSMessage response;
-		mDNSu8 *responseptr = response.data;
+		mDNSu8 *responseptr = m->omsg.data;
 		mDNSu8 *newptr;
-		InitializeDNSMessage(&response.h, zeroID, ResponseFlags);
+		InitializeDNSMessage(&m->omsg.h, zeroID, ResponseFlags);
 	
 		// First Pass. Look for:
 		// 1. Deregistering records that need to send their goodbye packet
@@ -2384,8 +2877,8 @@ mDNSlocal void SendResponses(mDNS *const m)
 				{
 				if (rr->resrec.RecordType == kDNSRecordTypeDeregistering)
 					{
-					newptr = PutResourceRecordTTL(&response, responseptr, &response.h.numAnswers, &rr->resrec, 0);
-					if (!newptr && response.h.numAnswers) break;
+					newptr = PutResourceRecordTTL(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec, 0);
+					if (!newptr && m->omsg.h.numAnswers) break;
 					numDereg++;
 					responseptr = newptr;
 					}
@@ -2394,31 +2887,30 @@ mDNSlocal void SendResponses(mDNS *const m)
 					RData *OldRData     = rr->resrec.rdata;
 					mDNSu16 oldrdlength = rr->resrec.rdlength;
 					// See if we should send a courtesy "goodbye" for the old data before we replace it.
-					// 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)
+					if (ResourceRecordIsValidAnswer(rr) && rr->RequireGoodbye)
 						{
-						newptr = PutResourceRecordTTL(&response, responseptr, &response.h.numAnswers, &rr->resrec, 0);
-						if (!newptr && response.h.numAnswers) break;
+						newptr = PutResourceRecordTTL(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec, 0);
+						if (!newptr && m->omsg.h.numAnswers) break;
 						numDereg++;
 						responseptr = newptr;
 						}
 					// Now try to see if we can fit the update in the same packet (not fatal if we can't)
 					SetNewRData(&rr->resrec, rr->NewRData, rr->newrdlength);
-					if ((rr->resrec.RecordType & kDNSRecordTypeUniqueMask) && HaveSentEntireRRSet(m, rr, intf->InterfaceID))
+					if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
 						rr->resrec.rrclass |= kDNSClass_UniqueRRSet;		// Temporarily set the cache flush bit so PutResourceRecord will set it
-					newptr = PutResourceRecord(&response, responseptr, &response.h.numAnswers, &rr->resrec);
+					newptr = PutResourceRecord(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec);
 					rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet;			// Make sure to clear cache flush bit back to normal state
 					if (newptr) responseptr = newptr;
 					SetNewRData(&rr->resrec, OldRData, oldrdlength);
 					}
 				else
 					{
-					if ((rr->resrec.RecordType & kDNSRecordTypeUniqueMask) && HaveSentEntireRRSet(m, rr, intf->InterfaceID))
+					if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
 						rr->resrec.rrclass |= kDNSClass_UniqueRRSet;		// Temporarily set the cache flush bit so PutResourceRecord will set it
-					newptr = PutResourceRecordTTL(&response, responseptr, &response.h.numAnswers, &rr->resrec, m->SleepState ? 0 : rr->resrec.rroriginalttl);
+					newptr = PutResourceRecordTTL(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec, m->SleepState ? 0 : rr->resrec.rroriginalttl);
 					rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet;			// Make sure to clear cache flush bit back to normal state
-					if (!newptr && response.h.numAnswers) break;
+					if (!newptr && m->omsg.h.numAnswers) break;
+					rr->RequireGoodbye = !m->SleepState;
 					if (rr->LastAPTime == m->timenow) numAnnounce++; else numAnswer++;
 					responseptr = newptr;
 					}
@@ -2433,47 +2925,56 @@ mDNSlocal void SendResponses(mDNS *const m)
 		newptr = responseptr;
 		for (rr = m->ResourceRecords; rr; rr=rr->next)
 			if (rr->ImmedAdditional == intf->InterfaceID)
-				{
-				// Since additionals are optional, we clear ImmedAdditional anyway, even if we subsequently find it doesn't fit in the packet
-				rr->ImmedAdditional = mDNSNULL;
-				if (newptr && ResourceRecordIsValidAnswer(rr))
+				if (ResourceRecordIsValidAnswer(rr))
 					{
-					if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
+					// If we have at least one answer already in the packet, then plan to add additionals too
+					mDNSBool SendAdditional = (m->omsg.h.numAnswers > 0);
+					
+					// If we're not planning to send any additionals, but this record is a unique one, then
+					// make sure we haven't already sent any other members of its RRSet -- if we have, then they
+					// will have had the cache flush bit set, so now we need to finish the job and send the rest.
+					if (!SendAdditional && (rr->resrec.RecordType & kDNSRecordTypeUniqueMask))
 						{
-						// Try to find another member of this set that we're still planning to send on this interface
 						const AuthRecord *a;
 						for (a = m->ResourceRecords; a; a=a->next)
-							if (a->ImmedAdditional == intf->InterfaceID && SameResourceRecordSignature(&a->resrec, &rr->resrec)) break;
-						if (a == mDNSNULL)							// If no more members of this set found
-							rr->resrec.rrclass |= kDNSClass_UniqueRRSet;	// Temporarily set the cache flush bit so PutResourceRecord will set it
+							if (a->LastMCTime      == m->timenow &&
+								a->LastMCInterface == intf->InterfaceID &&
+								SameResourceRecordSignature(&a->resrec, &rr->resrec)) { SendAdditional = mDNStrue; break; }
 						}
-					newptr = PutResourceRecord(&response, newptr, &response.h.numAdditionals, &rr->resrec);
-					if (newptr)
+					if (!SendAdditional)					// If we don't want to send this after all,
+						rr->ImmedAdditional = mDNSNULL;		// then cancel its ImmedAdditional field
+					else if (newptr)						// Else, try to add it if we can
 						{
-						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;
+						if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
+							rr->resrec.rrclass |= kDNSClass_UniqueRRSet;	// Temporarily set the cache flush bit so PutResourceRecord will set it
+						newptr = PutResourceRecord(&m->omsg, newptr, &m->omsg.h.numAdditionals, &rr->resrec);
+						rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet;		// Make sure to clear cache flush bit back to normal state
+						if (newptr)
+							{
+							responseptr = newptr;
+							rr->ImmedAdditional = mDNSNULL;
+							rr->RequireGoodbye = mDNStrue;
+							// 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
 					}
-				}
 	
-		if (response.h.numAnswers > 0)	// We *never* send a packet with only additionals in it
+		if (m->omsg.h.numAnswers > 0 || m->omsg.h.numAdditionals)
 			{
 			debugf("SendResponses: Sending %d Deregistration%s, %d Announcement%s, %d Answer%s, %d Additional%s on %p",
 				numDereg,                  numDereg                  == 1 ? "" : "s",
 				numAnnounce,               numAnnounce               == 1 ? "" : "s",
 				numAnswer,                 numAnswer                 == 1 ? "" : "s",
-				response.h.numAdditionals, response.h.numAdditionals == 1 ? "" : "s", intf->InterfaceID);
-			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; }
+				m->omsg.h.numAdditionals, m->omsg.h.numAdditionals == 1 ? "" : "s", intf->InterfaceID);
+			if (intf->IPv4Available) mDNSSendDNSMessage(m, &m->omsg, responseptr, intf->InterfaceID, &AllDNSLinkGroup_v4, MulticastDNSPort, -1, mDNSNULL);
+			if (intf->IPv6Available) mDNSSendDNSMessage(m, &m->omsg, responseptr, intf->InterfaceID, &AllDNSLinkGroup_v6, MulticastDNSPort, -1, mDNSNULL);
+			if (!m->SuppressSending) m->SuppressSending = NonZeroTime(m->timenow + (mDNSPlatformOneSecond+9)/10);
+			if (++pktcount >= 1000) { LogMsg("SendResponses exceeded loop limit %d: giving up", pktcount); break; }
 			// There might be more things to send on this interface, so go around one more time and try again.
 			}
 		else	// Nothing more to send on this interface; go to next
@@ -2499,20 +3000,24 @@ mDNSlocal void SendResponses(mDNS *const m)
 		m->CurrentRecord = rr->next;
 
 		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
+			{ LogMsg("SendResponses: No active interface to send: %s", ARDisplayString(m, rr)); rr->SendRNow = mDNSNULL; }
 
-		if (rr->resrec.RecordType == kDNSRecordTypeDeregistering)
-			CompleteDeregistration(m, rr);
-		else
+		if (rr->ImmedAnswer)
 			{
-			rr->ImmedAnswer = mDNSNULL;
-			rr->v4Requester = zeroIPAddr;
-			rr->v6Requester = zerov6Addr;
+			if (rr->NewRData) CompleteRDataUpdate(m,rr);	// Update our rdata, clear the NewRData pointer, and return memory to the client
+	
+			if (rr->resrec.RecordType == kDNSRecordTypeDeregistering)
+				CompleteDeregistration(m, rr);		// Don't touch rr after this
+			else
+				{
+				rr->ImmedAnswer  = mDNSNULL;
+				rr->ImmedUnicast = mDNSfalse;
+				rr->v4Requester  = zerov4Addr;
+				rr->v6Requester  = zerov6Addr;
+				}
 			}
 		}
-	verbosedebugf("SendResponses: Next in %d ticks", m->NextScheduledResponse - m->timenow);
+	verbosedebugf("SendResponses: Next in %ld ticks", m->NextScheduledResponse - m->timenow);
 	}
 
 // Calling CheckCacheExpiration() is an expensive operation because it has to look at the entire cache,
@@ -2526,12 +3031,14 @@ mDNSlocal void SendResponses(mDNS *const m)
 // 4. Else, it is expiring and had an original TTL of ten seconds or less (includes explicit goodbye packets),
 //    so allow at most 1/10 second lateness
 #define CacheCheckGracePeriod(RR) (                                                   \
+	((RR)->DelayDelivery                           ) ? (mDNSPlatformOneSecond/10)   : \
 	((RR)->CRActiveQuestion == mDNSNULL            ) ? (60 * mDNSPlatformOneSecond) : \
 	((RR)->UnansweredQueries < MaxUnansweredQueries) ? (TicksTTL(rr)/50)            : \
 	((RR)->resrec.rroriginalttl > 10               ) ? (mDNSPlatformOneSecond)      : (mDNSPlatformOneSecond/10))
 
 // Note: MUST call SetNextCacheCheckTime any time we change:
 // rr->TimeRcvd
+// rr->DelayDelivery
 // rr->resrec.rroriginalttl
 // rr->UnansweredQueries
 // rr->CRActiveQuestion
@@ -2551,20 +3058,18 @@ mDNSlocal void SetNextCacheCheckTime(mDNS *const m, CacheRecord *const rr)
 
 	if (m->NextCacheCheck - (rr->NextRequiredQuery + CacheCheckGracePeriod(rr)) > 0)
 		m->NextCacheCheck = (rr->NextRequiredQuery + CacheCheckGracePeriod(rr));
+	
+	if (rr->DelayDelivery)
+		if (m->NextCacheCheck - rr->DelayDelivery > 0)
+			m->NextCacheCheck = rr->DelayDelivery;
 	}
 
-#define kDefaultReconfirmTimeForNoAnswer        ((mDNSu32)mDNSPlatformOneSecond * 45)
+#define kDefaultReconfirmTimeForNoAnswer        ((mDNSu32)mDNSPlatformOneSecond * 15)
 #define kDefaultReconfirmTimeForCableDisconnect ((mDNSu32)mDNSPlatformOneSecond *  5)
 #define kMinimumReconfirmTime                   ((mDNSu32)mDNSPlatformOneSecond *  5)
 
 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
@@ -2579,7 +3084,7 @@ mDNSlocal mStatus mDNS_Reconfirm_internal(mDNS *const m, CacheRecord *const rr,
 		rr->resrec.rroriginalttl     = interval * 4 / mDNSPlatformOneSecond;
 		SetNextCacheCheckTime(m, rr);
 		}
-	debugf("mDNS_Reconfirm_internal:%5ld ticks to go for %s", RRExpireTime(rr) - m->timenow, GetRRDisplayString(m, rr));
+	debugf("mDNS_Reconfirm_internal:%5ld ticks to go for %s", RRExpireTime(rr) - m->timenow, CRDisplayString(m, rr));
 	return(mStatus_NoError);
 	}
 
@@ -2591,7 +3096,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) && m->CanReceiveUnicast;
+	mDNSBool ucast = (q->LargeAnswers || q->ThisQInterval <= InitialQuestionInterval*2) && m->CanReceiveUnicastOn5353;
 	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));
@@ -2812,17 +3317,16 @@ mDNSlocal void SendQueries(mDNS *const m)
 		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;
+				mDNSu8       *qptr        = m->omsg.data;
+				const mDNSu8 *const limit = m->omsg.data + sizeof(m->omsg.data);
+				InitializeDNSMessage(&m->omsg.h, q->TargetQID, QueryFlags);
+				qptr = putQuestion(&m->omsg, qptr, limit, &q->qname, q->qtype, q->qclass);
+				mDNSSendDNSMessage(m, &m->omsg, qptr, mDNSInterface_Any, &q->Target, q->TargetPort, -1, mDNSNULL);
+				q->ThisQInterval   *= 2;
+				q->LastQTime        = m->timenow;
+				q->LastQTxTime      = m->timenow;
+				q->RecentAnswerPkts = 0;
+				q->SendQNow         = mDNSNULL;
 				m->ExpectUnicastResponse = m->timenow;
 				}
 	
@@ -2870,8 +3374,8 @@ mDNSlocal void SendQueries(mDNS *const m)
 				// then we consider it recent enough that we don't need to do an identical query ourselves.
 				ExpireDupSuppressInfo(q->DupSuppress, m->timenow - q->ThisQInterval/2);
 
-				q->LastQTxTime   = m->timenow;
-				q->RecentAnswers = 0;
+				q->LastQTxTime      = m->timenow;
+				q->RecentAnswerPkts = 0;
 				}
 			// For all questions (not just the ones we're sending) check what the next scheduled event will be
 			SetNextQueryTime(m,q);
@@ -2917,7 +3421,7 @@ mDNSlocal void SendQueries(mDNS *const m)
 					for (r2 = m->DuplicateRecords; r2; r2=r2->next)
 						if (r2->resrec.RecordType == kDNSRecordTypeUnique && RecordIsLocalDuplicate(r2, rr))
 							r2->ProbeCount = 0;
-					CompleteProbing(m, rr);
+					AcknowledgeRecord(m, rr);
 					}
 				}
 			}
@@ -2927,7 +3431,7 @@ mDNSlocal void SendQueries(mDNS *const m)
 			AuthRecord *rr = m->CurrentRecord;
 			m->CurrentRecord = rr->next;
 			if (rr->resrec.RecordType == kDNSRecordTypeUnique && rr->ProbeCount == 0)
-				CompleteProbing(m, rr);
+				AcknowledgeRecord(m, rr);
 			}
 		}
 
@@ -2935,9 +3439,8 @@ mDNSlocal void SendQueries(mDNS *const m)
 	while (intf)
 		{
 		AuthRecord *rr;
-		DNSMessage query;
-		mDNSu8 *queryptr = query.data;
-		InitializeDNSMessage(&query.h, zeroID, QueryFlags);
+		mDNSu8 *queryptr = m->omsg.data;
+		InitializeDNSMessage(&m->omsg.h, zeroID, QueryFlags);
 		if (KnownAnswerList) verbosedebugf("SendQueries:   KnownAnswerList set... Will continue from previous packet");
 		if (!KnownAnswerList)
 			{
@@ -2949,12 +3452,12 @@ mDNSlocal void SendQueries(mDNS *const m)
 			for (q = m->Questions; q; q=q->next)
 				if (q->SendQNow == intf->InterfaceID)
 					{
-					debugf("SendQueries: %s question for %##s (%s) at %lu forecast total %lu",
+					debugf("SendQueries: %s question for %##s (%s) at %d forecast total %d",
 						SuppressOnThisInterface(q->DupSuppress, intf) ? "Suppressing" : "Putting    ",
-						q->qname.c, DNSTypeName(q->qtype), queryptr - query.data, queryptr + answerforecast - query.data);
+						q->qname.c, DNSTypeName(q->qtype), queryptr - m->omsg.data, queryptr + answerforecast - m->omsg.data);
 					// If we're suppressing this question, or we successfully put it, update its SendQNow state
 					if (SuppressOnThisInterface(q->DupSuppress, intf) ||
-						BuildQuestion(m, &query, &queryptr, q, &kalistptr, &answerforecast))
+						BuildQuestion(m, &m->omsg, &queryptr, q, &kalistptr, &answerforecast))
 							q->SendQNow = (q->InterfaceID || !q->SendOnAll) ? mDNSNULL : GetNextActiveInterfaceID(intf);
 					}
 
@@ -2962,10 +3465,10 @@ 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) && m->CanReceiveUnicast;
+					mDNSBool ucast = (rr->ProbeCount >= DefaultProbeCountForTypeUnique-1) && m->CanReceiveUnicastOn5353;
 					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));
+					const mDNSu8 *const limit = m->omsg.data + ((m->omsg.h.numQuestions) ? NormalMaxDNSMessageData : AbsoluteMaxDNSMessageData);
+					mDNSu8 *newptr = putQuestion(&m->omsg, queryptr, limit, &rr->resrec.name, kDNSQType_ANY, (mDNSu16)(rr->resrec.rrclass | ucbit));
 					// We forecast: compressed name (2) type (2) class (2) TTL (4) rdlength (2) rdata (n)
 					mDNSu32 forecast = answerforecast + 12 + rr->resrec.rdestimate;
 					if (newptr && newptr + forecast < limit)
@@ -2979,7 +3482,7 @@ mDNSlocal void SendQueries(mDNS *const m)
 					else
 						{
 						verbosedebugf("SendQueries:   Retracting Question %##s (%s)", rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype));
-						query.h.numQuestions--;
+						m->omsg.h.numQuestions--;
 						}
 					}
 				}
@@ -2989,10 +3492,10 @@ mDNSlocal void SendQueries(mDNS *const m)
 			{
 			CacheRecord *rr = KnownAnswerList;
 			mDNSu32 SecsSinceRcvd = ((mDNSu32)(m->timenow - rr->TimeRcvd)) / mDNSPlatformOneSecond;
-			mDNSu8 *newptr = PutResourceRecordTTL(&query, queryptr, &query.h.numAnswers, &rr->resrec, rr->resrec.rroriginalttl - SecsSinceRcvd);
+			mDNSu8 *newptr = PutResourceRecordTTL(&m->omsg, queryptr, &m->omsg.h.numAnswers, &rr->resrec, rr->resrec.rroriginalttl - SecsSinceRcvd);
 			if (newptr)
 				{
-				verbosedebugf("SendQueries:   Put %##s (%s) at %lu - %lu", rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype), queryptr - query.data, newptr - query.data);
+				verbosedebugf("SendQueries:   Put %##s (%s) at %d - %d", rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype), queryptr - m->omsg.data, newptr - m->omsg.data);
 				queryptr = newptr;
 				KnownAnswerList = rr->NextInKAList;
 				rr->NextInKAList = mDNSNULL;
@@ -3001,9 +3504,9 @@ mDNSlocal void SendQueries(mDNS *const m)
 				{
 				// If we ran out of space and we have more than one question in the packet, that's an error --
 				// we shouldn't have put more than one question if there was a risk of us running out of space.
-				if (query.h.numQuestions > 1)
-					LogMsg("SendQueries:   Put %d answers; No more space for known answers", query.h.numAnswers);
-				query.h.flags.b[0] |= kDNSFlag0_TC;
+				if (m->omsg.h.numQuestions > 1)
+					LogMsg("SendQueries:   Put %d answers; No more space for known answers", m->omsg.h.numAnswers);
+				m->omsg.h.flags.b[0] |= kDNSFlag0_TC;
 				break;
 				}
 			}
@@ -3011,24 +3514,24 @@ mDNSlocal void SendQueries(mDNS *const m)
 		for (rr = m->ResourceRecords; rr; rr=rr->next)
 			if (rr->IncludeInProbe)
 				{
-				mDNSu8 *newptr = PutResourceRecord(&query, queryptr, &query.h.numAuthorities, &rr->resrec);
+				mDNSu8 *newptr = PutResourceRecord(&m->omsg, queryptr, &m->omsg.h.numAuthorities, &rr->resrec);
 				rr->IncludeInProbe = mDNSfalse;
 				if (newptr) queryptr = newptr;
 				else LogMsg("SendQueries:   How did we fail to have space for the Update record %##s (%s)?",
 					rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype));
 				}
 		
-		if (queryptr > query.data)
+		if (queryptr > m->omsg.data)
 			{
-			if ((query.h.flags.b[0] & kDNSFlag0_TC) && query.h.numQuestions > 1)
-				LogMsg("SendQueries: Should not have more than one question (%d) in a truncated packet\n", query.h.numQuestions);
+			if ((m->omsg.h.flags.b[0] & kDNSFlag0_TC) && m->omsg.h.numQuestions > 1)
+				LogMsg("SendQueries: Should not have more than one question (%d) in a truncated packet", m->omsg.h.numQuestions);
 			debugf("SendQueries:   Sending %d Question%s %d Answer%s %d Update%s on %p",
-				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);
-			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
+				m->omsg.h.numQuestions,   m->omsg.h.numQuestions   == 1 ? "" : "s",
+				m->omsg.h.numAnswers,     m->omsg.h.numAnswers     == 1 ? "" : "s",
+				m->omsg.h.numAuthorities, m->omsg.h.numAuthorities == 1 ? "" : "s", intf->InterfaceID);
+			if (intf->IPv4Available) mDNSSendDNSMessage(m, &m->omsg, queryptr, intf->InterfaceID, &AllDNSLinkGroup_v4, MulticastDNSPort, -1, mDNSNULL);
+			if (intf->IPv6Available) mDNSSendDNSMessage(m, &m->omsg, queryptr, intf->InterfaceID, &AllDNSLinkGroup_v6, MulticastDNSPort, -1, mDNSNULL);
+			if (!m->SuppressSending) m->SuppressSending = NonZeroTime(m->timenow + mDNSPlatformOneSecond/10);
 			if (++pktcount >= 1000)
 				{ LogMsg("SendQueries exceeded loop limit %d: giving up", pktcount); break; }
 			// There might be more records left in the known answer list, or more questions to send
@@ -3050,7 +3553,7 @@ mDNSlocal void SendQueries(mDNS *const m)
 		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; }
+				{ LogMsg("SendQueries: No active interface to send: %s", ARDisplayString(m, rr)); rr->SendRNow = mDNSNULL; }
 		}
 	}
 
@@ -3067,8 +3570,11 @@ mDNSlocal void AnswerQuestionWithResourceRecord(mDNS *const m, DNSQuestion *q, C
 	verbosedebugf("AnswerQuestionWithResourceRecord:%4lu %s TTL%6lu %##s (%s)",
 		q->CurrentAnswers, AddRecord ? "Add" : "Rmv", rr->resrec.rroriginalttl, rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype));
 
+	// Note: Use caution here. In the case of records with rr->DelayDelivery set, AnswerQuestionWithResourceRecord(... mDNStrue)
+	// may be called twice, once when the record is received, and again when it's time to notify local clients.
+	// If any counters or similar are added here, care must be taken to ensure that they are not double-incremented by this.
+
 	rr->LastUsed = m->timenow;
-	rr->UseCount++;
 	if (ActiveQuestion(q) && rr->CRActiveQuestion != q)
 		{
 		if (!rr->CRActiveQuestion) m->rrcache_active++;	// If not previously active, increment rrcache_active count
@@ -3076,15 +3582,47 @@ mDNSlocal void AnswerQuestionWithResourceRecord(mDNS *const m, DNSQuestion *q, C
 		SetNextCacheCheckTime(m, rr);
 		}
 
-	// CAUTION: MUST NOT do anything more with q after calling q->Callback(), because the client's callback function
-	// is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc.
-	// Right now the only routines that call AnswerQuestionWithResourceRecord() are CacheRecordAdd(), CacheRecordRmv()
-	// and AnswerNewQuestion(), and all of them use the "m->CurrentQuestion" mechanism to protect against questions
-	// being deleted out from under them.
+	if (rr->DelayDelivery) return;		// We'll come back later when CacheRecordDeferredAdd() calls us
+
 	m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
 	if (q->QuestionCallback)
 		q->QuestionCallback(m, q, &rr->resrec, AddRecord);
 	m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
+	// CAUTION: MUST NOT do anything more with q after calling q->QuestionCallback(), because the client's callback function
+	// is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc.
+	// Right now the only routines that call AnswerQuestionWithResourceRecord() are CacheRecordAdd(), CacheRecordRmv()
+	// and AnswerNewQuestion(), and all of them use the "m->CurrentQuestion" mechanism to protect against questions
+	// being deleted out from under them.
+	}
+
+mDNSlocal void CacheRecordDeferredAdd(mDNS *const m, CacheRecord *rr)
+	{
+	rr->DelayDelivery = 0;
+	if (m->CurrentQuestion) LogMsg("CacheRecordDeferredAdd ERROR m->CurrentQuestion already set");
+	m->CurrentQuestion = m->Questions;
+	while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions)
+		{
+		DNSQuestion *q = m->CurrentQuestion;
+		m->CurrentQuestion = q->next;
+		if (ResourceRecordAnswersQuestion(&rr->resrec, q))
+			AnswerQuestionWithResourceRecord(m, q, rr, mDNStrue);
+		}
+	m->CurrentQuestion = mDNSNULL;
+	}
+
+mDNSlocal mDNSs32 CheckForSoonToExpireRecords(mDNS *const m, const domainname *const name, const mDNSu32 namehash, const mDNSu32 slot)
+	{
+	const mDNSs32 threshhold = m->timenow + mDNSPlatformOneSecond;	// See if there are any records expiring within one second
+	const mDNSs32 start      = m->timenow - 0x10000000;
+	mDNSs32 delay = start;
+	CacheRecord *rr;
+	for (rr = m->rrcache_hash[slot]; rr; rr=rr->next)
+		if (rr->resrec.namehash == namehash && SameDomainName(&rr->resrec.name, name))
+			if (threshhold - RRExpireTime(rr) >= 0)		// If we have records about to expire within a second
+				if (delay - RRExpireTime(rr) < 0)		// then delay until after they've been deleted
+					delay = RRExpireTime(rr);
+	if (delay - start > 0) return(delay ? delay : 1);	// Make sure we return non-zero if we want to delay
+	else return(0);
 	}
 
 // CacheRecordAdd is only called from mDNSCoreReceiveResponse, *never* directly as a result of a client API call.
@@ -3110,19 +3648,32 @@ mDNSlocal void CacheRecordAdd(mDNS *const m, CacheRecord *rr)
 			// We must be at least at the eight-second interval to do this. If we're at the four-second interval, or less,
 			// there's not much benefit accelerating because we will anyway send another query within a few seconds.
 			// The first reset query is sent out randomized over the next four seconds to reduce possible synchronization between machines.
-			if (ActiveQuestion(q) && ++q->RecentAnswers >= 10 &&
-				q->ThisQInterval > InitialQuestionInterval*16 && m->timenow - q->LastQTxTime < mDNSPlatformOneSecond)
+			if (q->LastAnswerPktNum != m->PktNum)
 				{
-				LogMsg("CacheRecordAdd: %##s (%s) got immediate answer burst; restarting exponential backoff sequence",
-					q->qname.c, DNSTypeName(q->qtype));
-				q->LastQTime     = m->timenow - InitialQuestionInterval + (mDNSs32)mDNSRandom((mDNSu32)mDNSPlatformOneSecond*4);
-				q->ThisQInterval = InitialQuestionInterval;
-				SetNextQueryTime(m,q);
+				q->LastAnswerPktNum = m->PktNum;
+				if (ActiveQuestion(q) && ++q->RecentAnswerPkts >= 10 &&
+					q->ThisQInterval > InitialQuestionInterval*16 && m->timenow - q->LastQTxTime < mDNSPlatformOneSecond)
+					{
+					LogMsg("CacheRecordAdd: %##s (%s) got immediate answer burst; restarting exponential backoff sequence",
+						q->qname.c, DNSTypeName(q->qtype));
+					q->LastQTime     = m->timenow - InitialQuestionInterval + (mDNSs32)mDNSRandom((mDNSu32)mDNSPlatformOneSecond*4);
+					q->ThisQInterval = InitialQuestionInterval;
+					SetNextQueryTime(m,q);
+					}
 				}
 			verbosedebugf("CacheRecordAdd %p %##s (%s) %lu", rr, rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype), rr->resrec.rroriginalttl);
 			q->CurrentAnswers++;
 			if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers++;
 			if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers++;
+			if (q->CurrentAnswers > 4000)
+				{
+				static int msgcount = 0;
+				if (msgcount++ < 10)
+					LogMsg("CacheRecordAdd: %##s (%s) has %d answers; shedding records to resist DOS attack",
+						q->qname.c, DNSTypeName(q->qtype), q->CurrentAnswers);
+				rr->resrec.rroriginalttl = 1;
+				rr->UnansweredQueries = MaxUnansweredQueries;
+				}
 			AnswerQuestionWithResourceRecord(m, q, rr, mDNStrue);
 			// MUST NOT dereference q again after calling AnswerQuestionWithResourceRecord()
 			}
@@ -3179,7 +3730,9 @@ mDNSlocal void ReleaseCacheRR(mDNS *const m, CacheRecord *r)
 	m->rrcache_totalused--;
 	}
 
-mDNSlocal void CheckCacheExpiration(mDNS *const m, mDNSu32 slot)
+// Note: We want to be careful that we deliver all the CacheRecordRmv calls before delivering CacheRecordDeferredAdd calls
+// The in-order nature of the cache lists ensures that all callbacks for old records are delivered before callbacks for newer records
+mDNSlocal void CheckCacheExpiration(mDNS *const m, const mDNSu32 slot)
 	{
 	CacheRecord **rp = &(m->rrcache_hash[slot]);
 
@@ -3193,7 +3746,7 @@ mDNSlocal void CheckCacheExpiration(mDNS *const m, mDNSu32 slot)
 		if (m->timenow - event >= 0)	// If expired, delete it
 			{
 			*rp = rr->next;				// Cut it from the list
-			verbosedebugf("CheckCacheExpiration: Deleting %s", GetRRDisplayString(m, rr));
+			verbosedebugf("CheckCacheExpiration: Deleting %s", CRDisplayString(m, rr));
 			if (rr->CRActiveQuestion)	// If this record has one or more active questions, tell them it's going away
 				{
 				CacheRecordRmv(m, rr);
@@ -3204,18 +3757,24 @@ mDNSlocal void CheckCacheExpiration(mDNS *const m, mDNSu32 slot)
 			}
 		else							// else, not expired; see if we need to query
 			{
-			if (rr->CRActiveQuestion && rr->UnansweredQueries < MaxUnansweredQueries)
+			if (rr->DelayDelivery && rr->DelayDelivery - m->timenow > 0)
+				event = rr->DelayDelivery;
+			else
 				{
-				if (m->timenow - rr->NextRequiredQuery < 0)		// If not yet time for next query
-					event = rr->NextRequiredQuery;				// then just record when we want the next query
-				else											// else trigger our question to go out now
+				if (rr->DelayDelivery) CacheRecordDeferredAdd(m, rr);
+				if (rr->CRActiveQuestion && rr->UnansweredQueries < MaxUnansweredQueries)
 					{
-					// Set NextScheduledQuery to timenow so that SendQueries() will run.
-					// SendQueries() will see that we have records close to expiration, and send FEQs for them.
-					m->NextScheduledQuery = m->timenow;
-					// After sending the query we'll increment UnansweredQueries and call SetNextCacheCheckTime(),
-					// which will correctly update m->NextCacheCheck for us
-					event = m->timenow + 0x3FFFFFFF;
+					if (m->timenow - rr->NextRequiredQuery < 0)		// If not yet time for next query
+						event = rr->NextRequiredQuery;				// then just record when we want the next query
+					else											// else trigger our question to go out now
+						{
+						// Set NextScheduledQuery to timenow so that SendQueries() will run.
+						// SendQueries() will see that we have records close to expiration, and send FEQs for them.
+						m->NextScheduledQuery = m->timenow;
+						// After sending the query we'll increment UnansweredQueries and call SetNextCacheCheckTime(),
+						// which will correctly update m->NextCacheCheck for us
+						event = m->timenow + 0x3FFFFFFF;
+						}
 					}
 				}
 			if (m->NextCacheCheck - (event + CacheCheckGracePeriod(rr)) > 0)
@@ -3223,7 +3782,7 @@ mDNSlocal void CheckCacheExpiration(mDNS *const m, mDNSu32 slot)
 			rp = &rr->next;
 			}
 		}
-	if (m->rrcache_tail[slot] != rp) debugf("CheckCacheExpiration: Updating m->rrcache_tail[%d] from %p to %p", slot, m->rrcache_tail[slot], rp);
+	if (m->rrcache_tail[slot] != rp) verbosedebugf("CheckCacheExpiration: Updating m->rrcache_tail[%lu] from %p to %p", slot, m->rrcache_tail[slot], rp);
 	m->rrcache_tail[slot] = rp;
 	m->lock_rrcache = 0;
 	}
@@ -3233,7 +3792,7 @@ mDNSlocal void AnswerNewQuestion(mDNS *const m)
 	mDNSBool ShouldQueryImmediately = mDNStrue;
 	CacheRecord *rr;
 	DNSQuestion *q = m->NewQuestions;		// Grab the question we're going to answer
-	mDNSu32 slot = HashSlot(&q->qname);
+	const mDNSu32 slot = HashSlot(&q->qname);
 
 	verbosedebugf("AnswerNewQuestion: Answering %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
 
@@ -3262,7 +3821,8 @@ mDNSlocal void AnswerNewQuestion(mDNS *const m)
 
 			// If this record set is marked unique, then that means we can reasonably assume we have the whole set
 			// -- we don't need to rush out on the network and query immediately to see if there are more answers out there
-			if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) ShouldQueryImmediately = mDNSfalse;
+			if ((rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) || (q->ExpectUnique))
+				ShouldQueryImmediately = mDNSfalse;
 			q->CurrentAnswers++;
 			if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers++;
 			if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers++;
@@ -3287,7 +3847,7 @@ mDNSlocal void AnswerNewQuestion(mDNS *const m)
 mDNSlocal void AnswerLocalOnlyQuestionWithResourceRecord(mDNS *const m, DNSQuestion *q, AuthRecord *rr, mDNSBool AddRecord)
 	{
 	// Indicate that we've given at least one positive answer for this record, so we should be prepared to send a goodbye for it
-	if (AddRecord) rr->AnnounceCount = InitialAnnounceCount - 1;
+	if (AddRecord) rr->RequireGoodbye = mDNStrue;
 	m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
 	if (q->QuestionCallback)
 		q->QuestionCallback(m, q, &rr->resrec, AddRecord);
@@ -3301,9 +3861,10 @@ mDNSlocal void AnswerNewLocalOnlyQuestion(mDNS *const m)
 
 	debugf("AnswerNewLocalOnlyQuestion: Answering %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
 
-	if (m->CurrentQuestion) LogMsg("AnswerNewQuestion ERROR m->CurrentQuestion already set");
+	if (m->CurrentQuestion) LogMsg("AnswerNewLocalOnlyQuestion ERROR m->CurrentQuestion already set");
 	m->CurrentQuestion = q;		// Indicate which question we're answering, so we'll know if it gets deleted
 
+	if (m->CurrentRecord) LogMsg("AnswerNewLocalOnlyQuestion ERROR m->CurrentRecord already set");
 	m->CurrentRecord = m->LocalOnlyRecords;
 	while (m->CurrentRecord && m->CurrentRecord != m->NewLocalOnlyRecords)
 		{
@@ -3318,6 +3879,7 @@ mDNSlocal void AnswerNewLocalOnlyQuestion(mDNS *const m)
 		}
 
 	m->CurrentQuestion = mDNSNULL;
+	m->CurrentRecord   = mDNSNULL;
 	}
 
 mDNSlocal void AnswerLocalOnlyQuestions(mDNS *const m, AuthRecord *rr, mDNSBool AddRecord)
@@ -3332,7 +3894,7 @@ mDNSlocal void AnswerLocalOnlyQuestions(mDNS *const m, AuthRecord *rr, mDNSBool
 			{
 			debugf("AnswerLocalOnlyQuestions %p %##s (%s) %lu", rr, rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype), rr->resrec.rroriginalttl);
 			AnswerLocalOnlyQuestionWithResourceRecord(m, q, rr, AddRecord);
-			// MUST NOT dereference q again after calling AnswerQuestionWithResourceRecord()
+			// MUST NOT dereference q again after calling AnswerLocalOnlyQuestionWithResourceRecord()
 			}
 		}
 	m->CurrentQuestion = mDNSNULL;
@@ -3411,7 +3973,7 @@ mDNSlocal CacheRecord *GetFreeCacheRR(mDNS *const m, mDNSu16 RDLength)
 					ReleaseCacheRR(m, rr);
 					}
 				}
-			if (m->rrcache_tail[slot] != rp) debugf("GetFreeCacheRR: Updating m->rrcache_tail[%d] from %p to %p", slot, m->rrcache_tail[slot], rp);
+			if (m->rrcache_tail[slot] != rp) verbosedebugf("GetFreeCacheRR: Updating m->rrcache_tail[%lu] from %p to %p", slot, m->rrcache_tail[slot], rp);
 			m->rrcache_tail[slot] = rp;
 			}
 		#if MDNS_DEBUGMSGS
@@ -3434,9 +3996,9 @@ mDNSlocal CacheRecord *GetFreeCacheRR(mDNS *const m, mDNSu16 RDLength)
 			else                         m->rrcache_report += 100;
 			}
 		mDNSPlatformMemZero(r, sizeof(*r));
-		r->resrec.rdata = (RData*)&r->rdatastorage;		// By default, assume we're usually going to be using local storage
+		r->resrec.rdata = (RData*)&r->rdatastorage;	// By default, assume we're usually going to be using local storage
 	
-		if (RDLength > InlineCacheRDSize)		// If RDLength is too big, allocate extra storage
+		if (RDLength > InlineCacheRDSize)			// If RDLength is too big, allocate extra storage
 			{
 			r->resrec.rdata = (RData*)mDNSPlatformMemAllocate(sizeofRDataHeader + RDLength);
 			if (r->resrec.rdata) r->resrec.rdata->MaxRDLength = r->resrec.rdlength = RDLength;
@@ -3462,89 +4024,26 @@ mDNSlocal void PurgeCacheResourceRecord(mDNS *const m, CacheRecord *rr)
 	SetNextCacheCheckTime(m, rr);
 	}
 
-mDNSlocal void mDNS_Lock(mDNS *const m)
+mDNSexport mDNSs32 mDNS_TimeNow(const mDNS *const m)
 	{
-	// MUST grab the platform lock FIRST!
+	mDNSs32 time;
 	mDNSPlatformLock(m);
-
-	// Normally, mDNS_reentrancy is zero and so is mDNS_busy
-	// However, when we call a client callback mDNS_busy is one, and we increment mDNS_reentrancy too
-	// If that client callback does mDNS API calls, mDNS_reentrancy and mDNS_busy will both be one
-	// If mDNS_busy != mDNS_reentrancy that's a bad sign
-	if (m->mDNS_busy != m->mDNS_reentrancy)
-		LogMsg("mDNS_Lock: Locking failure! mDNS_busy (%ld) != mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
-
-	// If this is an initial entry into the mDNSCore code, set m->timenow
-	// else, if this is a re-entrant entry into the mDNSCore code, m->timenow should already be set
-	if (m->mDNS_busy == 0)
-		{
-		if (m->timenow)
-			LogMsg("mDNS_Lock: m->timenow already set (%ld/%ld)", m->timenow, mDNSPlatformTimeNow() + m->timenow_adjust);
-		m->timenow = mDNSPlatformTimeNow() + m->timenow_adjust;
-		if (m->timenow == 0) m->timenow = 1;
-		}
-	else if (m->timenow == 0)
-		{
-		LogMsg("mDNS_Lock: m->mDNS_busy is %ld but m->timenow not set", m->mDNS_busy);
-		m->timenow = mDNSPlatformTimeNow() + m->timenow_adjust;
-		if (m->timenow == 0) m->timenow = 1;
-		}
-
-	if (m->timenow_last - m->timenow > 0)
+	if (m->mDNS_busy)
 		{
-		m->timenow_adjust += m->timenow_last - m->timenow;
-		LogMsg("mDNSPlatformTimeNow went backwards by %ld ticks; setting correction factor to %ld", m->timenow_last - m->timenow, m->timenow_adjust);
-		m->timenow = m->timenow_last;
+		LogMsg("mDNS_TimeNow called while holding mDNS lock. This is incorrect. Code protected by lock should just use m->timenow.");
+		if (!m->timenow) LogMsg("mDNS_TimeNow: m->mDNS_busy is %ld but m->timenow not set", m->mDNS_busy);
 		}
-	m->timenow_last = m->timenow;
-
-	// Increment mDNS_busy so we'll recognise re-entrant calls
-	m->mDNS_busy++;
-	}
-
-mDNSlocal mDNSs32 GetNextScheduledEvent(const mDNS *const m)
-	{
-	mDNSs32 e = m->timenow + 0x78000000;
-	if (m->mDNSPlatformStatus != mStatus_NoError || m->SleepState) return(e);
-	if (m->NewQuestions)            return(m->timenow);
-	if (m->NewLocalOnlyQuestions)   return(m->timenow);
-	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;
-	if (e - m->NextScheduledResponse > 0) e = m->NextScheduledResponse;
-	return(e);
-	}
-
-mDNSlocal void mDNS_Unlock(mDNS *const m)
-	{
-	// Decrement mDNS_busy
-	m->mDNS_busy--;
 	
-	// Check for locking failures
-	if (m->mDNS_busy != m->mDNS_reentrancy)
-		LogMsg("mDNS_Unlock: Locking failure! mDNS_busy (%ld) != mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
-
-	// If this is a final exit from the mDNSCore code, set m->NextScheduledEvent and clear m->timenow
-	if (m->mDNS_busy == 0)
-		{
-		m->NextScheduledEvent = GetNextScheduledEvent(m);
-		if (m->timenow == 0) LogMsg("mDNS_Unlock: ERROR! m->timenow aready zero");
-		m->timenow = 0;
-		}
-
-	// MUST release the platform lock LAST!
+	if (m->timenow) time = m->timenow;
+	else            time = mDNSPlatformRawTime() + m->timenow_adjust;
 	mDNSPlatformUnlock(m);
+	return(time);
 	}
 
 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;
@@ -3567,7 +4066,11 @@ mDNSexport mDNSs32 mDNS_Execute(mDNS *const m)
 			}
 	
 		// 4. See if we can answer any of our new local questions from the cache
-		for (i=0; m->NewQuestions && i<1000; i++) AnswerNewQuestion(m);
+		for (i=0; m->NewQuestions && i<1000; i++)
+			{
+			if (m->NewQuestions->DelayAnswering && m->timenow - m->NewQuestions->DelayAnswering < 0) break;
+			AnswerNewQuestion(m);
+			}
 		if (i >= 1000) debugf("mDNS_Execute: AnswerNewQuestion exceeded loop limit");
 		
 		for (i=0; m->DiscardLocalOnlyRecords && i<1000; i++) DiscardLocalOnlyRecords(m);
@@ -3636,7 +4139,9 @@ 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).
 
+#ifndef UNICAST_DISABLED
 	uDNS_Execute(m);
+#endif
 	mDNS_Unlock(m);		// Calling mDNS_Unlock is what gives m->NextScheduledEvent its new value
 	return(m->NextScheduledEvent);
 	}
@@ -3663,10 +4168,12 @@ mDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleepstate)
 
 	if (sleepstate)
 		{
-		uDNS_SuspendLLQs(m);
+#ifndef UNICAST_DISABLED
+		uDNS_Sleep(m);
+#endif		
 		// Mark all the records we need to deregister and send them
 		for (rr = m->ResourceRecords; rr; rr=rr->next)
-			if (rr->resrec.RecordType == kDNSRecordTypeShared && rr->AnnounceCount < InitialAnnounceCount)
+			if (rr->resrec.RecordType == kDNSRecordTypeShared && rr->RequireGoodbye)
 				rr->ImmedAnswer = mDNSInterfaceMark;
 		SendResponses(m);
 		}
@@ -3676,15 +4183,16 @@ mDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleepstate)
 		mDNSu32 slot;
 		CacheRecord *cr;
 
-		uDNS_RestartLLQs(m);
-
+#ifndef UNICAST_DISABLED
+		uDNS_Wake(m);
+#endif
         // 1. Retrigger all our questions
 		for (q = m->Questions; q; q=q->next)				// Scan our list of questions
 			if (ActiveQuestion(q))
 				{
-				q->ThisQInterval = InitialQuestionInterval;	// MUST be > zero for an active question
-				q->LastQTime     = m->timenow - q->ThisQInterval;
-				q->RecentAnswers = 0;
+				q->ThisQInterval    = InitialQuestionInterval;	// MUST be > zero for an active question
+				q->LastQTime        = m->timenow - q->ThisQInterval;
+				q->RecentAnswerPkts = 0;
 				ExpireDupSuppressInfo(q->DupSuppress, m->timenow);
 				m->NextScheduledQuery = m->timenow;
 				}
@@ -3699,13 +4207,11 @@ mDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleepstate)
 		for (rr = m->ResourceRecords; rr; rr=rr->next)
 			{
 			if (rr->resrec.RecordType == kDNSRecordTypeVerified && !rr->DependentOn) rr->resrec.RecordType = kDNSRecordTypeUnique;
-			rr->ProbeCount        = DefaultProbeCountForRecordType(rr->resrec.RecordType);
-			if (rr->AnnounceCount < ReannounceCount)
-				rr->AnnounceCount = ReannounceCount;
-			rr->ThisAPInterval    = DefaultAPIntervalForRecordType(rr->resrec.RecordType);
+			rr->ProbeCount     = DefaultProbeCountForRecordType(rr->resrec.RecordType);
+			rr->AnnounceCount  = InitialAnnounceCount;
+			rr->ThisAPInterval = DefaultAPIntervalForRecordType(rr->resrec.RecordType);
 			InitializeLastAPTime(m, rr);
 			}
-
 		}
 
 	mDNS_Unlock(m);
@@ -3717,21 +4223,6 @@ mDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleepstate)
 #pragma mark - Packet Reception Functions
 #endif
 
-mDNSlocal void AddRecordToResponseList(AuthRecord ***nrpp, AuthRecord *rr, AuthRecord *add)
-	{
-	if (rr->NextResponse == mDNSNULL && *nrpp != &rr->NextResponse)
-		{
-		**nrpp = rr;
-		// NR_AdditionalTo must point to a record with NR_AnswerTo set (and not NR_AdditionalTo)
-		// If 'add' does not meet this requirement, then follow its NR_AdditionalTo pointer to a record that does
-		// The referenced record will definitely be acceptable (by recursive application of this rule)
-		if (add && add->NR_AdditionalTo) add = add->NR_AdditionalTo;
-		rr->NR_AdditionalTo = add;
-		*nrpp = &rr->NextResponse;
-		}
-	debugf("AddRecordToResponseList: %##s (%s) already in list", rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype));
-	}
-
 #define MustSendRecord(RR) ((RR)->NR_AnswerTo || (RR)->NR_AdditionalTo)
 
 mDNSlocal mDNSu8 *GenerateUnicastResponse(const DNSMessage *const query, const mDNSu8 *const end,
@@ -3913,17 +4404,16 @@ mDNSlocal void ResolveSimultaneousProbe(mDNS *const m, const DNSMessage *const q
 
 	for (i = 0; i < query->h.numAuthorities; i++)
 		{
-		LargeCacheRecord pkt;
-		ptr = GetLargeResourceRecord(m, query, ptr, end, q->InterfaceID, 0, &pkt);
+		ptr = GetLargeResourceRecord(m, query, ptr, end, q->InterfaceID, kDNSRecordTypePacketAuth, &m->rec);
 		if (!ptr) break;
-		if (ResourceRecordAnswersQuestion(&pkt.r.resrec, q))
+		if (ResourceRecordAnswersQuestion(&m->rec.r.resrec, q))
 			{
 			FoundUpdate = mDNStrue;
-			if (PacketRRConflict(m, our, &pkt.r))
+			if (PacketRRConflict(m, our, &m->rec.r))
 				{
-				int result          = (int)our->resrec.rrclass - (int)pkt.r.resrec.rrclass;
-				if (!result) result = (int)our->resrec.rrtype  - (int)pkt.r.resrec.rrtype;
-				if (!result) result = CompareRData(our, &pkt.r);
+				int result          = (int)our->resrec.rrclass - (int)m->rec.r.resrec.rrclass;
+				if (!result) result = (int)our->resrec.rrtype  - (int)m->rec.r.resrec.rrtype;
+				if (!result) result = CompareRData(our, &m->rec.r);
 				switch (result)
 					{
 					case  1:	debugf("ResolveSimultaneousProbe: %##s (%s): We won",  our->resrec.name.c, DNSTypeName(our->resrec.rrtype));
@@ -3931,13 +4421,16 @@ mDNSlocal void ResolveSimultaneousProbe(mDNS *const m, const DNSMessage *const q
 					case  0:	break;
 					case -1:	debugf("ResolveSimultaneousProbe: %##s (%s): We lost", our->resrec.name.c, DNSTypeName(our->resrec.rrtype));
 								mDNS_Deregister_internal(m, our, mDNS_Dereg_conflict);
-								return;
+								goto exit;
 					}
 				}
 			}
+		m->rec.r.resrec.RecordType = 0;		// Clear RecordType to show we're not still using it
 		}
 	if (!FoundUpdate)
 		debugf("ResolveSimultaneousProbe: %##s (%s): No Update Record found", our->resrec.name.c, DNSTypeName(our->resrec.rrtype));
+exit:
+	m->rec.r.resrec.RecordType = 0;		// Clear RecordType to show we're not still using it
 	}
 
 mDNSlocal CacheRecord *FindIdenticalRecordInCache(const mDNS *const m, ResourceRecord *pktrr)
@@ -3950,25 +4443,22 @@ mDNSlocal CacheRecord *FindIdenticalRecordInCache(const mDNS *const m, ResourceR
 
 // ProcessQuery examines a received query to see if we have any answers to give
 mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, const mDNSu8 *const end,
-	const mDNSAddr *srcaddr, const mDNSInterfaceID InterfaceID, mDNSBool LegacyQuery, mDNSBool QueryWasMulticast,
+	const mDNSAddr *srcaddr, const mDNSInterfaceID InterfaceID, mDNSBool LegacyQuery, mDNSBool QueryWasMulticast, mDNSBool QueryWasLocalUnicast,
 	DNSMessage *const response)
 	{
-	AuthRecord  *ResponseRecords = mDNSNULL;
-	AuthRecord **nrp             = &ResponseRecords;
-	CacheRecord  *ExpectedAnswers = mDNSNULL;			// Records in our cache we expect to see updated
-	CacheRecord **eap             = &ExpectedAnswers;
-	DNSQuestion     *DupQuestions    = mDNSNULL;			// Our questions that are identical to questions in this packet
-	DNSQuestion    **dqp             = &DupQuestions;
-	mDNSs32          delayresponse   = 0;
-	mDNSBool         HaveUnicastAnswer = mDNSfalse;
-	const mDNSu8    *ptr             = query->data;
-	mDNSu8          *responseptr     = mDNSNULL;
-	AuthRecord  *rr, *rr2;
+	AuthRecord   *ResponseRecords    = mDNSNULL;
+	AuthRecord  **nrp                = &ResponseRecords;
+	CacheRecord  *ExpectedAnswers    = mDNSNULL;			// Records in our cache we expect to see updated
+	CacheRecord **eap                = &ExpectedAnswers;
+	DNSQuestion  *DupQuestions       = mDNSNULL;			// Our questions that are identical to questions in this packet
+	DNSQuestion **dqp                = &DupQuestions;
+	mDNSs32       delayresponse      = 0;
+	mDNSBool      SendLegacyResponse = mDNSfalse;
+	const mDNSu8 *ptr                = query->data;
+	mDNSu8       *responseptr        = mDNSNULL;
+	AuthRecord   *rr;
 	int i;
 
-	// If TC flag is set, it means we should expect that additional known answers may be coming in another packet.
-	if (query->h.flags.b[0] & kDNSFlag0_TC) delayresponse = mDNSPlatformOneSecond;	// Divided by 50 = 20ms
-
 	// ***
 	// *** 1. Parse Question Section and mark potential answers
 	// ***
@@ -4004,7 +4494,7 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con
 			{
 			rr = m->CurrentRecord;
 			m->CurrentRecord = rr->next;
-			if (ResourceRecordAnswersQuestion(&rr->resrec, &pktq))
+			if (ResourceRecordAnswersQuestion(&rr->resrec, &pktq) && (QueryWasMulticast || QueryWasLocalUnicast || rr->AllowRemoteQuery))
 				{
 				if (rr->resrec.RecordType == kDNSRecordTypeUnique)
 					ResolveSimultaneousProbe(m, query, end, &pktq, rr);
@@ -4012,9 +4502,9 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con
 					{
 					NumAnswersForThisQuestion++;
 					// Notes:
-					// NR_AnswerTo pointing into query packet means "answer via unicast"
-					//                         (may also choose to do multicast as well)
-					// NR_AnswerTo == ~0 means "definitely answer via multicast" (can't downgrade to unicast later)
+					// NR_AnswerTo pointing into query packet means "answer via immediate legacy unicast" (may also choose to multicast as well)
+					// NR_AnswerTo == (mDNSu8*)~1             means "answer via delayed unicast" (to modern querier)
+					// NR_AnswerTo == (mDNSu8*)~0             means "definitely answer via multicast" (can't downgrade to unicast later)
 					if (QuestionNeedsMulticastResponse)
 						{
 						// We only mark this question for sending if it is at least one second since the last time we multicast it
@@ -4024,20 +4514,21 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con
 							(rr->LastMCInterface != mDNSInterfaceMark && rr->LastMCInterface != InterfaceID))
 							rr->NR_AnswerTo = (mDNSu8*)~0;
 						}
-					else if (!rr->NR_AnswerTo) rr->NR_AnswerTo = ptr;
+					else if (!rr->NR_AnswerTo) rr->NR_AnswerTo = LegacyQuery ? ptr : (mDNSu8*)~1;
 					}
 				}
 			}
 
+		// If we couldn't answer this question, someone else might be able to,
+		// so use random delay on response to reduce collisions
+		if (NumAnswersForThisQuestion == 0) delayresponse = mDNSPlatformOneSecond;	// Divided by 50 = 20ms
+
 		// We only do the following accelerated cache expiration processing and duplicate question suppression processing
 		// for multicast queries with multicast responses.
 		// For any query generating a unicast response we don't do this because we can't assume we will see the response
 		if (QuestionNeedsMulticastResponse)
 			{
 			CacheRecord *rr;
-			// If we couldn't answer this question, someone else might be able to,
-			// so use random delay on response to reduce collisions
-			if (NumAnswersForThisQuestion == 0) delayresponse = mDNSPlatformOneSecond;	// Divided by 50 = 20ms
 
 			// Make a list indicating which of our own cache records we expect to see updated as a result of this query
 			// Note: Records larger than 1K are not habitually multicast, so don't expect those to be updated
@@ -4082,25 +4573,7 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con
 	// ***
 	// *** 3. Add additional records
 	// ***
-	for (rr=ResponseRecords; rr; rr=rr->NextResponse)			// For each record we plan to put
-		{
-		// (Note: This is an "if", not a "while". If we add a record, we'll find it again
-		// later in the "for" loop, and we will follow further "additional" links then.)
-		if (rr->Additional1 && ResourceRecordIsValidInterfaceAnswer(rr->Additional1, InterfaceID))
-			AddRecordToResponseList(&nrp, rr->Additional1, rr);
-
-		if (rr->Additional2 && ResourceRecordIsValidInterfaceAnswer(rr->Additional2, InterfaceID))
-			AddRecordToResponseList(&nrp, rr->Additional2, rr);
-		
-		// For SRV records, automatically add the Address record(s) for the target host
-		if (rr->resrec.rrtype == kDNSType_SRV)
-			for (rr2=m->ResourceRecords; rr2; rr2=rr2->next)					// Scan list of resource records
-				if (RRTypeIsAddressType(rr2->resrec.rrtype) &&					// For all address records (A/AAAA) ...
-					ResourceRecordIsValidInterfaceAnswer(rr2, InterfaceID) &&	// ... which are valid for answer ...
-					rr->resrec.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);
-		}
+	AddAdditionalsToResponseList(m, ResponseRecords, &nrp, InterfaceID);
 
 	// ***
 	// *** 4. Parse Answer Section and cancel any records disallowed by Known-Answer list
@@ -4108,26 +4581,25 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con
 	for (i=0; i<query->h.numAnswers; i++)						// For each record in the query's answer section...
 		{
 		// Get the record...
-		LargeCacheRecord pkt;
 		AuthRecord *rr;
 		CacheRecord *ourcacherr;
-		ptr = GetLargeResourceRecord(m, query, ptr, end, InterfaceID, kDNSRecordTypePacketAns, &pkt);
+		ptr = GetLargeResourceRecord(m, query, ptr, end, InterfaceID, kDNSRecordTypePacketAns, &m->rec);
 		if (!ptr) goto exit;
 
 		// See if this Known-Answer suppresses any of our currently planned answers
 		for (rr=ResponseRecords; rr; rr=rr->NextResponse)
-			if (MustSendRecord(rr) && ShouldSuppressKnownAnswer(&pkt.r, rr))
+			if (MustSendRecord(rr) && ShouldSuppressKnownAnswer(&m->rec.r, rr))
 				{ rr->NR_AnswerTo = mDNSNULL; rr->NR_AdditionalTo = mDNSNULL; }
 
 		// See if this Known-Answer suppresses any previously scheduled answers (for multi-packet KA suppression)
 		for (rr=m->ResourceRecords; rr; rr=rr->next)
 			{
 			// If we're planning to send this answer on this interface, and only on this interface, then allow KA suppression
-			if (rr->ImmedAnswer == InterfaceID && ShouldSuppressKnownAnswer(&pkt.r, rr))
+			if (rr->ImmedAnswer == InterfaceID && ShouldSuppressKnownAnswer(&m->rec.r, rr))
 				{
 				if (srcaddr->type == mDNSAddrType_IPv4)
 					{
-					if (mDNSSameIPv4Address(rr->v4Requester, srcaddr->ip.v4)) rr->v4Requester = zeroIPAddr;
+					if (mDNSSameIPv4Address(rr->v4Requester, srcaddr->ip.v4)) rr->v4Requester = zerov4Addr;
 					}
 				else if (srcaddr->type == mDNSAddrType_IPv6)
 					{
@@ -4135,9 +4607,10 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con
 					}
 				if (mDNSIPv4AddressIsZero(rr->v4Requester) && mDNSIPv6AddressIsZero(rr->v6Requester))
 					{
-					rr->ImmedAnswer = mDNSNULL;
+					rr->ImmedAnswer  = mDNSNULL;
+					rr->ImmedUnicast = mDNSfalse;
 #if MDNS_LOG_ANSWER_SUPPRESSION_TIMES
-					LogMsg("Suppressed after%4d: %s", m->timenow - rr->ImmedAnswerMarkTime, GetRRDisplayString(m, rr));
+					LogMsg("Suppressed after%4d: %s", m->timenow - rr->ImmedAnswerMarkTime, ARDisplayString(m, rr));
 #endif
 					}
 				}
@@ -4145,7 +4618,7 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con
 
 		// See if this Known-Answer suppresses any answers we were expecting for our cache records. We do this always,
 		// even if the TC bit is not set (the TC bit will *not* be set in the *last* packet of a multi-packet KA list).
-		ourcacherr = FindIdenticalRecordInCache(m, &pkt.r.resrec);
+		ourcacherr = FindIdenticalRecordInCache(m, &m->rec.r.resrec);
 		if (ourcacherr && ourcacherr->MPExpectingKA && m->timenow - ourcacherr->MPLastUnansweredQT < mDNSPlatformOneSecond)
 			{
 			ourcacherr->MPUnansweredKA++;
@@ -4159,7 +4632,7 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con
 		while (*eap)
 			{
 			CacheRecord *rr = *eap;
-			if (rr->resrec.InterfaceID == InterfaceID && IdenticalResourceRecord(&pkt.r.resrec, &rr->resrec))
+			if (rr->resrec.InterfaceID == InterfaceID && IdenticalResourceRecord(&m->rec.r.resrec, &rr->resrec))
 				{ *eap = rr->NextInKAList; rr->NextInKAList = mDNSNULL; }
 			else eap = &rr->NextInKAList;
 			}
@@ -4171,11 +4644,12 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con
 			while (*dqp)
 				{
 				DNSQuestion *q = *dqp;
-				if (ResourceRecordAnswersQuestion(&pkt.r.resrec, q))
+				if (ResourceRecordAnswersQuestion(&m->rec.r.resrec, q))
 					{ *dqp = q->NextInDQList; q->NextInDQList = mDNSNULL; }
 				else dqp = &q->NextInDQList;
 				}
 			}
+		m->rec.r.resrec.RecordType = 0;		// Clear RecordType to show we're not still using it
 		}
 
 	// ***
@@ -4192,16 +4666,18 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con
 		{
 		if (rr->NR_AnswerTo)
 			{
-			mDNSBool SendMulticastResponse = mDNSfalse;
+			mDNSBool SendMulticastResponse = mDNSfalse;		// Send modern multicast response
+			mDNSBool SendUnicastResponse   = mDNSfalse;		// Send modern unicast response (not legacy unicast response)
 			
 			// If it's been a while since we multicast this, then send a multicast response for conflict detection, etc.
 			if (m->timenow - (rr->LastMCTime + TicksTTL(rr)/4) >= 0) SendMulticastResponse = mDNStrue;
 			
 			// If the client insists on a multicast response, then we'd better send one
-			if (rr->NR_AnswerTo == (mDNSu8*)~0) SendMulticastResponse = mDNStrue;
-			else if (rr->NR_AnswerTo) HaveUnicastAnswer = mDNStrue;
+			if      (rr->NR_AnswerTo == (mDNSu8*)~0) SendMulticastResponse = mDNStrue;
+			else if (rr->NR_AnswerTo == (mDNSu8*)~1) SendUnicastResponse   = mDNStrue;
+			else if (rr->NR_AnswerTo)                SendLegacyResponse    = mDNStrue;
 	
-			if (SendMulticastResponse)
+			if (SendMulticastResponse || SendUnicastResponse)
 				{
 #if MDNS_LOG_ANSWER_SUPPRESSION_TIMES
 				rr->ImmedAnswerMarkTime = m->timenow;
@@ -4209,13 +4685,11 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con
 				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;
-					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
+					if (SendUnicastResponse) rr->ImmedUnicast = mDNStrue;
 					if (srcaddr->type == mDNSAddrType_IPv4)
 						{
 						if      (mDNSIPv4AddressIsZero(rr->v4Requester))                rr->v4Requester = srcaddr->ip.v4;
@@ -4228,11 +4702,12 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con
 						}
 					}
 				}
-			if (rr->resrec.RecordType == kDNSRecordTypeShared)
-				{
-				if (query->h.flags.b[0] & kDNSFlag0_TC) delayresponse = mDNSPlatformOneSecond * 20;	// Divided by 50 = 400ms
-				else                                    delayresponse = mDNSPlatformOneSecond;		// Divided by 50 = 20ms
-				}
+			// If TC flag is set, it means we should expect that additional known answers may be coming in another packet,
+			// so we allow roughly half a second before deciding to reply (we've observed inter-packet delays of 100-200ms on 802.11)
+			// else, if record is a shared one, spread responses over 100ms to avoid implosion of simultaneous responses
+			// else, for a simple unique record reply, we can reply immediately; no need for delay
+			if      (query->h.flags.b[0] & kDNSFlag0_TC)            delayresponse = mDNSPlatformOneSecond * 20;	// Divided by 50 = 400ms
+			else if (rr->resrec.RecordType == kDNSRecordTypeShared) delayresponse = mDNSPlatformOneSecond;		// Divided by 50 = 20ms
 			}
 		else if (rr->NR_AdditionalTo && rr->NR_AdditionalTo->NR_AnswerTo == (mDNSu8*)~0)
 			{
@@ -4279,10 +4754,12 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con
 	// ***
 	// *** 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)
+	if (SendLegacyResponse)
 		responseptr = GenerateUnicastResponse(query, end, InterfaceID, LegacyQuery, response, ResponseRecords);
 
 exit:
+	m->rec.r.resrec.RecordType = 0;		// Clear RecordType to show we're not still using it
+	
 	// ***
 	// *** 9. Finally, clear our link chains ready for use next time
 	// ***
@@ -4311,7 +4788,7 @@ exit:
 				rr->LastUnansweredTime = m->timenow;
 				if (rr->UnansweredQueries > 1)
 					debugf("ProcessQuery: (!TC) UAQ %lu MPQ %lu MPKA %lu %s",
-						rr->UnansweredQueries, rr->MPUnansweredQ, rr->MPUnansweredKA, GetRRDisplayString(m, rr));
+						rr->UnansweredQueries, rr->MPUnansweredQ, rr->MPUnansweredKA, CRDisplayString(m, rr));
 				SetNextCacheCheckTime(m, rr);
 				}
 
@@ -4322,7 +4799,7 @@ exit:
 			// Only show debugging message if this record was not about to expire anyway
 			if (RRExpireTime(rr) - m->timenow > 4 * mDNSPlatformOneSecond)
 				debugf("ProcessQuery: (Max) UAQ %lu MPQ %lu MPKA %lu mDNS_Reconfirm() for %s",
-					rr->UnansweredQueries, rr->MPUnansweredQ, rr->MPUnansweredKA, GetRRDisplayString(m, rr));
+					rr->UnansweredQueries, rr->MPUnansweredQ, rr->MPUnansweredKA, CRDisplayString(m, rr));
 			mDNS_Reconfirm_internal(m, rr, kDefaultReconfirmTimeForNoAnswer);
 			}
 		// Make a guess, based on the multi-packet query / known answer counts, whether we think we
@@ -4343,7 +4820,7 @@ exit:
 			// Only show debugging message if this record was not about to expire anyway
 			if (RRExpireTime(rr) - m->timenow > 4 * mDNSPlatformOneSecond)
 				debugf("ProcessQuery: (MPQ) UAQ %lu MPQ %lu MPKA %lu mDNS_Reconfirm() for %s",
-					rr->UnansweredQueries, rr->MPUnansweredQ, rr->MPUnansweredKA, GetRRDisplayString(m, rr));
+					rr->UnansweredQueries, rr->MPUnansweredQ, rr->MPUnansweredKA, CRDisplayString(m, rr));
 
 			if (remain <= 60 * (mDNSu32)mDNSPlatformOneSecond)
 				rr->UnansweredQueries++;	// Treat this as equivalent to one definite unanswered query
@@ -4371,16 +4848,44 @@ 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)
 	{
-	DNSMessage    response;
-	mDNSu8 *responseend    = mDNSNULL;
+	mDNSu8    *responseend = mDNSNULL;
+	mDNSBool   QueryWasLocalUnicast = !mDNSAddrIsDNSMulticast(dstaddr) && AddressIsLocalSubnet(m, InterfaceID, srcaddr);
 	
-	if (!InterfaceID)
+	if (!InterfaceID && mDNSAddrIsDNSMulticast(dstaddr))
 		{
-		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",
+		LogMsg("Ignoring Query from %#-15a:%-5d to %#-15a:%-5d on 0x%p with %2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s (Multicast, but no InterfaceID)",
 			srcaddr, mDNSVal16(srcport), dstaddr, mDNSVal16(dstport), InterfaceID,
 			msg->h.numQuestions,   msg->h.numQuestions   == 1 ? ", " : "s,",
 			msg->h.numAnswers,     msg->h.numAnswers     == 1 ? ", " : "s,",
@@ -4389,7 +4894,7 @@ mDNSlocal void mDNSCoreReceiveQuery(mDNS *const m, const DNSMessage *const msg,
 		return;
 		}
 	
-	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",
+	verbosedebugf("Received Query from %#-15a:%-5d to %#-15a:%-5d on 0x%p with %2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s",
 		srcaddr, mDNSVal16(srcport), dstaddr, mDNSVal16(dstport), InterfaceID,
 		msg->h.numQuestions,   msg->h.numQuestions   == 1 ? ", " : "s,",
 		msg->h.numAnswers,     msg->h.numAnswers     == 1 ? ", " : "s,",
@@ -4397,16 +4902,16 @@ mDNSlocal void mDNSCoreReceiveQuery(mDNS *const m, const DNSMessage *const msg,
 		msg->h.numAdditionals, msg->h.numAdditionals == 1 ? "" : "s");
 	
 	responseend = ProcessQuery(m, msg, end, srcaddr, InterfaceID,
-		(srcport.NotAnInteger != MulticastDNSPort.NotAnInteger), mDNSAddrIsDNSMulticast(dstaddr), &response);
+		(srcport.NotAnInteger != MulticastDNSPort.NotAnInteger), mDNSAddrIsDNSMulticast(dstaddr), QueryWasLocalUnicast, &m->omsg);
 
 	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",
+			m->omsg.h.numQuestions,   m->omsg.h.numQuestions   == 1 ? "" : "s",
+			m->omsg.h.numAnswers,     m->omsg.h.numAnswers     == 1 ? "" : "s",
+			m->omsg.h.numAdditionals, m->omsg.h.numAdditionals == 1 ? "" : "s",
 			srcaddr, mDNSVal16(srcport), InterfaceID, srcaddr->type);
-		mDNSSendDNSMessage(m, &response, responseend, InterfaceID, srcaddr, srcport);
+		mDNSSendDNSMessage(m, &m->omsg, responseend, InterfaceID, srcaddr, srcport, -1, mDNSNULL);
 		}
 	}
 
@@ -4416,53 +4921,39 @@ mDNSlocal void mDNSCoreReceiveQuery(mDNS *const m, const DNSMessage *const msg,
 mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
 	const DNSMessage *const response, const mDNSu8 *end,
 	const mDNSAddr *srcaddr, const mDNSIPPort srcport, const mDNSAddr *dstaddr, mDNSIPPort dstport,
-	const mDNSInterfaceID InterfaceID, mDNSu8 ttl)
+	const mDNSInterfaceID InterfaceID)
 	{
-	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;
 	CacheRecord **cfp = &CacheFlushRecords;
-		
+
 	// All records in a DNS response packet are treated as equally valid statements of truth. If we want
 	// to guard against spoof responses, then the only credible protection against that is cryptographic
 	// security, e.g. DNSSEC., not worring about which section in the spoof packet contained the record
 	int totalrecords = response->h.numAnswers + response->h.numAuthorities + response->h.numAdditionals;
 
 	(void)srcaddr;	// Currently used only for display in debugging message
+	(void)srcport;
+	(void)dstport;
 
-	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,
+	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,
 		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");
 
-	// 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++;
+	// 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))
+			return;
 
 	for (i = 0; i < totalrecords && ptr && ptr < end; i++)
 		{
-		LargeCacheRecord pkt;
 		const mDNSu8 RecordType = (mDNSu8)((i < response->h.numAnswers) ? kDNSRecordTypePacketAns : kDNSRecordTypePacketAdd);
-		ptr = GetLargeResourceRecord(m, response, ptr, end, InterfaceID, RecordType, &pkt);
-		if (!ptr) break;		// Break out of the loop and clean up our CacheFlushRecords list before exiting
+		ptr = GetLargeResourceRecord(m, response, ptr, end, InterfaceID, RecordType, &m->rec);
+		if (!ptr) goto exit;		// Break out of the loop and clean up our CacheFlushRecords list before exiting
 
 		// 1. Check that this packet resource record does not conflict with any of ours
 		if (m->CurrentRecord) LogMsg("mDNSCoreReceiveResponse ERROR m->CurrentRecord already set");
@@ -4471,16 +4962,16 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
 			{
 			AuthRecord *rr = m->CurrentRecord;
 			m->CurrentRecord = rr->next;
-			if (PacketRRMatchesSignature(&pkt.r, rr))		// If interface, name, type (if verified) and class match...
+			if (PacketRRMatchesSignature(&m->rec.r, rr))		// If interface, name, type (if shared record) and class match...
 				{
-				// ... check to see if rdata is identical
-				if (SameRData(&pkt.r.resrec, &rr->resrec))
+				// ... check to see if type and rdata are identical
+				if (m->rec.r.resrec.rrtype == rr->resrec.rrtype && SameRData(&m->rec.r.resrec, &rr->resrec))
 					{
 					// If the RR in the packet is identical to ours, just check they're not trying to lower the TTL on us
-					if (pkt.r.resrec.rroriginalttl >= rr->resrec.rroriginalttl/2 || m->SleepState)
+					if (m->rec.r.resrec.rroriginalttl >= rr->resrec.rroriginalttl/2 || m->SleepState)
 						{
 						// If we were planning to send on this -- and only this -- interface, then we don't need to any more
-						if (rr->ImmedAnswer == InterfaceID) rr->ImmedAnswer = mDNSNULL;
+						if      (rr->ImmedAnswer == InterfaceID) { rr->ImmedAnswer = mDNSNULL; rr->ImmedUnicast = mDNSfalse; }
 						}
 					else
 						{
@@ -4488,78 +4979,77 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
 						else if (rr->ImmedAnswer != InterfaceID) { rr->ImmedAnswer = mDNSInterfaceMark; m->NextScheduledResponse = m->timenow; }
 						}
 					}
-				else
+				// else, the packet RR has different type or different rdata -- check to see if this is a conflict
+				else if (m->rec.r.resrec.rroriginalttl > 0 && PacketRRConflict(m, rr, &m->rec.r))
 					{
-					// else, the packet RR has different rdata -- check to see if this is a conflict
-					if (pkt.r.resrec.rroriginalttl > 0 && PacketRRConflict(m, rr, &pkt.r))
-						{
-						debugf("mDNSCoreReceiveResponse: Our Record: %08X %08X %s", rr->  resrec.rdatahash, rr->  resrec.rdnamehash, GetRRDisplayString(m, rr));
-						debugf("mDNSCoreReceiveResponse: Pkt Record: %08X %08X %s", pkt.r.resrec.rdatahash, pkt.r.resrec.rdnamehash, GetRRDisplayString(m, &pkt.r));
+					debugf("mDNSCoreReceiveResponse: Our Record: %08lX %08lX %s", rr->     resrec.rdatahash, rr->     resrec.rdnamehash, ARDisplayString(m, rr));
+					debugf("mDNSCoreReceiveResponse: Pkt Record: %08lX %08lX %s", m->rec.r.resrec.rdatahash, m->rec.r.resrec.rdnamehash, CRDisplayString(m, &m->rec.r));
 
-						// If this record is marked DependentOn another record for conflict detection purposes,
-						// then *that* record has to be bumped back to probing state to resolve the conflict
-						while (rr->DependentOn) rr = rr->DependentOn;
+					// If this record is marked DependentOn another record for conflict detection purposes,
+					// then *that* record has to be bumped back to probing state to resolve the conflict
+					while (rr->DependentOn) rr = rr->DependentOn;
 
-						// If we've just whacked this record's ProbeCount, don't need to do it again
-						if (rr->ProbeCount <= DefaultProbeCountForTypeUnique)
+					// If we've just whacked this record's ProbeCount, don't need to do it again
+					if (rr->ProbeCount <= DefaultProbeCountForTypeUnique)
+						{
+						// If we'd previously verified this record, put it back to probing state and try again
+						if (rr->resrec.RecordType == kDNSRecordTypeVerified)
 							{
-							// If we'd previously verified this record, put it back to probing state and try again
-							if (rr->resrec.RecordType == kDNSRecordTypeVerified)
-								{
-								debugf("mDNSCoreReceiveResponse: Reseting to Probing: %##s (%s)", rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype));
-								rr->resrec.RecordType     = kDNSRecordTypeUnique;
-								rr->ProbeCount     = DefaultProbeCountForTypeUnique + 1;
-								rr->ThisAPInterval = DefaultAPIntervalForRecordType(kDNSRecordTypeUnique);
-								InitializeLastAPTime(m, rr);
-								RecordProbeFailure(m, rr);	// Repeated late conflicts also cause us to back off to the slower probing rate
-								}
-							// If we're probing for this record, we just failed
-							else if (rr->resrec.RecordType == kDNSRecordTypeUnique)
-								{
-								debugf("mDNSCoreReceiveResponse: Will rename %##s (%s)", rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype));
-								mDNS_Deregister_internal(m, rr, mDNS_Dereg_conflict);
-								}
-							// We assumed this record must be unique, but we were wrong.
-							// (e.g. There are two mDNSResponders on the same machine giving
-							// different answers for the reverse mapping record.)
-							// This is simply a misconfiguration, and we don't try to recover from it.
-							else if (rr->resrec.RecordType == kDNSRecordTypeKnownUnique)
-								{
-								debugf("mDNSCoreReceiveResponse: Unexpected conflict on %##s (%s) -- discarding our record",
-									rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype));
-								mDNS_Deregister_internal(m, rr, mDNS_Dereg_conflict);
-								}
-							else
-								debugf("mDNSCoreReceiveResponse: Unexpected record type %X %##s (%s)",
-									rr->resrec.RecordType, rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype));
+							debugf("mDNSCoreReceiveResponse: Reseting to Probing: %##s (%s)", rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype));
+							rr->resrec.RecordType     = kDNSRecordTypeUnique;
+							rr->ProbeCount     = DefaultProbeCountForTypeUnique + 1;
+							rr->ThisAPInterval = DefaultAPIntervalForRecordType(kDNSRecordTypeUnique);
+							InitializeLastAPTime(m, rr);
+							RecordProbeFailure(m, rr);	// Repeated late conflicts also cause us to back off to the slower probing rate
+							}
+						// If we're probing for this record, we just failed
+						else if (rr->resrec.RecordType == kDNSRecordTypeUnique)
+							{
+							debugf("mDNSCoreReceiveResponse: Will rename %##s (%s)", rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype));
+							mDNS_Deregister_internal(m, rr, mDNS_Dereg_conflict);
+							}
+						// We assumed this record must be unique, but we were wrong.
+						// (e.g. There are two mDNSResponders on the same machine giving
+						// different answers for the reverse mapping record.)
+						// This is simply a misconfiguration, and we don't try to recover from it.
+						else if (rr->resrec.RecordType == kDNSRecordTypeKnownUnique)
+							{
+							debugf("mDNSCoreReceiveResponse: Unexpected conflict on %##s (%s) -- discarding our record",
+								rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype));
+							mDNS_Deregister_internal(m, rr, mDNS_Dereg_conflict);
 							}
+						else
+							debugf("mDNSCoreReceiveResponse: Unexpected record type %X %##s (%s)",
+								rr->resrec.RecordType, rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype));
 						}
-					// Else, matching signature, different rdata, but not a considered a conflict.
-					// If the packet record has the cache-flush bit set, then we check to see if we have to re-assert our record(s)
-					// to rescue them (see note about "multi-homing and bridged networks" at the end of this function).
-					else if ((pkt.r.resrec.RecordType & kDNSRecordTypePacketUniqueMask) && m->timenow - rr->LastMCTime > mDNSPlatformOneSecond/2)
-						{ rr->ImmedAnswer = mDNSInterfaceMark; m->NextScheduledResponse = m->timenow; }
 					}
+				// Else, matching signature, different type or rdata, but not a considered a conflict.
+				// If the packet record has the cache-flush bit set, then we check to see if we
+				// have any record(s) of the same type that we should re-assert to rescue them
+				// (see note about "multi-homing and bridged networks" at the end of this function).
+				else if (m->rec.r.resrec.rrtype == rr->resrec.rrtype)
+					if ((m->rec.r.resrec.RecordType & kDNSRecordTypePacketUniqueMask) && m->timenow - rr->LastMCTime > mDNSPlatformOneSecond/2)
+						{ rr->ImmedAnswer = mDNSInterfaceMark; m->NextScheduledResponse = m->timenow; }
 				}
 			}
 
 		// 2. See if we want to add this packet resource record to our cache
 		if (m->rrcache_size)	// Only try to cache answers if we have a cache to put them in
 			{
-			mDNSu32 slot = HashSlot(&pkt.r.resrec.name);
+			const mDNSu32 slot = HashSlot(&m->rec.r.resrec.name);
 			CacheRecord *rr;
 			// 2a. Check if this packet resource record is already in our cache
 			for (rr = m->rrcache_hash[slot]; rr; rr=rr->next)
 				{
 				// If we found this exact resource record, refresh its TTL
-				if (rr->resrec.InterfaceID == InterfaceID && IdenticalResourceRecord(&pkt.r.resrec, &rr->resrec))
+				if (rr->resrec.InterfaceID == InterfaceID && IdenticalResourceRecord(&m->rec.r.resrec, &rr->resrec))
 					{
-					if (pkt.r.resrec.rdlength > InlineCacheRDSize)
+					if (m->rec.r.resrec.rdlength > InlineCacheRDSize)
 						verbosedebugf("Found record size %5d interface %p already in cache: %s",
-							pkt.r.resrec.rdlength, InterfaceID, GetRRDisplayString(m, &pkt.r));
+							m->rec.r.resrec.rdlength, InterfaceID, CRDisplayString(m, &m->rec.r));
 					rr->TimeRcvd  = m->timenow;
 					
-					if (pkt.r.resrec.RecordType & kDNSRecordTypePacketUniqueMask)
+					if (m->rec.r.resrec.RecordType & kDNSRecordTypePacketUniqueMask)
 						{
 						// If this packet record has the kDNSClass_UniqueRRSet flag set, then add it to our cache flushing list
 						if (rr->NextInCFList == mDNSNULL && cfp != &rr->NextInCFList)
@@ -4570,13 +5060,13 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
 							{
 							DNSQuestion *q;
 							for (q = m->Questions; q; q=q->next) if (ResourceRecordAnswersQuestion(&rr->resrec, q)) q->UniqueAnswers++;
-							rr->resrec.RecordType = pkt.r.resrec.RecordType;
+							rr->resrec.RecordType = m->rec.r.resrec.RecordType;
 							}
 						}
 
-					if (pkt.r.resrec.rroriginalttl > 0)
+					if (m->rec.r.resrec.rroriginalttl > 0)
 						{
-						rr->resrec.rroriginalttl = pkt.r.resrec.rroriginalttl;
+						rr->resrec.rroriginalttl = m->rec.r.resrec.rroriginalttl;
 						rr->UnansweredQueries = 0;
 						rr->MPUnansweredQ     = 0;
 						rr->MPUnansweredKA    = 0;
@@ -4599,41 +5089,50 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
 
 			// If packet resource record not in our cache, add it now
 			// (unless it is just a deletion of a record we never had, in which case we don't care)
-			if (!rr && pkt.r.resrec.rroriginalttl > 0)
+			if (!rr && m->rec.r.resrec.rroriginalttl > 0)
 				{
-				rr = GetFreeCacheRR(m, pkt.r.resrec.rdlength);
-				if (!rr) debugf("No cache space to add record for %#s", pkt.r.resrec.name.c);
+				rr = GetFreeCacheRR(m, m->rec.r.resrec.rdlength);
+				if (!rr) debugf("No cache space to add record for %#s", m->rec.r.resrec.name.c);
 				else
 					{
 					RData *saveptr = rr->resrec.rdata;		// Save the rr->resrec.rdata pointer
-					*rr = pkt.r;
-					rr->resrec.rdata = saveptr;			// and then restore it after the structure assignment
+					*rr = m->rec.r;
+					rr->resrec.rdata = saveptr;				// and then restore it after the structure assignment
 					if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask)
 						{ *cfp = rr; cfp = &rr->NextInCFList; }
 					// If this is an oversized record with external storage allocated, copy rdata to external storage
-					if (pkt.r.resrec.rdlength > InlineCacheRDSize)
-						mDNSPlatformMemCopy(pkt.r.resrec.rdata, rr->resrec.rdata, sizeofRDataHeader + pkt.r.resrec.rdlength);
+					if (m->rec.r.resrec.rdlength > InlineCacheRDSize)
+						mDNSPlatformMemCopy(m->rec.r.resrec.rdata, rr->resrec.rdata, sizeofRDataHeader + m->rec.r.resrec.rdlength);
 					rr->next = mDNSNULL;					// Clear 'next' pointer
 					*(m->rrcache_tail[slot]) = rr;			// Append this record to tail of cache slot list
 					m->rrcache_tail[slot] = &(rr->next);	// Advance tail pointer
 					m->rrcache_used[slot]++;
-					//debugf("Adding RR %##s to cache (%d)", pkt.r.name.c, m->rrcache_used);
+					if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask)	// If marked unique, assume we may have
+						rr->DelayDelivery = m->timenow + mDNSPlatformOneSecond;	// to delay delivery of this 'add' event
+					else
+						rr->DelayDelivery = CheckForSoonToExpireRecords(m, &rr->resrec.name, rr->resrec.namehash, slot);
+					//debugf("Adding RR %##s to cache (%d)", m->rec.r.name.c, m->rrcache_used);
 					CacheRecordAdd(m, rr);
 					// MUST do this AFTER CacheRecordAdd(), because that's what sets CRActiveQuestion for us
 					SetNextCacheCheckTime(m, rr);
 					}
 				}
 			}
+		m->rec.r.resrec.RecordType = 0;		// Clear RecordType to show we're not still using it
 		}
 
+exit:
+	m->rec.r.resrec.RecordType = 0;		// Clear RecordType to show we're not still using it
+
 	// If we've just received one or more records with their cache flush bits set,
 	// then scan that cache slot to see if there are any old stale records we need to flush
 	while (CacheFlushRecords)
 		{
 		CacheRecord *r1 = CacheFlushRecords, *r2;
+		const mDNSu32 slot = HashSlot(&r1->resrec.name);
 		CacheFlushRecords = CacheFlushRecords->NextInCFList;
 		r1->NextInCFList = mDNSNULL;
-		for (r2 = m->rrcache_hash[HashSlot(&r1->resrec.name)]; r2; r2=r2->next)
+		for (r2 = m->rrcache_hash[slot]; r2; r2=r2->next)
 			if (SameResourceRecordSignature(&r1->resrec, &r2->resrec) && m->timenow - r2->TimeRcvd > mDNSPlatformOneSecond)
 				{
 				verbosedebugf("Cache flush %p X %p %##s (%s)", r1, r2, r2->resrec.name.c, DNSTypeName(r2->resrec.rrtype));
@@ -4653,20 +5152,40 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
 				r2->UnansweredQueries = MaxUnansweredQueries;
 				SetNextCacheCheckTime(m, r2);
 				}
+		if (r1->DelayDelivery)	// If we were planning to delay delivery of this record, see if we still need to
+			{
+			r1->DelayDelivery = CheckForSoonToExpireRecords(m, &r1->resrec.name, r1->resrec.namehash, slot);
+			if (!r1->DelayDelivery) CacheRecordDeferredAdd(m, r1);
+			}
 		}
 	}
 
-mDNSexport void mDNSCoreReceive(mDNS *const m, DNSMessage *const msg, const mDNSu8 *const end,
+mDNSexport void mDNSCoreReceive(mDNS *const m, void *const pkt, const mDNSu8 *const end,
 	const mDNSAddr *const srcaddr, const mDNSIPPort srcport, const mDNSAddr *const dstaddr, const mDNSIPPort dstport,
-	const mDNSInterfaceID InterfaceID, mDNSu8 ttl)
+	const mDNSInterfaceID InterfaceID)
 	{
-	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);
+	DNSMessage  *msg  = (DNSMessage *)pkt;
+	const mDNSu8 StdQ = kDNSFlag0_QR_Query    | kDNSFlag0_OP_StdQuery;
+	const mDNSu8 StdR = kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery;
+	mDNSu8 QR_OP;
+	mDNSu8 *ptr = mDNSNULL;
+
+#ifndef UNICAST_DISABLED	
+	mDNSIPPort NATPort = mDNSOpaque16fromIntVal(NATMAP_PORT);
+	const mDNSu8 UpdateR = kDNSFlag0_QR_Response | kDNSFlag0_OP_Update;
 	
+	if (srcport.NotAnInteger == NATPort.NotAnInteger)
+		{
+		mDNS_Lock(m);
+		uDNS_ReceiveNATMap(m, pkt, (mDNSu16)(end - (mDNSu8 *)pkt));
+		mDNS_Unlock(m);
+		return;
+		}
+#endif		
+	if ((unsigned)(end - (mDNSu8 *)pkt) < sizeof(DNSMessageHeader)) { LogMsg("DNS Message too short"); return; }
+	QR_OP = (mDNSu8)(msg->h.flags.b[0] & kDNSFlag0_QROP_Mask);
 	// Read the integer parts which are in IETF byte-order (MSB first, LSB second)
-	mDNSu8 *ptr = (mDNSu8 *)&msg->h.numQuestions;
+	ptr = (mDNSu8 *)&msg->h.numQuestions;
 	msg->h.numQuestions   = (mDNSu16)((mDNSu16)ptr[0] <<  8 | ptr[1]);
 	msg->h.numAnswers     = (mDNSu16)((mDNSu16)ptr[2] <<  8 | ptr[3]);
 	msg->h.numAuthorities = (mDNSu16)((mDNSu16)ptr[4] <<  8 | ptr[5]);
@@ -4678,18 +5197,18 @@ mDNSexport void mDNSCoreReceive(mDNS *const m, DNSMessage *const msg, const mDNS
 	// 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);
+	m->PktNum++;
+#ifndef UNICAST_DISABLED
+	if (!mDNSAddressIsAllDNSLinkGroup(dstaddr) && (QR_OP == StdR || QR_OP == UpdateR))
+		uDNS_ReceiveMsg(m, msg, end, srcaddr, srcport, dstaddr, dstport, InterfaceID);
+		// Note: mDNSCore also needs to get access to received unicast responses
+#endif	
 	if      (QR_OP == StdQ) mDNSCoreReceiveQuery   (m, msg, end, srcaddr, srcport, dstaddr, dstport, InterfaceID);
-	else if (QR_OP == StdR) mDNSCoreReceiveResponse(m, msg, end, srcaddr, srcport, dstaddr, dstport, InterfaceID, 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);
+	else if (QR_OP == StdR) mDNSCoreReceiveResponse(m, msg, end, srcaddr, srcport, dstaddr, dstport, InterfaceID);
+	else if (QR_OP != UpdateR)
+		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
@@ -4734,11 +5253,11 @@ mDNSlocal void UpdateQuestionDuplicates(mDNS *const m, const DNSQuestion *const
 	for (q = m->Questions; q; q=q->next)		// Scan our list of questions
 		if (q->DuplicateOf == question)			// To see if any questions were referencing this as their duplicate
 			{
-			q->ThisQInterval = question->ThisQInterval;
-			q->LastQTime     = question->LastQTime;
-			q->RecentAnswers = 0;
-			q->DuplicateOf   = FindDuplicateQuestion(m, q);
-			q->LastQTxTime   = question->LastQTxTime;
+			q->ThisQInterval    = question->ThisQInterval;
+			q->LastQTime        = question->LastQTime;
+			q->RecentAnswerPkts = 0;
+			q->DuplicateOf      = FindDuplicateQuestion(m, q);
+			q->LastQTxTime      = question->LastQTxTime;
 			SetNextQueryTime(m,q);
 			}
 	}
@@ -4754,23 +5273,29 @@ mDNSlocal mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const que
 
 	if (question->Target.type && !ValidQuestionTarget(question))
 		{
-		LogMsg("Warning! Target.type = %d port = %u (Client forgot to initialize before calling mDNS_StartQuery?)",
+		LogMsg("Warning! Target.type = %ld 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,
+	if (!question->Target.type)		// No question->Target specified, so clear TargetPort and TargetQID
+		{
+		question->TargetPort = zeroIPPort;
+		question->TargetQID  = zeroID;
+		}
+
+#ifndef UNICAST_DISABLED	
+	// If the client has specified 'kDNSServiceFlagsForceMulticast'
 	// then we do a multicast query on that interface, even for unicast domains.
-    if (question->InterfaceID || IsLocalDomain(&question->qname))
+    if (question->InterfaceID == mDNSInterface_LocalOnly || question->ForceMCast || 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;
-
+#else
+    question->uDNS_info.id = zeroID;
+#endif // UNICAST_DISABLED
+	
+	//LogOperation("mDNS_StartQuery %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
+	
 	if (m->rrcache_size == 0)	// Can't do queries if we have no cache space allocated
 		return(mStatus_NoCache);
 	else
@@ -4801,41 +5326,43 @@ mDNSlocal mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const que
 				}
 			}
 
-		// Note: In the case where we already have the answer to this question in our cache, that may be all the client
-		// wanted, and they may immediately cancel their question. In this case, sending an actual query on the wire would
-		// be a waste. For that reason, we schedule our first query to go out in half a second. If AnswerNewQuestion() finds
-		// that we have *no* relevant answers currently in our cache, then it will accelerate that to go out immediately.
 		if (!ValidateDomainName(&question->qname))
 			{
 			LogMsg("Attempt to start query with invalid qname %##s %s", question->qname.c, DNSTypeName(question->qtype));
 			return(mStatus_Invalid);
 			}
 
+		// Note: In the case where we already have the answer to this question in our cache, that may be all the client
+		// wanted, and they may immediately cancel their question. In this case, sending an actual query on the wire would
+		// be a waste. For that reason, we schedule our first query to go out in half a second. If AnswerNewQuestion() finds
+		// that we have *no* relevant answers currently in our cache, then it will accelerate that to go out immediately.
 		if (!m->RandomQueryDelay) m->RandomQueryDelay = 1 + (mDNSs32)mDNSRandom((mDNSu32)InitialQuestionInterval);
 
-		question->next           = mDNSNULL;
-		question->qnamehash      = DomainNameHashValue(&question->qname);	// MUST do this before FindDuplicateQuestion()
-		question->ThisQInterval  = InitialQuestionInterval * 2;				// MUST be > zero for an active question
-		question->LastQTime      = m->timenow - m->RandomQueryDelay;		// Avoid inter-machine synchronization
-		question->RecentAnswers  = 0;
-		question->CurrentAnswers = 0;
-		question->LargeAnswers   = 0;
-		question->UniqueAnswers  = 0;
-		question->DuplicateOf    = FindDuplicateQuestion(m, question);
-		question->NextInDQList   = mDNSNULL;
+		question->next             = mDNSNULL;
+		question->qnamehash        = DomainNameHashValue(&question->qname);	// MUST do this before FindDuplicateQuestion()
+		question->DelayAnswering   = CheckForSoonToExpireRecords(m, &question->qname, question->qnamehash, HashSlot(&question->qname));
+		question->ThisQInterval    = InitialQuestionInterval * 2;			// MUST be > zero for an active question
+		question->LastQTime        = m->timenow - m->RandomQueryDelay;		// Avoid inter-machine synchronization
+		question->LastAnswerPktNum = m->PktNum;
+		question->RecentAnswerPkts = 0;
+		question->CurrentAnswers   = 0;
+		question->LargeAnswers     = 0;
+		question->UniqueAnswers    = 0;
+		question->DuplicateOf      = FindDuplicateQuestion(m, question);
+		question->NextInDQList     = mDNSNULL;
 		for (i=0; i<DupSuppressInfoSize; i++)
 			question->DupSuppress[i].InterfaceID = mDNSNULL;
 		// question->InterfaceID must be already set by caller
-		question->SendQNow       = mDNSNULL;
-		question->SendOnAll      = mDNSfalse;
-		question->LastQTxTime    = m->timenow;
+		question->SendQNow         = mDNSNULL;
+		question->SendOnAll        = mDNSfalse;
+		question->LastQTxTime      = m->timenow;
 
 		if (!question->DuplicateOf)
-			verbosedebugf("mDNS_StartQuery_internal: Question %##s %s %p (%p) started",
-				question->qname.c, DNSTypeName(question->qtype), question->InterfaceID, question);
+			verbosedebugf("mDNS_StartQuery_internal: Question %##s %s %p %d (%p) started",
+				question->qname.c, DNSTypeName(question->qtype), question->InterfaceID, question->LastQTime + question->ThisQInterval - m->timenow, question);
 		else
-			verbosedebugf("mDNS_StartQuery_internal: Question %##s %s %p (%p) duplicate of (%p)",
-				question->qname.c, DNSTypeName(question->qtype), question->InterfaceID, question, question->DuplicateOf);
+			verbosedebugf("mDNS_StartQuery_internal: Question %##s %s %p %d (%p) duplicate of (%p)",
+				question->qname.c, DNSTypeName(question->qtype), question->InterfaceID, question->LastQTime + question->ThisQInterval - m->timenow, question, question->DuplicateOf);
 
 		*q = question;
 		if (question->InterfaceID == mDNSInterface_LocalOnly)
@@ -4857,8 +5384,8 @@ mDNSlocal mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const ques
 	CacheRecord *rr;
 	DNSQuestion **q = &m->Questions;
 
-    if (IsActiveUnicastQuery(question, &m->uDNS_info)) return uDNS_StopQuery(m, question);
-
+    if (uDNS_IsActiveQuery(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;
@@ -4885,7 +5412,7 @@ mDNSlocal mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const ques
 			for (q = m->Questions; q; q=q->next)		// Scan our list of questions
 				if (ActiveQuestion(q) && ResourceRecordAnswersQuestion(&rr->resrec, q))
 					break;
-			verbosedebugf("mDNS_StopQuery_internal: Cache RR %##s (%s) setting CRActiveQuestion to %X", rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype), q);
+			verbosedebugf("mDNS_StopQuery_internal: Cache RR %##s (%s) setting CRActiveQuestion to %p", rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype), q);
 			rr->CRActiveQuestion = q;		// Question used to be active; new value may or may not be null
 			if (!q) m->rrcache_active--;	// If no longer active, decrement rrcache_active count
 			}
@@ -4954,19 +5481,21 @@ mDNSexport mStatus mDNS_ReconfirmByValue(mDNS *const m, ResourceRecord *const rr
 
 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)
+	const mDNSInterfaceID InterfaceID, mDNSBool ForceMCast, mDNSQuestionCallback *Callback, void *Context)
 	{
 	question->InterfaceID      = InterfaceID;
 	question->Target           = zeroAddr;
 	question->qtype            = kDNSType_PTR;
 	question->qclass           = kDNSClass_IN;
+	question->LongLived        = mDNSfalse;
+	question->ExpectUnique     = mDNSfalse;
+	question->ForceMCast       = ForceMCast;
 	question->QuestionCallback = Callback;
 	question->QuestionContext  = Context;
 	if (!ConstructServiceName(&question->qname, mDNSNULL, srv, domain)) return(mStatus_BadParamErr);
 
-	// 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))
+#ifndef UNICAST_DISABLED
+    if (question->InterfaceID == mDNSInterface_LocalOnly || question->ForceMCast || IsLocalDomain(&question->qname))
     	{
 		question->LongLived = mDNSfalse;
 		question->uDNS_info.id = zeroID;
@@ -4974,9 +5503,25 @@ mDNSexport mStatus mDNS_StartBrowse(mDNS *const m, DNSQuestion *const question,
 		}
 	else
 		{
+		mStatus status;
+		// Need to explicitly lock here, because mDNS_StartQuery does locking but uDNS_StartQuery does not
+		mDNS_Lock(m);
 		question->LongLived = mDNStrue;
-		return uDNS_StartQuery(m, question);
+		status = uDNS_StartQuery(m, question);
+		mDNS_Unlock(m);
+		return(status);
 		}
+#else
+	return(mDNS_StartQuery(m, question));
+#endif // UNICAST_DISABLED
+	}
+
+mDNSlocal mDNSBool MachineHasActiveIPv6(mDNS *const m)
+	{
+	NetworkInterfaceInfo *intf;
+	for (intf = m->HostInterfaces; intf; intf = intf->next)
+	if (intf->ip.type == mDNSAddrType_IPv6) return(mDNStrue);
+	return(mDNSfalse);
 	}
 
 mDNSlocal void FoundServiceInfoSRV(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
@@ -4996,15 +5541,16 @@ mDNSlocal void FoundServiceInfoSRV(mDNS *const m, DNSQuestion *question, const R
 		AssignDomainName(query->qAv4.qname, answer->rdata->u.srv.target);
 		query->qAv6.InterfaceID   = answer->InterfaceID;
 		AssignDomainName(query->qAv6.qname, answer->rdata->u.srv.target);
-		mDNS_StartQuery_internal(m, &query->qAv4);
-		mDNS_StartQuery_internal(m, &query->qAv6);
+		mDNS_StartQuery(m, &query->qAv4);
+		// Only do the AAAA query if this machine actually has IPv6 active
+		if (MachineHasActiveIPv6(m)) mDNS_StartQuery(m, &query->qAv6);
 		}
 	// If this is not our first answer, only re-issue the address query if the target host name has changed
 	else if ((query->qAv4.InterfaceID != query->qSRV.InterfaceID && query->qAv4.InterfaceID != answer->InterfaceID) ||
 		!SameDomainName(&query->qAv4.qname, &answer->rdata->u.srv.target))
 		{
-		mDNS_StopQuery_internal(m, &query->qAv4);
-		mDNS_StopQuery_internal(m, &query->qAv6);
+		mDNS_StopQuery(m, &query->qAv4);
+		if (query->qAv6.ThisQInterval >= 0) mDNS_StopQuery(m, &query->qAv6);
 		if (SameDomainName(&query->qAv4.qname, &answer->rdata->u.srv.target) && !PortChanged)
 			{
 			// If we get here, it means:
@@ -5023,8 +5569,9 @@ mDNSlocal void FoundServiceInfoSRV(mDNS *const m, DNSQuestion *question, const R
 			AssignDomainName(query->qAv6.qname, answer->rdata->u.srv.target);
 			}
 		debugf("FoundServiceInfoSRV: Restarting address queries for %##s", query->qAv4.qname.c);
-		mDNS_StartQuery_internal(m, &query->qAv4);
-		mDNS_StartQuery_internal(m, &query->qAv6);
+		mDNS_StartQuery(m, &query->qAv4);
+		// Only do the AAAA query if this machine actually has IPv6 active
+		if (MachineHasActiveIPv6(m)) mDNS_StartQuery(m, &query->qAv6);
 		}
 	else if (query->ServiceInfoQueryCallback && query->GotADD && query->GotTXT && PortChanged)
 		{
@@ -5066,12 +5613,13 @@ mDNSlocal void FoundServiceInfoTXT(mDNS *const m, DNSQuestion *question, const R
 mDNSlocal void FoundServiceInfo(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
 	{
 	ServiceInfoQuery *query = (ServiceInfoQuery *)question->QuestionContext;
+	//LogOperation("FoundServiceInfo %d %s", AddRecord, RRDisplayString(m, answer));
 	if (!AddRecord) return;
 	
 	if (answer->rrtype == kDNSType_A)
 		{
 		query->info->ip.type = mDNSAddrType_IPv4;
-		query->info->ip.ip.v4 = answer->rdata->u.ip;
+		query->info->ip.ip.v4 = answer->rdata->u.ipv4;
 		}
 	else if (answer->rrtype == kDNSType_AAAA)
 		{
@@ -5087,7 +5635,7 @@ mDNSlocal void FoundServiceInfo(mDNS *const m, DNSQuestion *question, const Reso
 	query->GotADD = mDNStrue;
 	query->info->InterfaceID = answer->InterfaceID;
 
-	verbosedebugf("FoundServiceInfo v%d: %##s GotTXT=%d", query->info->ip.type, query->info->name.c, query->GotTXT);
+	verbosedebugf("FoundServiceInfo v%ld: %##s GotTXT=%d", query->info->ip.type, query->info->name.c, query->GotTXT);
 
 	// CAUTION: MUST NOT do anything more with query after calling query->Callback(), because the client's
 	// callback function is allowed to do anything, including deleting this query and freeing its memory.
@@ -5096,7 +5644,7 @@ mDNSlocal void FoundServiceInfo(mDNS *const m, DNSQuestion *question, const Reso
 		if (++query->Answers >= 100)
 			{
 			if (answer->rrtype == kDNSType_A)
-				debugf("**** WARNING **** have given %lu answers for %##s (A) %.4a",     query->Answers, query->qSRV.qname.c, &answer->rdata->u.ip);
+				debugf("**** WARNING **** have given %lu answers for %##s (A) %.4a",     query->Answers, query->qSRV.qname.c, &answer->rdata->u.ipv4);
 			else
 				debugf("**** WARNING **** have given %lu answers for %##s (AAAA) %.16a", query->Answers, query->qSRV.qname.c, &answer->rdata->u.ipv6);
 			}
@@ -5120,6 +5668,9 @@ mDNSexport mStatus mDNS_StartResolveService(mDNS *const m,
 	AssignDomainName(query->qSRV.qname, info->name);
 	query->qSRV.qtype               = kDNSType_SRV;
 	query->qSRV.qclass              = kDNSClass_IN;
+	query->qSRV.LongLived           = mDNSfalse;
+	query->qSRV.ExpectUnique        = mDNStrue;
+	query->qSRV.ForceMCast          = mDNSfalse;
 	query->qSRV.QuestionCallback    = FoundServiceInfoSRV;
 	query->qSRV.QuestionContext     = query;
 
@@ -5129,6 +5680,9 @@ mDNSexport mStatus mDNS_StartResolveService(mDNS *const m,
 	AssignDomainName(query->qTXT.qname, info->name);
 	query->qTXT.qtype               = kDNSType_TXT;
 	query->qTXT.qclass              = kDNSClass_IN;
+	query->qTXT.LongLived           = mDNSfalse;
+	query->qTXT.ExpectUnique        = mDNStrue;
+	query->qTXT.ForceMCast          = mDNSfalse;
 	query->qTXT.QuestionCallback    = FoundServiceInfoTXT;
 	query->qTXT.QuestionContext     = query;
 
@@ -5138,6 +5692,9 @@ mDNSexport mStatus mDNS_StartResolveService(mDNS *const m,
 	query->qAv4.qname.c[0]          = 0;
 	query->qAv4.qtype               = kDNSType_A;
 	query->qAv4.qclass              = kDNSClass_IN;
+	query->qAv4.LongLived           = mDNSfalse;
+	query->qAv4.ExpectUnique        = mDNStrue;
+	query->qAv4.ForceMCast          = mDNSfalse;
 	query->qAv4.QuestionCallback    = FoundServiceInfo;
 	query->qAv4.QuestionContext     = query;
 
@@ -5147,6 +5704,9 @@ mDNSexport mStatus mDNS_StartResolveService(mDNS *const m,
 	query->qAv6.qname.c[0]          = 0;
 	query->qAv6.qtype               = kDNSType_AAAA;
 	query->qAv6.qclass              = kDNSClass_IN;
+	query->qAv6.LongLived           = mDNSfalse;
+	query->qAv6.ExpectUnique        = mDNStrue;
+	query->qAv6.ForceMCast          = mDNSfalse;
 	query->qAv6.QuestionCallback    = FoundServiceInfo;
 	query->qAv6.QuestionContext     = query;
 
@@ -5165,6 +5725,7 @@ mDNSexport mStatus mDNS_StartResolveService(mDNS *const m,
 	info->port      = zeroIPPort;
 	info->TXTlen    = 0;
 
+	// We use mDNS_StartQuery_internal here because we're already holding the lock
 	status = mDNS_StartQuery_internal(m, &query->qSRV);
 	if (status == mStatus_NoError) status = mDNS_StartQuery_internal(m, &query->qTXT);
 	if (status != mStatus_NoError) mDNS_StopResolveService(m, query);
@@ -5176,13 +5737,14 @@ mDNSexport mStatus mDNS_StartResolveService(mDNS *const m,
 mDNSexport void    mDNS_StopResolveService (mDNS *const m, ServiceInfoQuery *query)
 	{
 	mDNS_Lock(m);
-	if (query->qSRV.ThisQInterval >= 0 || IsActiveUnicastQuery(&query->qSRV, &m->uDNS_info))
+	// We use mDNS_StopQuery_internal here because we're already holding the lock
+	if (query->qSRV.ThisQInterval >= 0 || uDNS_IsActiveQuery(&query->qSRV, &m->uDNS_info))
 		mDNS_StopQuery_internal(m, &query->qSRV);
-	if (query->qTXT.ThisQInterval >= 0 || IsActiveUnicastQuery(&query->qTXT, &m->uDNS_info))
+	if (query->qTXT.ThisQInterval >= 0 || uDNS_IsActiveQuery(&query->qTXT, &m->uDNS_info))
 		mDNS_StopQuery_internal(m, &query->qTXT);
-	if (query->qAv4.ThisQInterval >= 0 || IsActiveUnicastQuery(&query->qAv4, &m->uDNS_info))
+	if (query->qAv4.ThisQInterval >= 0 || uDNS_IsActiveQuery(&query->qAv4, &m->uDNS_info))
 		mDNS_StopQuery_internal(m, &query->qAv4);
-	if (query->qAv6.ThisQInterval >= 0 || IsActiveUnicastQuery(&query->qAv6, &m->uDNS_info))
+	if (query->qAv6.ThisQInterval >= 0 || uDNS_IsActiveQuery(&query->qAv6, &m->uDNS_info))
 		mDNS_StopQuery_internal(m, &query->qAv6);
 	mDNS_Unlock(m);
 	}
@@ -5194,11 +5756,14 @@ mDNSexport mStatus mDNS_GetDomains(mDNS *const m, DNSQuestion *const question, m
 	question->Target           = zeroAddr;
 	question->qtype            = kDNSType_PTR;
 	question->qclass           = kDNSClass_IN;
+	question->LongLived        = mDNSfalse;
+	question->ExpectUnique     = mDNSfalse;
+	question->ForceMCast       = mDNSfalse;
 	question->QuestionCallback = Callback;
 	question->QuestionContext  = Context;
-	if (DomainType > mDNS_DomainTypeRegistrationDefault) return(mStatus_BadParamErr);
+	if (DomainType > mDNS_DomainTypeBrowseLegacy) return(mStatus_BadParamErr);
 	if (!MakeDomainNameFromDNSNameString(&question->qname, mDNS_DomainTypeNames[DomainType])) return(mStatus_BadParamErr);
-	if (!dom) dom = (const domainname *)"\x5local";
+	if (!dom) dom = &localdomain;
 	if (!AppendDomainName(&question->qname, dom)) return(mStatus_BadParamErr);
 	return(mDNS_StartQuery(m, question));
 	}
@@ -5214,11 +5779,12 @@ mDNSexport mStatus mDNS_GetDomains(mDNS *const m, DNSQuestion *const question, m
 mDNSexport void mDNS_SetupResourceRecord(AuthRecord *rr, RData *RDataStorage, mDNSInterfaceID InterfaceID,
 	mDNSu16 rrtype, mDNSu32 ttl, mDNSu8 RecordType, mDNSRecordCallback Callback, void *Context)
 	{
+	  mDNSPlatformMemZero(&rr->uDNS_info, sizeof(uDNS_RegInfo));
 	// Don't try to store a TTL bigger than we can represent in platform time units
 	if (ttl > 0x7FFFFFFFUL / mDNSPlatformOneSecond)
 		ttl = 0x7FFFFFFFUL / mDNSPlatformOneSecond;
 	else if (ttl == 0)		// And Zero TTL is illegal
-		ttl = kDefaultTTLforShared;
+		ttl = DefaultTTLforRRType(rrtype);
 
 	// Field Group 1: Persistent metadata for Authoritative Records
 	rr->Additional1       = mDNSNULL;
@@ -5230,6 +5796,8 @@ mDNSexport void mDNS_SetupResourceRecord(AuthRecord *rr, RData *RDataStorage, mD
 
 	rr->resrec.RecordType        = RecordType;
 	rr->HostTarget        = mDNSfalse;
+	rr->AllowRemoteQuery  = mDNSfalse;
+	rr->ForceMCast        = mDNSfalse;
 	
 	// Field Group 2: Transient state for Authoritative Records (set in mDNS_Register_internal)
 	// Field Group 3: Transient state for Cache Records         (set in mDNS_Register_internal)
@@ -5263,19 +5831,17 @@ mDNSexport mStatus mDNS_Register(mDNS *const m, AuthRecord *const rr)
 	}
 
 mDNSexport mStatus mDNS_Update(mDNS *const m, AuthRecord *const rr, mDNSu32 newttl,
-	const mDNSu16 newrdlength,
-	RData *const newrdata, mDNSRecordUpdateCallback *Callback)
+	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;
-		}
+#ifndef UNICAST_DISABLED
+	mDNSBool unicast = !(rr->resrec.InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(&rr->resrec.name));
+#else
+	mDNSBool unicast = mDNSfalse;
+#endif
 
 	if (!ValidateRData(rr->resrec.rrtype, newrdlength, newrdata))
-		{ LogMsg("Attempt to update record with invalid rdata: %s", GetRRDisplayString_rdb(m, &rr->resrec, &newrdata->u)); return(mStatus_Invalid); }
-
+		{ LogMsg("Attempt to update record with invalid rdata: %s", GetRRDisplayString_rdb(&rr->resrec, &newrdata->u, m->MsgBuffer)); return(mStatus_Invalid); }
+	
 	mDNS_Lock(m);
 
 	// If TTL is unspecified, leave TTL unchanged
@@ -5283,7 +5849,7 @@ mDNSexport mStatus mDNS_Update(mDNS *const m, AuthRecord *const rr, mDNSu32 newt
 
 	// If we already have an update queued up which has not gone through yet,
 	// give the client a chance to free that memory
-	if (rr->NewRData)
+	if (!unicast && rr->NewRData)
 		{
 		RData *n = rr->NewRData;
 		rr->NewRData = mDNSNULL;			// Clear the NewRData pointer ...
@@ -5294,7 +5860,9 @@ mDNSexport mStatus mDNS_Update(mDNS *const m, AuthRecord *const rr, mDNSu32 newt
 	rr->NewRData             = newrdata;
 	rr->newrdlength          = newrdlength;
 	rr->UpdateCallback       = Callback;
-	
+
+	if (unicast) { mStatus status = uDNS_UpdateRecord(m, rr); mDNS_Unlock(m); return(status); }
+
 	if (rr->resrec.rroriginalttl == newttl && rr->resrec.rdlength == newrdlength && mDNSPlatformMemSame(rr->resrec.rdata->u.data, newrdata->u.data, newrdlength))
 		CompleteRDataUpdate(m, rr);
 	else
@@ -5302,8 +5870,7 @@ mDNSexport mStatus mDNS_Update(mDNS *const m, AuthRecord *const rr, mDNSu32 newt
 		domainlabel name;
 		domainname type, domain;
 		DeconstructServiceName(&rr->resrec.name, &name, &type, &domain);
-		if (rr->AnnounceCount < ReannounceCount)
-			rr->AnnounceCount = ReannounceCount;
+		rr->AnnounceCount = InitialAnnounceCount;
 		// iChat often does suprious record updates where no data has changed. For the _presence service type, using
 		// name/value pairs, the mDNSPlatformMemSame() check above catches this and correctly suppresses the wasteful
 		// update. For the _ichat service type, the XML encoding introduces spurious noise differences into the data
@@ -5314,15 +5881,15 @@ mDNSexport mStatus mDNS_Update(mDNS *const m, AuthRecord *const rr, mDNSu32 newt
 		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->NextUpdateCredit) rr->NextUpdateCredit = NonZeroTime(m->timenow + kUpdateCreditRefreshInterval);
 		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;
+			mDNSs32 delay = 6 - rr->UpdateCredits;		// Delay 1 second, then 2, then 3, etc. up to 6 seconds maximum
+			if (!rr->UpdateBlocked) rr->UpdateBlocked = NonZeroTime(m->timenow + delay * mDNSPlatformOneSecond);
 			rr->ThisAPInterval *= 4;
-			LogMsg("Excessive update rate for %##s; delaying announcement by %d second%s", rr->resrec.name.c, delay, delay > 1 ? "s" : "");
+			rr->LastAPTime = rr->UpdateBlocked - rr->ThisAPInterval;
+			LogMsg("Excessive update rate for %##s; delaying announcement by %ld second%s", rr->resrec.name.c, delay, delay > 1 ? "s" : "");
 			}
 		rr->resrec.rroriginalttl = newttl;
 		}
@@ -5360,18 +5927,22 @@ mDNSlocal void AdvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set)
 	if (!primary) primary = set; // If no existing advertised interface, this new NetworkInterfaceInfo becomes our new primary
 
 	// 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);
-
+	mDNS_SetupResourceRecord(&set->RR_A,     mDNSNULL, set->InterfaceID, kDNSType_A,     kHostNameTTL, kDNSRecordTypeUnique,      mDNS_HostNameCallback, set);
+	mDNS_SetupResourceRecord(&set->RR_PTR,   mDNSNULL, set->InterfaceID, kDNSType_PTR,   kHostNameTTL, kDNSRecordTypeKnownUnique, mDNSNULL, mDNSNULL);
+	mDNS_SetupResourceRecord(&set->RR_HINFO, mDNSNULL, set->InterfaceID, kDNSType_HINFO, kHostNameTTL, kDNSRecordTypeUnique,      mDNSNULL, mDNSNULL);
+
+#if ANSWER_REMOTE_HOSTNAME_QUERIES
+	set->RR_A    .AllowRemoteQuery  = mDNStrue;
+	set->RR_PTR  .AllowRemoteQuery  = mDNStrue;
+	set->RR_HINFO.AllowRemoteQuery  = mDNStrue;
+#endif
 	// 1. Set up Address record to map from host name ("foo.local.") to IP address
 	// 2. Set up reverse-lookup PTR record to map from our address back to our host name
-	AssignDomainName(set->RR_A.resrec.name, m->hostname);
+	AssignDomainName(set->RR_A.resrec.name, m->MulticastHostname);
 	if (set->ip.type == mDNSAddrType_IPv4)
 		{
 		set->RR_A.resrec.rrtype = kDNSType_A;
-		set->RR_A.resrec.rdata->u.ip = set->ip.ip.v4;
+		set->RR_A.resrec.rdata->u.ipv4 = set->ip.ip.v4;
 		// Note: This is reverse order compared to a normal dotted-decimal IP address
 		mDNS_snprintf(buffer, sizeof(buffer), "%d.%d.%d.%d.in-addr.arpa.",
 			set->ip.ip.v4.b[3], set->ip.ip.v4.b[2], set->ip.ip.v4.b[1], set->ip.ip.v4.b[0]);
@@ -5394,6 +5965,7 @@ mDNSlocal void AdvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set)
 
 	MakeDomainNameFromDNSNameString(&set->RR_PTR.resrec.name, buffer);
 	set->RR_PTR.HostTarget = mDNStrue;	// Tell mDNS that the target of this PTR is to be kept in sync with our host name
+	set->RR_PTR.ForceMCast = mDNStrue;	// This PTR points to our dot-local name, so don't ever try to write it into a uDNS server
 
 	set->RR_A.RRSet = &primary->RR_A;	// May refer to self
 
@@ -5403,7 +5975,7 @@ mDNSlocal void AdvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set)
 	if (m->HIHardware.c[0] > 0 && m->HISoftware.c[0] > 0 && m->HIHardware.c[0] + m->HISoftware.c[0] <= 254)
 		{
 		mDNSu8 *p = set->RR_HINFO.resrec.rdata->u.data;
-		AssignDomainName(set->RR_HINFO.resrec.name, m->hostname);
+		AssignDomainName(set->RR_HINFO.resrec.name, m->MulticastHostname);
 		set->RR_HINFO.DependentOn = &set->RR_A;
 		mDNSPlatformMemCopy(&m->HIHardware, p, 1 + (mDNSu32)m->HIHardware.c[0]);
 		p += 1 + (int)p[0];
@@ -5438,56 +6010,34 @@ mDNSlocal void DeadvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set)
 	if (set->RR_HINFO.resrec.RecordType) mDNS_Deregister_internal(m, &set->RR_HINFO, mDNS_Dereg_normal);
 	}
 
-mDNSlocal void GenerateFQDN(mDNS *const m, const char *domain, mDNSBool local)
+mDNSexport void mDNS_SetFQDN(mDNS *const m)
 	{
-	domainname newname;
-	mDNS_Lock(m);
-
-	newname.c[0] = 0;
-	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;
-
-		if (local) m->hostname = newname;
-		else       m->uDNS_info.hostname = newname;
+	domainname newmname;
+	NetworkInterfaceInfo *intf;
+	AuthRecord *rr;
+	newmname.c[0] = 0;
 
-		//!!!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)
-				local ? DeadvertiseInterface(m, intf) : uDNS_DeadvertiseInterface(m, intf);
+	if (!AppendDomainLabel(&newmname, &m->hostlabel))  { LogMsg("ERROR: mDNS_SetFQDN: Cannot create MulticastHostname"); return; }
+	if (!AppendLiteralLabelString(&newmname, "local")) { LogMsg("ERROR: mDNS_SetFQDN: Cannot create MulticastHostname"); return; }
+	if (SameDomainName(&m->MulticastHostname, &newmname)) { LogMsg("mDNS_SetFQDN - hostname unchanged"); return; }
 
-		// 2. Start advertising our address records using the new name
-		for (intf = m->HostInterfaces; intf; intf = intf->next)
-			if (intf->Advertise)
-				local ? AdvertiseInterface(m, intf) : uDNS_AdvertiseInterface(m, intf);
+	mDNS_Lock(m);
+	AssignDomainName(m->MulticastHostname, newmname);
 
-		// 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
-		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);
-	}
+	// 1. Stop advertising our address records on all interfaces
+	for (intf = m->HostInterfaces; intf; intf = intf->next)
+		if (intf->Advertise) DeadvertiseInterface(m, intf);
 
-mDNSexport void mDNS_GenerateFQDN(mDNS *const m)
-	{
-	GenerateFQDN(m, "local.", mDNStrue);
-	}
+	// 2. Start advertising our address records using the new name
+	for (intf = m->HostInterfaces; intf; intf = intf->next)
+		if (intf->Advertise) AdvertiseInterface(m, intf);
 
-mDNSexport void mDNS_GenerateGlobalFQDN(mDNS *const m)
-	{
-    if (!m->uDNS_info.NameRegDomain[0]) return;
-    GenerateFQDN(m, m->uDNS_info.NameRegDomain, mDNSfalse);
+	// 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);
+   
+	mDNS_Unlock(m);
 	}
 
 mDNSexport void mDNS_HostNameCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
@@ -5516,7 +6066,7 @@ mDNSexport void mDNS_HostNameCallback(mDNS *const m, AuthRecord *const rr, mStat
 	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)
 			{
@@ -5531,21 +6081,17 @@ mDNSexport void mDNS_HostNameCallback(mDNS *const m, AuthRecord *const rr, mStat
 		
 		// 3. Generate the FQDNs from the hostlabel,
 		// and make sure all SRV records, etc., are updated to reference our new hostname
-		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);
-			}
+		mDNS_SetFQDN(m);
+		LogMsg("Local Hostname %#s.local already in use; will try %#s.local instead", oldlabel.c, m->hostlabel.c);
+		}
+	else if (result == mStatus_MemFree)
+		{
+		// .local hostnames do not require goodbyes - we ignore the MemFree (which is sent directly by
+		// mDNS_Deregister_internal), and allow the caller to deallocate immediately following mDNS_DeadvertiseInterface
+		debugf("mDNS_HostNameCallback: MemFree (ignored)");
 		}
-	else LogMsg("mDNS_HostNameCallback: Unknown error %d for registration of record %s", result,  rr->resrec.name.c);
+	else
+		LogMsg("mDNS_HostNameCallback: Unknown error %ld for registration of record %s", result,  rr->resrec.name.c);
 	}
 
 mDNSlocal void UpdateInterfaceProtocols(mDNS *const m, NetworkInterfaceInfo *active)
@@ -5565,6 +6111,13 @@ mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *s
 	{
 	mDNSBool FirstOfType = mDNStrue;
 	NetworkInterfaceInfo **p = &m->HostInterfaces;
+
+	if (!set->InterfaceID)
+		{ LogMsg("Error! Tried to register a NetworkInterfaceInfo %#a with zero InterfaceID", &set->ip); return(mStatus_Invalid); }
+
+	if (!mDNSAddressIsValidNonZero(&set->mask))
+		{ LogMsg("Error! Tried to register a NetworkInterfaceInfo %#a with invalid mask %#a", &set->ip, &set->mask); return(mStatus_Invalid); }
+
 	mDNS_Lock(m);
 	
 	// Assume this interface will be active
@@ -5616,9 +6169,9 @@ mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *s
 		for (q = m->Questions; q; q=q->next)							// Scan our list of questions
 			if (!q->InterfaceID || q->InterfaceID == set->InterfaceID)	// If non-specific Q, or Q on this specific interface,
 				{														// then reactivate this question
-				q->ThisQInterval = InitialQuestionInterval;				// MUST be > zero for an active question
-				q->LastQTime     = m->timenow - q->ThisQInterval;
-				q->RecentAnswers = 0;
+				q->ThisQInterval    = InitialQuestionInterval;			// MUST be > zero for an active question
+				q->LastQTime        = m->timenow - q->ThisQInterval;
+				q->RecentAnswerPkts = 0;
 				if (ActiveQuestion(q)) m->NextScheduledQuery = m->timenow;
 				}
 		
@@ -5628,10 +6181,9 @@ mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *s
 			if (!rr->resrec.InterfaceID || rr->resrec.InterfaceID == set->InterfaceID)
 				{
 				if (rr->resrec.RecordType == kDNSRecordTypeVerified && !rr->DependentOn) rr->resrec.RecordType = kDNSRecordTypeUnique;
-				rr->ProbeCount        = DefaultProbeCountForRecordType(rr->resrec.RecordType);
-				if (rr->AnnounceCount < ReannounceCount)
-					rr->AnnounceCount = ReannounceCount;
-				rr->ThisAPInterval    = DefaultAPIntervalForRecordType(rr->resrec.RecordType);
+				rr->ProbeCount     = DefaultProbeCountForRecordType(rr->resrec.RecordType);
+				rr->AnnounceCount  = InitialAnnounceCount;
+				rr->ThisAPInterval = DefaultAPIntervalForRecordType(rr->resrec.RecordType);
 				InitializeLastAPTime(m, rr);
 				}
 		}
@@ -5717,11 +6269,8 @@ 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)
-		{
-		DeadvertiseInterface(m, set);
-		uDNS_DeadvertiseInterface(m, set);
-		}
+	if (set->Advertise) 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.
@@ -5755,12 +6304,14 @@ mDNSlocal void ServiceCallback(mDNS *const m, AuthRecord *const rr, mStatus resu
 		}
 	#endif
 
+	// Only pass on the NoError acknowledgement for the SRV record (when it finishes probing)
+	if (result == mStatus_NoError && rr != &sr->RR_SRV) return;
+
 	// If we got a name conflict on either SRV or TXT, forcibly deregister this service, and record that we did that
 	if (result == mStatus_NameConflict)
 		{
-		sr->Conflict = mDNStrue;							// Record that this service set had a conflict
-		sr->RR_PTR.AnnounceCount = InitialAnnounceCount;	// Make sure we don't send a goodbye for the PTR record
-		mDNS_DeregisterService(m, sr);						// Unlink the records from our list
+		sr->Conflict = mDNStrue;				// Record that this service set had a conflict
+		mDNS_DeregisterService(m, sr);			// Unlink the records from our list
 		return;
 		}
 	
@@ -5783,6 +6334,13 @@ mDNSlocal void ServiceCallback(mDNS *const m, AuthRecord *const rr, mStatus resu
 		sr->ServiceCallback(m, sr, result);
 	}
 
+mDNSlocal void NSSCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
+	{
+	ServiceRecordSet *sr = (ServiceRecordSet *)rr->RecordContext;
+	if (sr->ServiceCallback)
+		sr->ServiceCallback(m, sr, result);
+	}
+
 // Note:
 // Name is first label of domain name (any dots in the name are actual dots, not label separators)
 // Type is service type (e.g. "_ipp._tcp.")
@@ -5790,7 +6348,7 @@ mDNSlocal void ServiceCallback(mDNS *const m, AuthRecord *const rr, mStatus resu
 // We always register a TXT, even if it is empty (so that clients are not
 // left waiting forever looking for a nonexistent record.)
 // If the host parameter is mDNSNULL or the root domain (ASCII NUL),
-// then the default host name (m->hostname1) is automatically used
+// then the default host name (m->MulticastHostname) is automatically used
 mDNSexport mStatus mDNS_RegisterService(mDNS *const m, ServiceRecordSet *sr,
 	const domainlabel *const name, const domainname *const type, const domainname *const domain,
 	const domainname *const host, mDNSIPPort port, const mDNSu8 txtinfo[], mDNSu16 txtlen,
@@ -5809,11 +6367,14 @@ mDNSexport mStatus mDNS_RegisterService(mDNS *const m, ServiceRecordSet *sr,
 	if (host && host->c[0]) sr->Host = *host;
 	else sr->Host.c[0] = 0;
 	
+	// If port number is zero, that means the client is really trying to do a RegisterNoSuchService
+	if (!port.NotAnInteger) return(mDNS_RegisterNoSuchService(m, &sr->RR_SRV, name, type, domain, mDNSNULL, mDNSInterface_Any, NSSCallback, sr));
+
 	// Initialize the AuthRecord objects to sane values
-	mDNS_SetupResourceRecord(&sr->RR_ADV, mDNSNULL, InterfaceID, kDNSType_PTR, kDefaultTTLforShared, kDNSRecordTypeAdvisory, ServiceCallback, 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);
+	mDNS_SetupResourceRecord(&sr->RR_ADV, mDNSNULL, InterfaceID, kDNSType_PTR, kStandardTTL, kDNSRecordTypeAdvisory, ServiceCallback, sr);
+	mDNS_SetupResourceRecord(&sr->RR_PTR, mDNSNULL, InterfaceID, kDNSType_PTR, kStandardTTL, kDNSRecordTypeShared,   ServiceCallback, sr);
+	mDNS_SetupResourceRecord(&sr->RR_SRV, mDNSNULL, InterfaceID, kDNSType_SRV, kHostNameTTL, kDNSRecordTypeUnique,   ServiceCallback, sr);
+	mDNS_SetupResourceRecord(&sr->RR_TXT, mDNSNULL, InterfaceID, kDNSType_TXT, kStandardTTL, kDNSRecordTypeUnique,   ServiceCallback, sr);
 
 	// If 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
@@ -5843,9 +6404,11 @@ 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++)
 		{
-		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, &s, type, domain) == mDNSNULL) return(mStatus_BadParamErr);
+		domainname st;
+		AssignDomainName(st, sr->SubTypes[i].resrec.name);
+		AppendDomainName(&st, type);
+		mDNS_SetupResourceRecord(&sr->SubTypes[i], mDNSNULL, InterfaceID, kDNSType_PTR, kStandardTTL, kDNSRecordTypeShared, ServiceCallback, sr);
+		if (ConstructServiceName(&sr->SubTypes[i].resrec.name, mDNSNULL, &st, domain) == mDNSNULL) return(mStatus_BadParamErr);
 		AssignDomainName(sr->SubTypes[i].resrec.rdata->u.name, sr->RR_SRV.resrec.name);
 		sr->SubTypes[i].Additional1 = &sr->RR_SRV;
 		sr->SubTypes[i].Additional2 = &sr->RR_TXT;
@@ -5871,11 +6434,21 @@ mDNSexport mStatus mDNS_RegisterService(mDNS *const m, ServiceRecordSet *sr,
 		}
 	sr->RR_TXT.DependentOn = &sr->RR_SRV;
 
+#ifndef UNICAST_DISABLED	
 	// If the client has specified an explicit InterfaceID,
 	// then we do a multicast registration  on that interface, even for unicast domains.
-    if (!InterfaceID && !IsLocalDomain(&sr->RR_SRV.resrec.name))
-		return uDNS_RegisterService(m, sr);
-
+	if (!(InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(&sr->RR_SRV.resrec.name)))
+		{
+		mStatus status;
+		mDNS_Lock(m);
+		// Some (or perhaps all) versions of BIND named (name daemon) don't allow updates with zero-length rdata.
+		// (We have to duplicate this check here because uDNS_RegisterService() bypasses the usual mDNS_Register_internal() bottleneck)
+		if (!sr->RR_TXT.resrec.rdlength) { sr->RR_TXT.resrec.rdlength = 1; sr->RR_TXT.resrec.rdata->u.txt.c[0] = 0; }
+		status = uDNS_RegisterService(m, sr);
+		mDNS_Unlock(m);
+		return(status);
+		}
+#endif
 	mDNS_Lock(m);
 	err = mDNS_Register_internal(m, &sr->RR_SRV);
 	if (!err) err = mDNS_Register_internal(m, &sr->RR_TXT);
@@ -5900,22 +6473,30 @@ mDNSexport mStatus mDNS_AddRecordToService(mDNS *const m, ServiceRecordSet *sr,
 	ExtraResourceRecord **e;
 	mStatus status;
 
-	if (!sr->RR_SRV.resrec.InterfaceID && !IsLocalDomain(&sr->RR_SRV.resrec.name))
+	extra->next = mDNSNULL;
+	mDNS_SetupResourceRecord(&extra->r, rdata, sr->RR_PTR.resrec.InterfaceID, extra->r.resrec.rrtype, ttl, kDNSRecordTypeUnique, ServiceCallback, sr);
+	AssignDomainName(extra->r.resrec.name, sr->RR_SRV.resrec.name);
+	
+#ifndef UNICAST_DISABLED
+	if (!(sr->RR_SRV.resrec.InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(&sr->RR_SRV.resrec.name)))
 		{
-		LogMsg("mDNS_AddRecordToService: Not implemented for unicast DNS");
-		return mStatus_UnsupportedErr;
+		mDNS_Lock(m);
+		// Some (or perhaps all) versions of BIND named (name daemon) don't allow updates with zero-length rdata.
+		// (We have to duplicate this check here because uDNS_AddRecordToService() bypasses the usual mDNS_Register_internal() bottleneck)
+		if (extra->r.resrec.rrtype == kDNSType_TXT && extra->r.resrec.rdlength == 0)
+			{ extra->r.resrec.rdlength = 1; extra->r.resrec.rdata->u.txt.c[0] = 0; }
+		status = uDNS_AddRecordToService(m, sr, extra);
+		mDNS_Unlock(m);
+		return status;
 		}
-
+#endif
+	
 	mDNS_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
-	if (ttl == 0) ttl = kDefaultTTLforUnique;
+	if (ttl == 0) ttl = kStandardTTL;
 
-	extra->next          = mDNSNULL;
-	mDNS_SetupResourceRecord(&extra->r, rdata, sr->RR_PTR.resrec.InterfaceID, extra->r.resrec.rrtype, ttl, kDNSRecordTypeUnique, ServiceCallback, sr);
-	AssignDomainName(extra->r.resrec.name, sr->RR_SRV.resrec.name);
 	extra->r.DependentOn = &sr->RR_SRV;
 	
 	debugf("mDNS_AddRecordToService adding record to %##s", extra->r.resrec.name.c);
@@ -5926,17 +6507,11 @@ mDNSexport mStatus mDNS_AddRecordToService(mDNS *const m, ServiceRecordSet *sr,
 	return(status);
 	}
 
-mDNSexport mStatus mDNS_RemoveRecordFromService(mDNS *const m, ServiceRecordSet *sr, ExtraResourceRecord *extra)
+mDNSexport mStatus mDNS_RemoveRecordFromService(mDNS *const m, ServiceRecordSet *sr, ExtraResourceRecord *extra, mDNSRecordCallback MemFreeCallback, void *Context)
 	{
 	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;
@@ -5948,7 +6523,14 @@ mDNSexport mStatus mDNS_RemoveRecordFromService(mDNS *const m, ServiceRecordSet
 	else
 		{
 		debugf("mDNS_RemoveRecordFromService removing record from %##s", extra->r.resrec.name.c);
+		extra->r.RecordCallback = MemFreeCallback;
+		extra->r.RecordContext  = Context;
 		*e = (*e)->next;
+#ifndef UNICAST_DISABLED	
+		if (!(sr->RR_SRV.resrec.InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(&sr->RR_SRV.resrec.name)))
+			status = uDNS_DeregisterRecord(m, &extra->r);
+		else
+#endif
 		status = mDNS_Deregister_internal(m, &extra->r, mDNS_Dereg_normal);
 		}
 	mDNS_Unlock(m);
@@ -5998,17 +6580,27 @@ 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 port number is zero, that means this was actually registered using mDNS_RegisterNoSuchService()
+	if (!sr->RR_SRV.resrec.rdata->u.srv.port.NotAnInteger) return(mDNS_DeregisterNoSuchService(m, &sr->RR_SRV));
 
+#ifndef UNICAST_DISABLED	
+	if (!(sr->RR_SRV.resrec.InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(&sr->RR_SRV.resrec.name)))
+		{
+		mStatus status;
+		mDNS_Lock(m);
+		status = uDNS_DeregisterService(m, sr);
+		mDNS_Unlock(m);
+		return(status);
+		}
+#endif
 	if (sr->RR_PTR.resrec.RecordType == kDNSRecordTypeUnregistered)
 		{
-		debugf("Service set for %##s already deregistered", sr->RR_PTR.resrec.name.c);
+		debugf("Service set for %##s already deregistered", sr->RR_SRV.resrec.name.c);
 		return(mStatus_BadReferenceErr);
 		}
 	else if (sr->RR_PTR.resrec.RecordType == kDNSRecordTypeDeregistering)
 		{
-		debugf("Service set for %##s already in the process of deregistering", sr->RR_PTR.resrec.name.c);
+		debugf("Service set for %##s already in the process of deregistering", sr->RR_SRV.resrec.name.c);
 		return(mStatus_NoError);
 		}
 	else
@@ -6059,7 +6651,7 @@ mDNSexport mStatus mDNS_RegisterNoSuchService(mDNS *const m, AuthRecord *const r
 	const domainname *const host,
 	const mDNSInterfaceID InterfaceID, mDNSRecordCallback Callback, void *Context)
 	{
-	mDNS_SetupResourceRecord(rr, mDNSNULL, InterfaceID, kDNSType_SRV, kDefaultTTLforUnique, kDNSRecordTypeUnique, Callback, Context);
+	mDNS_SetupResourceRecord(rr, mDNSNULL, InterfaceID, kDNSType_SRV, kHostNameTTL, kDNSRecordTypeUnique, Callback, Context);
 	if (ConstructServiceName(&rr->resrec.name, name, type, domain) == mDNSNULL) return(mStatus_BadParamErr);
 	rr->resrec.rdata->u.srv.priority    = 0;
 	rr->resrec.rdata->u.srv.weight      = 0;
@@ -6072,7 +6664,7 @@ mDNSexport mStatus mDNS_RegisterNoSuchService(mDNS *const m, AuthRecord *const r
 mDNSexport mStatus mDNS_AdvertiseDomains(mDNS *const m, AuthRecord *rr,
 	mDNS_DomainType DomainType, const mDNSInterfaceID InterfaceID, char *domname)
 	{
-	mDNS_SetupResourceRecord(rr, mDNSNULL, InterfaceID, kDNSType_PTR, kDefaultTTLforShared, kDNSRecordTypeShared, mDNSNULL, mDNSNULL);
+	mDNS_SetupResourceRecord(rr, mDNSNULL, InterfaceID, kDNSType_PTR, kStandardTTL, kDNSRecordTypeShared, mDNSNULL, mDNSNULL);
 	if (!MakeDomainNameFromDNSNameString(&rr->resrec.name, mDNS_DomainTypeNames[DomainType])) return(mStatus_BadParamErr);
 	if (!MakeDomainNameFromDNSNameString(&rr->resrec.rdata->u.name, domname))                 return(mStatus_BadParamErr);
 	return(mDNS_Register(m, rr));
@@ -6109,19 +6701,21 @@ mDNSexport mStatus mDNS_Init(mDNS *const m, mDNS_PlatformSupport *const p,
 	mDNSBool AdvertiseLocalAddresses, mDNSCallback *Callback, void *Context)
 	{
 	mDNSu32 slot;
-	mDNSs32 timenow;
-	mStatus result = mDNSPlatformTimeInit(&timenow);
-	if (result != mStatus_NoError) return(result);
+	mDNSs32 timenow, timenow_adjust;
+	mStatus result;
 	
 	if (!rrcachestorage) rrcachesize = 0;
 	
 	m->p                       = p;
 	m->KnownBugs               = 0;
-	m->CanReceiveUnicast       = mDNSfalse;		// Assume we can't receive unicasts, unless platform layer tells us otherwise
+	m->CanReceiveUnicastOn5353 = mDNSfalse;		// Assume we can't receive unicasts on 5353, unless platform layer tells us otherwise
 	m->AdvertiseLocalAddresses = AdvertiseLocalAddresses;
 	m->mDNSPlatformStatus      = mStatus_Waiting;
+	m->UnicastPort4            = zeroIPPort;
+	m->UnicastPort6            = zeroIPPort;
 	m->MainCallback            = Callback;
 	m->MainContext             = Context;
+	m->rec.r.resrec.RecordType = 0;
 
 	// For debugging: To catch and report locking failures
 	m->mDNS_busy               = 0;
@@ -6132,9 +6726,14 @@ mDNSexport mStatus mDNS_Init(mDNS *const m, mDNS_PlatformSupport *const p,
 	m->lock_Records            = 0;
 
 	// Task Scheduling variables
+	result = mDNSPlatformTimeInit();
+	if (result != mStatus_NoError) return(result);
+	timenow_adjust = (mDNSs32)mDNSRandom(0xFFFFFFFF);
+	timenow = mDNSPlatformRawTime() + timenow_adjust;
+
 	m->timenow                 = 0;		// MUST only be set within mDNS_Lock/mDNS_Unlock section
 	m->timenow_last            = timenow;
-	m->timenow_adjust          = 0;
+	m->timenow_adjust          = timenow_adjust;
 	m->NextScheduledEvent      = timenow;
 	m->SuppressSending         = timenow;
 	m->NextCacheCheck          = timenow + 0x78000000;
@@ -6143,6 +6742,7 @@ mDNSexport mStatus mDNS_Init(mDNS *const m, mDNS_PlatformSupport *const p,
 	m->NextScheduledResponse   = timenow + 0x78000000;
 	m->ExpectUnicastResponse   = timenow + 0x78000000;
 	m->RandomQueryDelay        = 0;
+	m->PktNum                  = 0;
 	m->SendDeregistrations     = mDNSfalse;
 	m->SendImmediateAnswers    = mDNSfalse;
 	m->SleepState              = mDNSfalse;
@@ -6171,7 +6771,7 @@ mDNSexport mStatus mDNS_Init(mDNS *const m, mDNS_PlatformSupport *const p,
 	// Fields below only required for mDNS Responder...
 	m->hostlabel.c[0]          = 0;
 	m->nicelabel.c[0]          = 0;
-	m->hostname.c[0]           = 0;
+	m->MulticastHostname.c[0]  = 0;
 	m->HIHardware.c[0]         = 0;
 	m->HISoftware.c[0]         = 0;
 	m->ResourceRecords         = mDNSNULL;
@@ -6185,7 +6785,9 @@ mDNSexport mStatus mDNS_Init(mDNS *const m, mDNS_PlatformSupport *const p,
 	m->NumFailedProbes         = 0;
 	m->SuppressProbes          = 0;
 
+#ifndef UNICAST_DISABLED	
 	uDNS_Init(m);
+#endif
 	result = mDNSPlatformInit(m);
 
 	return(result);
@@ -6214,6 +6816,9 @@ mDNSexport void mDNS_Close(mDNS *const m)
 	
 	m->mDNS_shutdown = mDNStrue;
 
+#ifndef UNICAST_DISABLED	
+	uDNS_Close(m);
+#endif
 	rrcache_totalused = m->rrcache_totalused;
 	for (slot = 0; slot < CACHE_HASH_SLOTS; slot++)
 		{
@@ -6228,7 +6833,7 @@ mDNSexport void mDNS_Close(mDNS *const m)
 		// Reset tail pointer back to empty state (not that it really matters on exit, but we'll do it anyway, for the sake of completeness)
 		m->rrcache_tail[slot] = &m->rrcache_hash[slot];
 		}
-	debugf("mDNS_Close: RR Cache was using %ld records, %d active", rrcache_totalused, rrcache_active);
+	debugf("mDNS_Close: RR Cache was using %ld records, %lu active", rrcache_totalused, rrcache_active);
 	if (rrcache_active != m->rrcache_active)
 		LogMsg("*** ERROR *** rrcache_active %lu != m->rrcache_active %lu", rrcache_active, m->rrcache_active);
 
@@ -6252,8 +6857,6 @@ 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");
 
diff --git a/mDNSCore/mDNSDebug.h b/mDNSCore/mDNSDebug.h
index bcb0851..8f95d42 100755
--- a/mDNSCore/mDNSDebug.h
+++ b/mDNSCore/mDNSDebug.h
@@ -3,8 +3,6 @@
  *
  * @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
@@ -25,6 +23,9 @@
     Change History (most recent first):
 
 $Log: mDNSDebug.h,v $
+Revision 1.24  2004/09/16 01:58:21  cheshire
+Fix compiler warnings
+
 Revision 1.23  2004/05/18 23:51:25  cheshire
 Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
 
@@ -88,6 +89,7 @@ Merge in license terms from Quinn's copy, in preparation for Darwin release
 // (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.)
 
+//#undef MDNS_DEBUGMSGS
 //#define MDNS_DEBUGMSGS 2
 
 // Set MDNS_CHECK_PRINTF_STYLE_FUNCTIONS to 1 to enable extra GCC compiler warnings
@@ -136,8 +138,8 @@ extern void verbosedebugf_(const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(1
 // 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, ...);
+extern void LogMsgIdent(const char *ident, const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(2,3);
+extern void LogMsgNoIdent(const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(1,2);
 
 // 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()
diff --git a/mDNSCore/mDNSClientAPI.h b/mDNSCore/mDNSEmbeddedAPI.h
similarity index 72%
rename from mDNSCore/mDNSClientAPI.h
rename to mDNSCore/mDNSEmbeddedAPI.h
index df404f7..ac0215d 100755
--- a/mDNSCore/mDNSClientAPI.h
+++ b/mDNSCore/mDNSEmbeddedAPI.h
@@ -3,8 +3,6 @@
  *
  * @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
@@ -22,9 +20,317 @@
  * 
  * @APPLE_LICENSE_HEADER_END@
 
+
+   NOTE:
+   If you're building an application that uses DNS Service Discovery
+   this is probably NOT the header file you're looking for.
+   In most cases you will want to use /usr/include/dns_sd.h instead.
+
+   This header file defines the lowest level raw interface to mDNSCore,
+   which is appropriate *only* on tiny embedded systems where everything
+   runs in a single address space and memory is extremely constrained.
+   All the APIs here are malloc-free, which means that the caller is
+   responsible for passing in a pointer to the relevant storage that
+   will be used in the execution of that call, and (when called with
+   correct parameters) all the calls are guaranteed to succeed. There
+   is never a case where a call can suffer intermittent failures because
+   the implementation calls malloc() and sometimes malloc() returns NULL
+   because memory is so limited that no more is available.
+   This is primarily for devices that need to have precisely known fixed
+   memory requirements, with absolutely no uncertainty or run-time variation,
+   but that certainty comes at a cost of more difficult programming.
+   
+   For applications running on general-purpose desktop operating systems
+   (Mac OS, Linux, Solaris, Windows, etc.) the API you should use is
+   /usr/include/dns_sd.h, which defines the API by which multiple
+   independent client processes communicate their DNS Service Discovery
+   requests to a single "mdnsd" daemon running in the background.
+   
+   Even on platforms that don't run multiple independent processes in
+   multiple independent address spaces, you can still use the preferred
+   dns_sd.h APIs by linking in "dnssd_clientshim.c", which implements
+   the standard "dns_sd.h" API calls, allocates any required storage
+   using malloc(), and then calls through to the low-level malloc-free
+   mDNSCore routines defined here. This has the benefit that even though
+   you're running on a small embedded system with a single address space,
+   you can still use the exact same client C code as you'd use on a
+   general-purpose desktop system.
+
+
     Change History (most recent first):
 
-$Log: mDNSClientAPI.h,v $
+$Log: mDNSEmbeddedAPI.h,v $
+Revision 1.260  2004/12/12 23:51:42  ksekar
+<rdar://problem/3845683> Wide-area registrations should fallback to using DHCP hostname as target
+
+Revision 1.259  2004/12/11 20:55:29  ksekar
+<rdar://problem/3916479> Clean up registration state machines
+
+Revision 1.258  2004/12/10 20:48:32  cheshire
+<rdar://problem/3705229> Need to pick final EDNS numbers for LLQ and GC
+
+Revision 1.257  2004/12/10 02:09:23  cheshire
+<rdar://problem/3898376> Modify default TTLs
+
+Revision 1.256  2004/12/09 03:15:40  ksekar
+<rdar://problem/3806610> use _legacy instead of _default to find "empty string" browse domains
+
+Revision 1.255  2004/12/07 22:48:37  cheshire
+Tidying
+
+Revision 1.254  2004/12/07 21:26:04  ksekar
+<rdar://problem/3908336> DNSServiceRegisterRecord() can crash on deregistration
+
+Revision 1.253  2004/12/07 20:42:33  cheshire
+Add explicit context parameter to mDNS_RemoveRecordFromService()
+
+Revision 1.252  2004/12/07 03:02:12  ksekar
+Fixed comments, grouped unicast-specific routines together
+
+Revision 1.251  2004/12/06 21:15:22  ksekar
+<rdar://problem/3884386> mDNSResponder crashed in CheckServiceRegistrations
+
+Revision 1.250  2004/12/04 02:12:45  cheshire
+<rdar://problem/3517236> mDNSResponder puts LargeCacheRecord on the stack
+
+Revision 1.249  2004/12/03 05:18:33  ksekar
+<rdar://problem/3810596> mDNSResponder needs to return more specific TSIG errors
+
+Revision 1.248  2004/12/02 20:03:48  ksekar
+<rdar://problem/3889647> Rendezvous still publishes wide-area domains even after switching to a local subnet
+
+Revision 1.247  2004/12/01 20:57:19  ksekar
+<rdar://problem/3873921> Wide Area Rendezvous must be split-DNS aware
+
+Revision 1.246  2004/11/29 23:26:32  cheshire
+Added NonZeroTime() function, which usually returns the value given, with the exception
+that if the value given is zero, it returns one instead. For timer values where zero is
+used to mean "not set", this can be used to ensure that setting them to the result of an
+interval computation (e.g. "now+interval") does not inadvertently result in a zero value.
+
+Revision 1.245  2004/11/25 01:28:09  cheshire
+<rdar://problem/3557050> Need to implement random delay for 'QU' unicast replies (and set cache flush bit too)
+
+Revision 1.244  2004/11/24 22:00:59  cheshire
+Move definition of mDNSAddressIsAllDNSLinkGroup() from mDNSMacOSX.c to mDNSEmbeddedAPI.h
+
+Revision 1.243  2004/11/23 22:43:53  cheshire
+Tidy up code alignment
+
+Revision 1.242  2004/11/23 03:39:46  cheshire
+Let interface name/index mapping capability live directly in JNISupport.c,
+instead of having to call through to the daemon via IPC to get this information.
+
+Revision 1.241  2004/11/22 17:16:19  ksekar
+<rdar://problem/3854298> Unicast services don't disappear when you disable all networking
+
+Revision 1.240  2004/11/19 02:32:43  ksekar
+Wide-Area Rendezvous Security: Add LLQ-ID to events
+
+Revision 1.239  2004/11/15 20:09:23  ksekar
+<rdar://problem/3719050> Wide Area support for Add/Remove record
+
+Revision 1.238  2004/11/12 03:16:48  rpantos
+rdar://problem/3809541 Add mDNSPlatformGetInterfaceByName, mDNSPlatformGetInterfaceName
+
+Revision 1.237  2004/11/10 20:40:53  ksekar
+<rdar://problem/3868216> LLQ mobility fragile on non-primary interface
+
+Revision 1.236  2004/11/01 20:36:11  ksekar
+<rdar://problem/3802395> mDNSResponder should not receive Keychain Notifications
+
+Revision 1.235  2004/11/01 17:48:14  cheshire
+Changed SOA serial number back to signed. RFC 1035 may describe it as "unsigned", but
+it's wrong. The SOA serial is a modular counter, as explained in "DNS & BIND", page
+137. Since C doesn't have a modular type, we used signed, C's closest approximation.
+
+Revision 1.234  2004/10/29 21:59:02  ksekar
+SOA serial should be a unsigned integer, as per RFC 1035
+
+Revision 1.233  2004/10/28 03:24:41  cheshire
+Rename m->CanReceiveUnicastOn as m->CanReceiveUnicastOn5353
+
+Revision 1.232  2004/10/26 06:20:23  cheshire
+Add mDNSAddressIsValidNonZero() macro
+
+Revision 1.231  2004/10/26 06:11:41  cheshire
+Add improved logging to aid in diagnosis of <rdar://problem/3842714> mDNSResponder crashed
+
+Revision 1.230  2004/10/26 03:52:02  cheshire
+Update checkin comments
+
+Revision 1.229  2004/10/25 19:30:52  ksekar
+<rdar://problem/3827956> Simplify dynamic host name structures
+
+Revision 1.228  2004/10/23 01:16:00  cheshire
+<rdar://problem/3851677> uDNS operations not always reliable on multi-homed hosts
+
+Revision 1.227  2004/10/22 20:52:07  ksekar
+<rdar://problem/3799260> Create NAT port mappings for Long Lived Queries
+
+Revision 1.226  2004/10/20 01:50:40  cheshire
+<rdar://problem/3844991> Cannot resolve non-local registrations using the mach API
+Implemented ForceMCast mode for AuthRecords as well as for Questions
+
+Revision 1.225  2004/10/19 21:33:17  cheshire
+<rdar://problem/3844991> Cannot resolve non-local registrations using the mach API
+Added flag 'kDNSServiceFlagsForceMulticast'. Passing through an interface id for a unicast name
+doesn't force multicast unless you set this flag to indicate explicitly that this is what you want
+
+Revision 1.224  2004/10/16 00:16:59  cheshire
+<rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check
+
+Revision 1.223  2004/10/15 23:00:17  ksekar
+<rdar://problem/3799242> Need to update LLQs on location changes
+
+Revision 1.222  2004/10/12 02:49:20  ksekar
+<rdar://problem/3831228> Clean up LLQ sleep/wake, error handling
+
+Revision 1.221  2004/10/10 06:57:15  cheshire
+Change definition of "localdomain" to make code compile a little smaller
+
+Revision 1.220  2004/10/06 01:44:19  cheshire
+<rdar://problem/3813936> Resolving too quickly sometimes returns stale TXT record
+
+Revision 1.219  2004/10/03 23:18:58  cheshire
+Move address comparison macros from DNSCommon.h to mDNSEmbeddedAPI.h
+
+Revision 1.218  2004/10/03 23:14:12  cheshire
+Add "mDNSEthAddr" type and "zeroEthAddr" constant
+
+Revision 1.217  2004/09/30 00:24:56  ksekar
+<rdar://problem/3695802> Dynamically update default registration domains on config change
+
+Revision 1.216  2004/09/27 23:24:32  cheshire
+Fix typo: SOA refresh interval is supposed to be unsigned
+
+Revision 1.215  2004/09/26 23:20:35  ksekar
+<rdar://problem/3813108> Allow default registrations in multiple wide-area domains
+
+Revision 1.214  2004/09/25 02:41:39  cheshire
+<rdar://problem/3637266> Deliver near-pending "remove" events before new "add" events
+
+Revision 1.213  2004/09/25 02:24:27  cheshire
+Removed unused rr->UseCount
+
+Revision 1.212  2004/09/24 20:57:39  cheshire
+<rdar://problem/3680902> Eliminate inappropriate casts that cause misaligned-address errors
+
+Revision 1.211  2004/09/24 20:33:22  cheshire
+Remove unused DNSDigest_MD5 declaration
+
+Revision 1.210  2004/09/23 20:21:07  cheshire
+<rdar://problem/3426876> Refine "immediate answer burst; restarting exponential backoff sequence" logic
+Associate a unique sequence number with each received packet, and only increment the count of recent answer
+packets if the packet sequence number for this answer record is not one we've already seen and counted.
+
+Revision 1.209  2004/09/23 20:14:39  cheshire
+Rename "question->RecentAnswers" to "question->RecentAnswerPkts"
+
+Revision 1.208  2004/09/23 00:50:53  cheshire
+<rdar://problem/3419452> Don't send a (DE) if a service is unregistered after wake from sleep
+
+Revision 1.207  2004/09/22 02:34:46  cheshire
+Move definitions of default TTL times from mDNS.c to mDNSEmbeddedAPI.h
+
+Revision 1.206  2004/09/22 00:41:59  cheshire
+Move tcp connection status codes into the legal range allocated for mDNS use
+
+Revision 1.205  2004/09/21 23:40:11  ksekar
+<rdar://problem/3810349> mDNSResponder to return errors on NAT traversal failure
+
+Revision 1.204  2004/09/21 23:29:50  cheshire
+<rdar://problem/3680045> DNSServiceResolve should delay sending packets
+
+Revision 1.203  2004/09/21 20:58:22  cheshire
+Add ifname field to NetworkInterfaceInfo_struct
+
+Revision 1.202  2004/09/17 00:46:34  cheshire
+mDNS_TimeNow should take const mDNS parameter
+
+Revision 1.201  2004/09/17 00:31:51  cheshire
+For consistency with ipv6, renamed rdata field 'ip' to 'ipv4'
+
+Revision 1.200  2004/09/17 00:19:10  cheshire
+For consistency with AllDNSLinkGroupv6, rename AllDNSLinkGroup to AllDNSLinkGroupv4
+
+Revision 1.199  2004/09/16 21:59:16  cheshire
+For consistency with zerov6Addr, rename zeroIPAddr to zerov4Addr
+
+Revision 1.198  2004/09/16 21:36:36  cheshire
+<rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
+Changes to add necessary locking calls around unicast DNS operations
+
+Revision 1.197  2004/09/16 00:24:48  cheshire
+<rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
+
+Revision 1.196  2004/09/14 23:42:35  cheshire
+<rdar://problem/3801296> Need to seed random number generator from platform-layer data
+
+Revision 1.195  2004/09/14 23:27:46  cheshire
+Fix compile errors
+
+Revision 1.194  2004/09/10 00:49:57  cheshire
+<rdar://problem/3787644> Add error code kDNSServiceErr_Firewall, for future use
+
+Revision 1.193  2004/09/03 19:23:05  ksekar
+<rdar://problem/3788460>: Need retransmission mechanism for wide-area service registrations
+
+Revision 1.192  2004/09/02 03:48:47  cheshire
+<rdar://problem/3709039> Disable targeted unicast query support by default
+1. New flag kDNSServiceFlagsAllowRemoteQuery to indicate we want to allow remote queries for this record
+2. New field AllowRemoteQuery in AuthRecord structure
+3. uds_daemon.c sets AllowRemoteQuery if kDNSServiceFlagsAllowRemoteQuery is set
+4. mDNS.c only answers remote queries if AllowRemoteQuery is set
+
+Revision 1.191  2004/08/25 00:37:27  ksekar
+<rdar://problem/3774635>: Cleanup DynDNS hostname registration code
+
+Revision 1.190  2004/08/18 17:35:41  ksekar
+<rdar://problem/3651443>: Feature #9586: Need support for Legacy NAT gateways
+
+Revision 1.189  2004/08/14 03:22:41  cheshire
+<rdar://problem/3762579> Dynamic DNS UI <-> mDNSResponder glue
+Add GetUserSpecifiedDDNSName() routine
+Convert ServiceRegDomain to domainname instead of C string
+Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs
+
+Revision 1.188  2004/08/13 23:46:58  cheshire
+"asyncronous" -> "asynchronous"
+
+Revision 1.187  2004/08/13 23:37:02  cheshire
+Now that we do both uDNS and mDNS, global replace "uDNS_info.hostname" with
+"uDNS_info.UnicastHostname" for clarity
+
+Revision 1.186  2004/08/13 23:25:00  cheshire
+Now that we do both uDNS and mDNS, global replace "m->hostname" with
+"m->MulticastHostname" for clarity
+
+Revision 1.185  2004/08/12 00:32:36  ksekar
+<rdar://problem/3759567>: LLQ Refreshes never terminate if unanswered
+
+Revision 1.184  2004/08/11 17:09:31  cheshire
+Add comment clarifying the applicability of these APIs
+
+Revision 1.183  2004/08/10 23:19:14  ksekar
+<rdar://problem/3722542>: DNS Extension daemon for Wide Area Rendezvous
+Moved routines/constants to allow extern access for garbage collection daemon
+
+Revision 1.182  2004/07/30 17:40:06  ksekar
+<rdar://problem/3739115>: TXT Record updates not available for wide-area services
+
+Revision 1.181  2004/07/29 19:27:15  ksekar
+NATPMP Support - minor fixes and cleanup
+
+Revision 1.180  2004/07/29 02:03:35  ksekar
+Delete unused #define and structure field
+
+Revision 1.179  2004/07/26 22:49:30  ksekar
+<rdar://problem/3651409>: Feature #9516: Need support for NATPMP in client
+
+Revision 1.178  2004/07/13 21:24:24  rpantos
+Fix for <rdar://problem/3701120>.
+
 Revision 1.177  2004/06/05 00:04:26  cheshire
 <rdar://problem/3668639>: wide-area domains should be returned in reg. domain enumeration
 
@@ -54,7 +360,7 @@ 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"
+from mDNSMacOSX.h to mDNSEmbeddedAPI.h), implemented to return "local"
 only on non-OSX platforms.  Changed call to return a copy of the list
 to avoid shared memory issues.  Added a routine to free the list.
 
@@ -119,9 +425,9 @@ 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
+Added an asynchronous state machine mechanism to uDNS.c, including
 calls to find the parent zone for a domain name.  Changes include code
-in repository previously dissabled via "#if 0 //incomplete".  Codepath
+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
@@ -162,7 +468,7 @@ 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
+Move mDNSAddrIsDNSMulticast() from DNSCommon.h to mDNSEmbeddedAPI.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"
@@ -202,7 +508,7 @@ Revision 1.125  2003/11/22 00:18:27  cheshire
 Add compile-time asserts to verify correct sizes of mDNSu32, mDNSOpaque16, etc.
 
 Revision 1.124  2003/11/20 22:59:54  cheshire
-Changed runtime checks in mDNS.c to be compile-time checks in mDNSClientAPI.h
+Changed runtime checks in mDNS.c to be compile-time checks in mDNSEmbeddedAPI.h
 Thanks to Bob Bradley for suggesting the ingenious compiler trick to make this work.
 
 Revision 1.123  2003/11/20 22:53:01  cheshire
@@ -216,13 +522,13 @@ 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.
+Best solution is just to combine mDNSEmbeddedAPI.h and mDNSPlatformFunctions.h into a single file.
 
 Revision 1.119  2003/11/14 19:47:52  cheshire
 Define symbol MAX_ESCAPED_DOMAIN_NAME to indicate recommended buffer size for ConvertDomainNameToCString
 
 Revision 1.118  2003/11/14 19:18:34  cheshire
-Move AssignDomainName macro to mDNSClientAPI.h to that client layers can use it too
+Move AssignDomainName macro to mDNSEmbeddedAPI.h to that client layers can use it too
 
 Revision 1.117  2003/11/08 23:32:24  cheshire
 Gave name to anonymous struct, to avoid errors on certain compilers.
@@ -302,7 +608,7 @@ We want to avoid touching the rdata pages, so we don't page them in.
 
 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 mDNSClientAPI.h so daemon.c can use them
+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
@@ -346,10 +652,10 @@ To eliminate compiler warnings, changed definition of mDNSBool from
 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 mDNSClientAPI.h to mDNSPlatformFunctions.h where they belong
+Move platform-layer function prototypes from mDNSEmbeddedAPI.h to mDNSPlatformFunctions.h where they belong
 
 Revision 1.86  2003/07/20 03:52:02  ksekar
-<rdar://problem/3320722>: Feature: New Rendezvous APIs (#7875) (mDNSResponder component)
+<rdar://problem/3320722>: Feature: New DNS-SD APIs (#7875) (mDNSResponder component)
 Added error type for incompatibility between daemon and client versions
 
 Revision 1.85  2003/07/19 03:23:13  cheshire
@@ -589,7 +895,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-existance
+Added mDNS_RegisterNoSuchService() function for assertion of non-existence
 of a particular named service
 
 Revision 1.23  2002/09/19 21:25:34  cheshire
@@ -739,13 +1045,15 @@ typedef struct mDNSInterfaceID_dummystruct { void *dummy; } *mDNSInterfaceID;
 // 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[ 2]; mDNSu16 NotAnInteger; } mDNSOpaque16;
+typedef packedunion { mDNSu8 b[ 4]; mDNSu32 NotAnInteger; } mDNSOpaque32;
+typedef packedunion { mDNSu8 b[ 6]; mDNSu16 w[3]; mDNSu32 l[1]; } mDNSOpaque48;
 typedef packedunion { mDNSu8 b[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)
+typedef mDNSOpaque48  mDNSEthAddr;		// An Ethernet address is a six-byte opaque identifier (not an integer)
 
 enum
 	{
@@ -775,7 +1083,7 @@ enum
 	// the bottom end of the range (FFFE FF00) is used for non-error values;
 
 	// Error codes:
-	mStatus_UnknownErr        = -65537,		// 0xFFFE FFFF
+	mStatus_UnknownErr        = -65537,		// First value: 0xFFFE FFFF
 	mStatus_NoSuchNameErr     = -65538,
 	mStatus_NoMemoryErr       = -65539,
 	mStatus_BadParamErr       = -65540,
@@ -788,23 +1096,32 @@ enum
 	mStatus_AlreadyRegistered = -65547,
 	mStatus_NameConflict      = -65548,
 	mStatus_Invalid           = -65549,
-	//                        = -65550,
+	mStatus_Firewall          = -65550,
 	mStatus_Incompatible      = -65551,
 	mStatus_BadInterfaceErr   = -65552,
 	mStatus_Refused           = -65553,
 	mStatus_NoSuchRecord      = -65554,
-    mStatus_NoAuth            = -65555,
-	// -65556 - -65789 currently unused
+	mStatus_NoAuth            = -65555,
+	mStatus_NoSuchKey         = -65556,
+	mStatus_NATTraversal      = -65557,
+	mStatus_DblNAT            = -65558,
+	mStatus_BadTime           = -65559,
+	mStatus_BadSig            = -65560,     // while we define this per RFC 2845, BIND 9 returns Refused for bad/missing signatures
+	mStatus_BadKey            = -65561,
+	
+	// -65562 to -65786 currently unused; available for allocation
+
+	// tcp connection status
+	mStatus_ConnPending       = -65787,
+	mStatus_ConnFailed        = -65788,
+	mStatus_ConnEstablished   = -65789,
 
 	// Non-error values:
 	mStatus_GrowCache         = -65790,
 	mStatus_ConfigChanged     = -65791,
-	mStatus_MemFree           = -65792,		// 0xFFFE FF00
-
-	// tcp connection status
-	mStatus_ConnectionPending = -65793,
-	mStatus_ConnectionFailed =  -65794,
-	mStatus_ConnectionEstablished = -65795
+	mStatus_MemFree           = -65792		// Last value: 0xFFFE FF00
+	
+	// mStatus_MemFree is the last legal mDNS error code, at the end of the range allocated for mDNS
 	};
 
 typedef mDNSs32 mStatus;
@@ -834,6 +1151,15 @@ typedef struct { mDNSu8 c[256]; } UTF8str255;		// Null-terminated C string
 #define MAX_ESCAPED_DOMAIN_LABEL 254
 #define MAX_ESCAPED_DOMAIN_NAME 1005
 
+// Most records have a TTL of 75 minutes, so that their 80% cache-renewal query occurs once per hour.
+// For records containing a hostname (in the name on the left, or in the rdata on the right),
+// like A, AAAA, reverse-mapping PTR, and SRV, we use a two-minute TTL by default, because we don't want
+// them to hang around for too long in the cache if the host in question crashes or otherwise goes away.
+#define kStandardTTL (3600 * 100 / 80)
+#define kHostNameTTL 120
+
+#define DefaultTTLforRRType(X) (((X) == kDNSType_A || (X) == kDNSType_AAAA || (X) == kDNSType_SRV) ? kHostNameTTL : kStandardTTL)
+
 // ***************************************************************************
 #if 0
 #pragma mark - DNS Message structures
@@ -938,24 +1264,34 @@ enum
 	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
+	kDNSRecordTypePacketAdd        = 0x80,	// Received in the Additional  Section of a DNS Response
+	kDNSRecordTypePacketAddUnique  = 0x90,	// Received in the Additional  Section of a DNS Response with kDNSClass_UniqueRRSet set
+	kDNSRecordTypePacketAuth       = 0xA0,	// Received in the Authorities Section of a DNS Response
+	kDNSRecordTypePacketAuthUnique = 0xB0,	// Received in the Authorities Section of a DNS Response with kDNSClass_UniqueRRSet set
+	kDNSRecordTypePacketAns        = 0xC0,	// Received in the Answer      Section of a DNS Response
+	kDNSRecordTypePacketAnsUnique  = 0xD0,	// Received in the Answer      Section of a DNS Response with kDNSClass_UniqueRRSet set
 
-	kDNSRecordTypePacketAnsMask    = 0x40,	// True for PacketAns       and PacketAnsUnique
-	kDNSRecordTypePacketUniqueMask = 0x20	// True for PacketAddUnique and PacketAnsUnique
+	kDNSRecordTypePacketAnsMask    = 0x40,	// True for PacketAns and    PacketAnsUnique
+	kDNSRecordTypePacketUniqueMask = 0x10	// True for PacketAddUnique, PacketAnsUnique, PacketAuthUnique
 	};
 
 typedef packedstruct { mDNSu16 priority; mDNSu16 weight; mDNSIPPort port; domainname target;   } rdataSRV;
 typedef packedstruct { mDNSu16 preference;                                domainname exchange; } rdataMX;
-typedef packedstruct { domainname mname; domainname rname; mDNSOpaque32 serial; mDNSOpaque32 refresh;
-                       mDNSOpaque32 retry; mDNSOpaque32 expire; mDNSOpaque32 min;              } rdataSOA;
+typedef packedstruct
+	{
+	domainname mname;
+	domainname rname;
+	mDNSs32 serial;		// Modular counter; increases when zone changes
+	mDNSu32 refresh;	// Time in seconds that a slave waits after successful replication of the database before it attempts replication again
+	mDNSu32 retry;		// Time in seconds that a slave waits after an unsuccessful replication attempt before it attempts replication again
+	mDNSu32 expire;		// Time in seconds that a slave holds on to old data while replication attempts remain unsuccessful
+	mDNSu32 min;		// Nominally the minimum record TTL for this zone, in seconds; also used for negative caching.
+	} rdataSOA;
 
 typedef packedstruct
 	{
 	mDNSu16 vers;
-    mDNSu16 llqOp;
+	mDNSu16 llqOp;
 	mDNSu16 err;
 	mDNSu8 id[8];
 	mDNSu32 lease;
@@ -989,14 +1325,14 @@ typedef packedstruct
 typedef union
 	{
 	mDNSu8      data[StandardAuthRDSize];
-	mDNSv4Addr  ip;			// For 'A' record
+	mDNSv4Addr  ipv4;		// For 'A' record
 	mDNSv6Addr  ipv6;		// For 'AAAA' record
 	domainname  name;		// For PTR, NS, and CNAME records
 	UTF8str255  txt;		// For TXT record
 	rdataSRV    srv;		// For SRV record
 	rdataMX     mx;			// For MX record
-    rdataSOA    soa;        // For SOA record
-    rdataOpt    opt;        // For eDNS0 opt record
+	rdataSOA    soa;        // For SOA record
+	rdataOpt    opt;        // For eDNS0 opt record
 	} RDataBody;
 
 typedef struct
@@ -1012,6 +1348,7 @@ typedef struct ResourceRecord_struct ResourceRecord;
 typedef struct DNSQuestion_struct DNSQuestion;
 typedef struct mDNS_struct mDNS;
 typedef struct mDNS_PlatformSupport_struct mDNS_PlatformSupport;
+typedef struct NATTraversalInfo_struct NATTraversalInfo;
 
 // 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);
@@ -1041,7 +1378,8 @@ struct ResourceRecord_struct
 	RData           *rdata;				// Pointer to storage for this rdata
 	};
 
-enum
+// Unless otherwise noted, states may apply to either independent record registrations or service registrations	
+typedef enum
 	{
 	regState_FetchingZoneData  = 1,     // getting info - update not sent
 	regState_Pending           = 2,     // update sent, reply not received
@@ -1049,24 +1387,45 @@ enum
 	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;
-
+	regState_Refresh           = 9,     // outstanding refresh (or target change) message
+	regState_NATMap            = 10,    // establishing NAT port mapping or learning public address
+	regState_UpdatePending     = 11,    // update in flight as result of mDNS_Update call
+	regState_NoTarget          = 12,    // service registration pending registration of hostname (ServiceRegistrations only)
+    regState_ExtraQueued       = 13     // extra record to be registered upon completion of service registration (RecordRegistrations only)
+	} regState_t; 
+
+// context for both ServiceRecordSet and individual AuthRec structs
 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)
+	// registration/lease state
+	regState_t   state;
+	mDNSBool     lease;    // dynamic update contains (should contain) lease option
+	mDNSs32      expire;   // expiration of lease (-1 for static)
+	mDNSBool     TestForSelfConflict;  // on name conflict, check if we're just seeing our own orphaned records
+	
+	// identifier to match update request and response
+	mDNSOpaque16 id;
+	
+	// server info
+	domainname   zone;     // the zone that is updated
+	mDNSAddr     ns;       // primary name server for the record's zone    !!!KRS not technically correct to cache longer than TTL
+	mDNSIPPort   port;     // port on which server accepts dynamic updates
+	
+	// NAT traversal context
+	NATTraversalInfo *NATinfo; // may be NULL
+	
+	// state for deferred operations
+    mDNSBool     ClientCallbackDeferred;  // invoke client callback on completion of pending operation(s)
+	mStatus      DeferredStatus;          // status to deliver when above flag is set
+    mDNSBool     SRVUpdateDeferred;       // do we need to change target or port once current operation completes?
+    mDNSBool     LostTarget;              // temporarily deregistered service because its target was deregistered
+
+    // uDNS_UpdateRecord support fields
+	mDNSBool     UpdateQueued; // Update the rdata once the current pending operation completes
+	RData       *UpdateRData;  // Pointer to new RData while a record update is in flight
+	mDNSu16      UpdateRDLen;  // length of above field
+	mDNSRecordUpdateCallback *UpdateRDCallback; // client callback to free old rdata
 	} uDNS_RegInfo;
 
 struct AuthRecord_struct
@@ -1078,23 +1437,27 @@ struct AuthRecord_struct
 
 	AuthRecord     *next;				// Next in list; first element of structure for efficiency reasons
 	ResourceRecord  resrec;
-    uDNS_RegInfo uDNS_info;
+	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
 	AuthRecord     *RRSet;				// This unique record is part of an RRSet
-	mDNSRecordCallback *RecordCallback;	// Callback function to call for state changes
+	mDNSRecordCallback *RecordCallback;	// Callback function to call for state changes, and to free memory asynchronously on deregistration
 	void           *RecordContext;		// Context parameter for the callback function
 	mDNSu8          HostTarget;			// Set if the target of this record (PTR, CNAME, SRV, etc.) is our host name
+	mDNSu8          AllowRemoteQuery;	// Set if we allow hosts not on the local link to query this record
+	mDNSu8          ForceMCast;			// Set by client to advertise solely via multicast, even for apparently unicast names
 
 	// Transient state for Authoritative Records
 	mDNSu8          Acknowledged;		// Set if we've given the success callback to the client
 	mDNSu8          ProbeCount;			// Number of probes remaining before this record is valid (kDNSRecordTypeUnique)
 	mDNSu8          AnnounceCount;		// Number of announcements remaining (kDNSRecordTypeShared)
+	mDNSu8          RequireGoodbye;		// Set if this RR has been announced on the wire and will require a goodbye packet
 	mDNSu8          IncludeInProbe;		// Set if this RR is being put into a probe right now
 	mDNSInterfaceID ImmedAnswer;		// Someone on this interface issued a query we need to answer (all-ones for all interfaces)
+	mDNSu8          ImmedUnicast;		// Set if we may send our response directly via unicast to the requester
 #if MDNS_LOG_ANSWER_SUPPRESSION_TIMES
 	mDNSs32         ImmedAnswerMarkTime;
 #endif
@@ -1123,6 +1486,13 @@ struct AuthRecord_struct
 	// DO NOT ADD ANY MORE FIELDS HERE
 	};
 
+// Wrapper struct for Auth Records for higher-level code that cannot use the AuthRecord's ->next pointer field
+typedef struct ARListElem
+	{
+	struct ARListElem *next;
+	AuthRecord ar;          // Note: Must be last struct in field to accomodate oversized AuthRecords
+	} ARListElem;
+
 struct CacheRecord_struct
 	{
 	CacheRecord    *next;				// Next in list; first element of structure for efficiency reasons
@@ -1131,9 +1501,9 @@ struct CacheRecord_struct
 	// 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         DelayDelivery;		// Set if we want to defer delivery of this answer to local clients
 	mDNSs32         NextRequiredQuery;	// In platform time units
 	mDNSs32         LastUsed;			// In platform time units
-	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
@@ -1152,14 +1522,22 @@ typedef struct
 	mDNSu8 _extradata[MaximumRDSize-InlineCacheRDSize];		// Glue on the necessary number of extra bytes
 	} LargeCacheRecord;
 
-typedef struct NetworkInterfaceInfo_struct NetworkInterfaceInfo;
+typedef struct uDNS_HostnameInfo
+	{
+	struct uDNS_HostnameInfo *next;
+	AuthRecord *ar;                           // registered address record
+	mDNSRecordCallback *StatusCallback;       // callback to deliver success or error code to client layer
+	const void *StatusContext;                // Client Context
+	} uDNS_HostnameInfo;
 
-typedef struct
+typedef struct DNSServer
 	{
-    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;
+    struct DNSServer *next;
+    mDNSAddr addr;
+    domainname domain;       // name->server matching for "split dns"
+	} DNSServer;
+
+typedef struct NetworkInterfaceInfo_struct NetworkInterfaceInfo;
 
 // A NetworkInterfaceInfo_struct serves two purposes:
 // 1. It holds the address, PTR and HINFO records to advertise a given IP address on a given physical interface
@@ -1184,11 +1562,11 @@ 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;		// Identifies physical interface; MUST NOT be 0, -1, or -2
 	mDNSAddr        ip;					// The IPv4 or IPv6 address to advertise
+	mDNSAddr        mask;
+	char            ifname[16];
 	mDNSBool        Advertise;			// False if you are only searching on this interface
 	mDNSBool        McastTxRx;			// Send/Receive multicast on this { InterfaceID, address family } ?
 	};
@@ -1197,6 +1575,7 @@ typedef struct ExtraResourceRecord_struct ExtraResourceRecord;
 struct ExtraResourceRecord_struct
 	{
 	ExtraResourceRecord *next;
+    mDNSu32 ClientID;  // Opaque ID field to be used by client to map an AddRecord call to a set of Extra records
 	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
@@ -1211,9 +1590,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.
-    ServiceRecordSet    *next;
-    uDNS_RegInfo        uDNS_info;
-    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;
@@ -1248,15 +1627,20 @@ typedef struct
 
 typedef enum
 	{
+	// Setup states
 	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_Refresh           = 4,
+	LLQ_Retry             = 5,
+	LLQ_Established       = 6,	
+	LLQ_Suspended         = 7,   
+	LLQ_SuspendDeferred   = 8, // suspend once we get zone info
+	LLQ_SuspendedPoll     = 9, // suspended from polling state
+	LLQ_NatMapWait        = 10,
+	
+	// Established/error states
 	LLQ_Static            = 16,
 	LLQ_Poll              = 17,
 	LLQ_Error             = 18,
@@ -1265,21 +1649,22 @@ typedef enum
 
 typedef struct
 	{
-    LLQ_State state;
-    mDNSAddr servAddr;
-    mDNSIPPort servPort;
-    DNSQuestion *question;
-    mDNSu32 origLease;  // seconds (relative)
-    mDNSs32 retry;  // ticks (absolute)
-    mDNSs32 expire; // ticks (absolute)
+	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;
+	mDNSu8 id[8];
+	mDNSBool deriveRemovesOnResume;
+    mDNSBool NATMap;        // does this LLQ use the global LLQ NAT mapping?
 	} LLQ_Info;
 
 // LLQ constants
-#define kDNSOpt_LLQ	   1 //!!!KRS
-#define kDNSOpt_Lease  2 //!!!KRS
+#define kDNSOpt_LLQ	   1
+#define kDNSOpt_Lease  2
 #define kLLQ_Vers      0 // prerelease
 #define kLLQ_DefLease  7200 // 2 hours
 #define kUpdate_DefLease 7200
@@ -1287,8 +1672,9 @@ typedef struct
 #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 kLLQOp_Setup     1
+#define kLLQOp_Refresh   2
+#define kLLQOp_Event     3
 
 #define LLQ_OPT_SIZE (2 * sizeof(mDNSu16)) + sizeof(LLQOptData)
 #define LEASE_OPT_SIZE (2 * sizeof(mDNSu16)) + sizeof(mDNSs32)
@@ -1307,15 +1693,16 @@ enum
 
 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
+	{
+	mDNSOpaque16          id;
+	mDNSBool              internal;
+	InternalResponseHndlr responseCallback;   // NULL if internal field is false
+	LLQ_Info              *llq;               // NULL for 1-shot queries
+    mDNSBool              Answered;           // have we received an answer (including NXDOMAIN) for this question?
     CacheRecord           *knownAnswers;
+    mDNSs32               RestartTime;        // Mark when we restart a suspended query
     void *context;
-    } uDNS_QuestionInfo;
+	} 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);
@@ -1324,12 +1711,14 @@ 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               DelayAnswering;	// Set if we want to defer answering this question until the cache settles
 	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
+	mDNSs32               LastAnswerPktNum;	// The sequence number of the last response packet containing an answer to this Q
+	mDNSu32               RecentAnswerPkts;	// Number of answers since the last time we sent this query
 	mDNSu32               CurrentAnswers;	// Number of records currently in the cache that answer this question
 	mDNSu32               LargeAnswers;		// Number of answers with rdata > 1024 bytes
 	mDNSu32               UniqueAnswers;	// Number of answers received with kDNSClass_UniqueRRSet bit set
@@ -1339,7 +1728,7 @@ 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;
+	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 queries only on a single specific IP interface
@@ -1349,10 +1738,11 @@ struct DNSQuestion_struct
 	domainname            qname;
 	mDNSu16               qtype;
 	mDNSu16               qclass;
+	mDNSBool              LongLived;        // Set by client for calls to mDNS_StartQuery to indicate LLQs to unicast layer.
+	mDNSBool              ExpectUnique;		// Set by client if it's expecting unique RR(s) for this question, not shared RRs
+	mDNSBool              ForceMCast;		// Set by client to force mDNS query, even for apparently uDNS names
 	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
@@ -1391,6 +1781,72 @@ struct ServiceInfoQuery_struct
 	void                         *ServiceInfoQueryContext;
 	};
 
+// ***************************************************************************
+#if 0
+#pragma mark - NAT Traversal structures and constants
+#endif
+
+#define NATMAP_INIT_RETRY (mDNSPlatformOneSecond / 4)          // start at 250ms w/ exponential decay
+#define NATMAP_MAX_RETRY mDNSPlatformOneSecond                 // back off to once per second
+#define NATMAP_MAX_TRIES 3                                     // for max 3 tries
+#define NATMAP_DEFAULT_LEASE (60 * 60)  // lease life in seconds
+#define NATMAP_VERS 0
+#define NATMAP_PORT 5351
+#define ADDR_REQUEST_PKTLEN 2
+#define ADDR_REPLY_PKTLEN 8
+#define PORTMAP_PKTLEN 12
+#define NATMAP_RESPONSE_MASK 0x80
+
+typedef enum
+	{
+	NATOp_AddrRequest = 0,
+	NATOp_MapUDP      = 1,
+	NATOp_MapTCP      = 2
+	} NATOp_t;
+
+enum
+   	{
+   	NATErr_None = 0,
+   	NATErr_Vers = 1,
+   	NATErr_Refused = 2,
+   	NATErr_NetFail = 3,
+   	NATErr_Res = 4,
+   	NATErr_Opcode = 5
+   	};
+
+typedef mDNSu16 NATErr_t;
+
+typedef enum
+	{
+	NATState_Init,
+	NATState_Request,
+	NATState_Established,
+	NATState_Legacy,
+	NATState_Error,
+	NATState_Refresh,
+	NATState_Deleted
+	} NATState_t;
+// Note: we have no explicit "cancelled" state, where a service/interface is deregistered while we
+ // have an outstanding NAT request.  This is conveyed by the "reg" pointer being set to NULL
+
+// Pass NULL for pkt on error (including timeout)
+typedef void (*NATResponseHndlr)(NATTraversalInfo *n, mDNS *m, mDNSu8 *pkt, mDNSu16 len);
+
+struct NATTraversalInfo_struct
+	{
+	NATOp_t op;
+	NATResponseHndlr ReceiveResponse;
+	union { AuthRecord *RecordRegistration; ServiceRecordSet *ServiceRegistration; } reg;
+	mDNSIPPort PublicPort;
+	mDNSu8 request[PORTMAP_PKTLEN];  // buffer for request messages
+	int requestlen;                  // length of buffer used
+	mDNSs32 retry;                   // absolute time when we retry
+	mDNSs32 RetryInterval;           // delta between time sent and retry
+	int ntries;
+	NATState_t state;
+	NATTraversalInfo *next;
+	};
+
 // ***************************************************************************
 #if 0
 #pragma mark - Main mDNS object, used to hold all the mDNS state
@@ -1406,27 +1862,28 @@ enum
 	};
 
 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;
+	{
+	mDNSs32          nextevent;
+	DNSQuestion      *ActiveQueries;     //!!!KRS this should be a hashtable (hash on messageID)
+	DNSQuestion      *CurrentQuery;      // pointer to ActiveQueries list being examined in a loop.  Functions that remove
+										 // elements from the ActiveQueries list must update this pointer (if non-NULL) as necessary.
+										 //!!!KRS do the same for registration lists
+	ServiceRecordSet *ServiceRegistrations;
+	AuthRecord       *RecordRegistrations;
+	NATTraversalInfo *NATTraversals;
+	mDNSu16          NextMessageID;
+    DNSServer        *Servers;           // list of DNS servers
+	mDNSAddr         Router;
+	mDNSAddr         PrimaryIP;          // Address of primary interface
+	mDNSAddr         MappedPrimaryIP;    // Cache of public address if PrimaryIP is behind a NAT
+    NATTraversalInfo *LLQNatInfo;        // Nat port mapping to receive LLQ events
+	domainname       ServiceRegDomain;   // (going away w/ multi-user support)
+	struct uDNS_AuthInfo *AuthInfoList;  // list of domains requiring authentication for updates.
+	uDNS_HostnameInfo *Hostnames;        // List of registered hostnames + hostname metadata
+    DNSQuestion      ReverseMap;         // Reverse-map query to find  static hostname for service target
+    mDNSBool         ReverseMapActive;   // Is above query active?
+    domainname       StaticHostname;     // Current answer to reverse-map query (above)
+	} uDNS_GlobalInfo;
 
 struct mDNS_struct
 	{
@@ -1437,9 +1894,11 @@ struct mDNS_struct
 
 	mDNS_PlatformSupport *p;			// Pointer to platform-specific data of indeterminite size
 	mDNSu32  KnownBugs;
-	mDNSBool CanReceiveUnicast;
+	mDNSBool CanReceiveUnicastOn5353;
 	mDNSBool AdvertiseLocalAddresses;
 	mStatus mDNSPlatformStatus;
+	mDNSIPPort UnicastPort4;
+	mDNSIPPort UnicastPort6;
 	mDNSCallback *MainCallback;
 	void         *MainContext;
 
@@ -1464,6 +1923,7 @@ struct mDNS_struct
 	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
+	mDNSs32  PktNum;					// Unique sequence number assigned to each received packet
 	mDNSBool SendDeregistrations;		// Set if we need to send deregistrations (immediately)
 	mDNSBool SendImmediateAnswers;		// Set if we need to send answers (immediately -- or as soon as SuppressSending clears)
 	mDNSBool SleepState;				// Set if we're sleeping (send no more packets)
@@ -1486,9 +1946,9 @@ struct mDNS_struct
 	// 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;
+	domainname  MulticastHostname;		// Fully Qualified "dot-local" 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 mDNSInterface_LocalOnly
@@ -1500,8 +1960,13 @@ struct mDNS_struct
 	mDNSu32 NumFailedProbes;
 	mDNSs32 SuppressProbes;
 
-    // unicast-specific data
-    uDNS_GlobalInfo uDNS_info;
+	// unicast-specific data
+	uDNS_GlobalInfo uDNS_info;
+
+	// Fixed storage, to avoid creating large objects on the stack
+	DNSMessage imsg;		// Incoming message received from wire
+	DNSMessage omsg;		// Outgoing message we're building
+	LargeCacheRecord rec;	// Resource Record extracted from received message
 	};
 
 // ***************************************************************************
@@ -1510,20 +1975,20 @@ struct mDNS_struct
 #endif
 
 extern const mDNSIPPort      zeroIPPort;
-extern const mDNSv4Addr      zeroIPAddr;
+extern const mDNSv4Addr      zerov4Addr;
 extern const mDNSv6Addr      zerov6Addr;
+extern const mDNSEthAddr     zeroEthAddr;
 extern const mDNSv4Addr      onesIPv4Addr;
 extern const mDNSv6Addr      onesIPv6Addr;
 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;
 extern const mDNSv4Addr      AllDNSAdminGroup;
-extern const mDNSv4Addr      AllDNSLinkGroup;
+extern const mDNSv4Addr      AllDNSLinkGroupv4;
 extern const mDNSv6Addr      AllDNSLinkGroupv6;
 extern const mDNSAddr        AllDNSLinkGroup_v4;
 extern const mDNSAddr        AllDNSLinkGroup_v6;
@@ -1534,6 +1999,8 @@ extern const mDNSOpaque16 ResponseFlags;
 extern const mDNSOpaque16 UpdateReqFlags;
 extern const mDNSOpaque16 UpdateRespFlags;
 
+#define localdomain (*(const domainname *)"\x5local")
+
 // ***************************************************************************
 #if 0
 #pragma mark - Inline functions
@@ -1561,6 +2028,8 @@ extern mDNSOpaque32 mDNSOpaque32fromIntVal(mDNSu32 v);
 
 #ifdef mDNSinline
 
+mDNSinline mDNSs32 NonZeroTime(mDNSs32 t) { if (t) return(t); else return(1); }
+
 mDNSinline mDNSu16 mDNSVal16(mDNSOpaque16 x) { return((mDNSu16)((mDNSu16)x.b[0] <<  8 | (mDNSu16)x.b[1])); }
 mDNSinline mDNSu32 mDNSVal32(mDNSOpaque32 x) { return((mDNSu32)((mDNSu32)x.b[0] << 24 | (mDNSu32)x.b[1] << 16 | (mDNSu32)x.b[2] << 8 | (mDNSu32)x.b[3])); }
 
@@ -1619,6 +2088,8 @@ mDNSinline mDNSOpaque32 mDNSOpaque32fromIntVal(mDNSu32 v)
 // 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).
+// Following deregistration, the RecordCallback will be called with result mStatus_MemFree to signal that it is safe to deallocate
+// the record's storage (memory must be freed asynchronously to allow for goodbye packets and dynamic update deregistration).
 //
 // 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
@@ -1650,14 +2121,14 @@ 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);
+								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);
+extern mDNSs32 mDNS_TimeNow(const mDNS *const m);
 
 // ***************************************************************************
 #if 0
@@ -1665,7 +2136,6 @@ extern mStatus mDNS_ReconfirmByValue(mDNS *const m, ResourceRecord *const rr);
 #endif
 
 extern mDNSs32  mDNSPlatformOneSecond;
-extern mDNSs32  mDNSPlatformTimeNow(void);
 
 // ***************************************************************************
 #if 0
@@ -1680,6 +2150,11 @@ extern mDNSs32  mDNSPlatformTimeNow(void);
 // 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_AddRecordToService adds an additional record to a Service Record Set.  This record may be deregistered
+// via mDNS_RemoveRecordFromService, or by deregistering the service.  mDNS_RemoveRecordFromService is passed a
+// callback to free the memory associated with the extra RR when it is safe to do so.  The ExtraResourceRecord
+// object  can be found in the record's context pointer.
+	
 // mDNS_GetBrowseDomains is a special case of the mDNS_StartQuery call, where the resulting answers
 // are a list of PTR records indicating (in the rdata) domains that are recommended for browsing.
 // After getting the list of domains to browse, call mDNS_StopQuery to end the search.
@@ -1698,7 +2173,7 @@ extern mStatus mDNS_RegisterService  (mDNS *const m, ServiceRecordSet *sr,
                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_RemoveRecordFromService(mDNS *const m, ServiceRecordSet *sr, ExtraResourceRecord *extra, mDNSRecordCallback MemFreeCallback, void *Context);
 extern mStatus mDNS_RenameAndReregisterService(mDNS *const m, ServiceRecordSet *const sr, const domainlabel *newname);
 extern mStatus mDNS_DeregisterService(mDNS *const m, ServiceRecordSet *sr);
 
@@ -1710,7 +2185,7 @@ extern mStatus mDNS_RegisterNoSuchService(mDNS *const m, AuthRecord *const rr,
 
 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);
+               const mDNSInterfaceID InterfaceID, mDNSBool ForceMCast, mDNSQuestionCallback *Callback, void *Context);
 #define        mDNS_StopBrowse mDNS_StopQuery
 
 extern mStatus mDNS_StartResolveService(mDNS *const m, ServiceInfoQuery *query, ServiceInfo *info, mDNSServiceInfoQueryCallback *Callback, void *Context);
@@ -1721,7 +2196,8 @@ typedef enum
 	mDNS_DomainTypeBrowse              = 0,
 	mDNS_DomainTypeBrowseDefault       = 1,
 	mDNS_DomainTypeRegistration        = 2,
-	mDNS_DomainTypeRegistrationDefault = 3
+	mDNS_DomainTypeRegistrationDefault = 3,
+	mDNS_DomainTypeBrowseLegacy        = 4,	
 	} mDNS_DomainType;
 
 extern mStatus mDNS_GetDomains(mDNS *const m, DNSQuestion *const question, mDNS_DomainType DomainType, const domainname *dom,
@@ -1805,17 +2281,51 @@ extern mDNSBool DeconstructServiceName(const domainname *const fqdn, domainlabel
 
 // ***************************************************************************
 #if 0
-#pragma mark - Other utility functions
+#pragma mark - Other utility functions and macros
 #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 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 char *GetRRDisplayString_rdb(const ResourceRecord *rr, RDataBody *rd, char *buffer);
+#define RRDisplayString(m, rr) GetRRDisplayString_rdb(rr, &(rr)->rdata->u, (m)->MsgBuffer)
+#define ARDisplayString(m, rr) GetRRDisplayString_rdb(&(rr)->resrec, &(rr)->resrec.rdata->u, (m)->MsgBuffer)
+#define CRDisplayString(m, rr) GetRRDisplayString_rdb(&(rr)->resrec, &(rr)->resrec.rdata->u, (m)->MsgBuffer)
 extern mDNSBool mDNSSameAddress(const mDNSAddr *ip1, const mDNSAddr *ip2);
 extern void IncrementLabelSuffix(domainlabel *name, mDNSBool RichText);
+extern mDNSBool IsPrivateV4Addr(mDNSAddr *addr);  // returns true for RFC1918 private addresses
+
+#define mDNSSameIPv4Address(A,B) ((A).NotAnInteger == (B).NotAnInteger)
+#define mDNSSameIPv6Address(A,B) ((A).l[0] == (B).l[0] && (A).l[1] == (B).l[1] && (A).l[2] == (B).l[2] && (A).l[3] == (B).l[3])
+#define mDNSSameEthAddress(A,B)  ((A)->w[0] == (B)->w[0] && (A)->w[1] == (B)->w[1] && (A)->w[2] == (B)->w[2])
+
+#define mDNSIPv4AddressIsZero(A) mDNSSameIPv4Address((A), zerov4Addr)
+#define mDNSIPv6AddressIsZero(A) mDNSSameIPv6Address((A), zerov6Addr)
+
+#define mDNSIPv4AddressIsOnes(A) mDNSSameIPv4Address((A), onesIPv4Addr)
+#define mDNSIPv6AddressIsOnes(A) mDNSSameIPv6Address((A), onesIPv6Addr)
+
+#define mDNSAddressIsAllDNSLinkGroup(X) (                                                     \
+	((X)->type == mDNSAddrType_IPv4 && mDNSSameIPv4Address((X)->ip.v4, AllDNSLinkGroupv4)) || \
+	((X)->type == mDNSAddrType_IPv6 && mDNSSameIPv6Address((X)->ip.v6, AllDNSLinkGroupv6))    )
+
+#define mDNSAddressIsZero(X) (                                                \
+	((X)->type == mDNSAddrType_IPv4 && mDNSIPv4AddressIsZero((X)->ip.v4))  || \
+	((X)->type == mDNSAddrType_IPv6 && mDNSIPv6AddressIsZero((X)->ip.v6))     )
+
+#define mDNSAddressIsValidNonZero(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 0
@@ -1830,47 +2340,66 @@ extern void IncrementLabelSuffix(domainlabel *name, mDNSBool RichText);
 // padded keys for inned/outer hash rounds
 typedef struct
 	{
-    mDNSu8 ipad[HMAC_LEN];
-    mDNSu8 opad[HMAC_LEN];
-   	} HMAC_Key;
+	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;
+	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)
+// Unicast DNS and Dynamic Update specific Client Calls
+//
+// mDNS_SetSecretForZone tells the core to authenticate (via TSIG with an HMAC_MD5 hash of the shared secret)
 // 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);
-
+// Calling this routine multiple times for a zone replaces previously entered values.  Call with a NULL key
+// to dissable authentication for the zone.
+
+extern mStatus mDNS_SetSecretForZone(mDNS *m, const domainname *zone, const domainname *key, const mDNSu8 *sharedSecret, mDNSu32 ssLen, mDNSBool base64);
+
+// Hostname/Unicast Interface Configuration
+
+// All hostnames advertised point to a single IP address, set via SetPrimaryInterfaceInfo.  Invoking this routine
+// updates all existing hostnames to point to the new address.
+	
+// A hostname is added via AddDynDNSHostName, which points to the primary interface's IP address.
+
+// The status callback is invoked to convey success or failure codes - the callback should not modify the AuthRecord or free memory.
+// Added hostnames may be removed (deregistered) via mDNS_RemoveDynDNSHostName.
+
+// Host domains added prior to specification of the primary interface address and computer name will be deferred until
+// these values are initialized.
+
+// When routable V4 interfaces are added or removed, mDNS_UpdateLLQs should be called to re-estabish LLQs in case the
+// destination address for events (i.e. the route) has changed.  For performance reasons, the caller is responsible for 
+// batching changes, e.g.  calling the routine only once if multiple interfaces are simultanously removed or added.
+
+// DNS servers used to resolve unicast queries are specified by mDNS_AddDNSServer, and may later be removed via mDNS_DeleteDNSServers.
+// For "split" DNS configurations, in which queries for different domains are sent to different servers (e.g. VPN and external),
+// a domain may be associated with a DNS server.  For standard configurations, specify the root label (".") or NULL.
+	
+extern void mDNS_AddDynDNSHostName(mDNS *m, const domainname *fqdn, mDNSRecordCallback *StatusCallback, const void *StatusContext);
+extern void mDNS_RemoveDynDNSHostName(mDNS *m, const domainname *fqdn);
+extern void mDNS_SetPrimaryInterfaceInfo(mDNS *m, const mDNSAddr *addr, const mDNSAddr *router);
+extern void mDNS_UpdateLLQs(mDNS *m);
+extern void mDNS_AddDNSServer(mDNS *const m, const mDNSAddr *dnsAddr, const domainname *domain);
+extern void mDNS_DeleteDNSServers(mDNS *const m);
+	
 // 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);
+extern void DNSDigest_ConstructHMACKey(uDNS_AuthInfo *info, const 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
@@ -1878,9 +2407,6 @@ extern void DNSDigest_ConstructHMACKey(uDNS_AuthInfo *info, mDNSu8 *key, mDNSu32
 // 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
@@ -1897,15 +2423,24 @@ extern mStatus DNSDigest_MD5(const DNSMessage *msg, mDNSu32 msglen, mDNSOpaque16
 // 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 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
 // 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).
+//
+// USE CAUTION WHEN CALLING mDNSPlatformRawTime: The m->timenow_adjust correction factor needs to be added
+// Generally speaking:
+// Code that's protected by the main mDNS lock should just use the m->timenow value
+// Code outside the main mDNS lock should use mDNS_TimeNow(m) to get properly adjusted time
+//
+// mDNSPlatformUTC returns the time, in seconds, since Jan 1st 1970 UTC and is required for generating TSIG records
+
 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,
+extern mStatus  mDNSPlatformSendUDP(const mDNS *const m, const void *const msg, const mDNSu8 *const end,
 mDNSInterfaceID InterfaceID, const mDNSAddr *dst, mDNSIPPort dstport);
 
 extern void     mDNSPlatformLock        (const mDNS *const m);
@@ -1918,7 +2453,10 @@ extern mDNSBool mDNSPlatformMemSame     (const void *src, const void *dst, mDNSu
 extern void     mDNSPlatformMemZero     (                       void *dst, mDNSu32 len);
 extern void *   mDNSPlatformMemAllocate (mDNSu32 len);
 extern void     mDNSPlatformMemFree     (void *mem);
-extern mStatus  mDNSPlatformTimeInit    (mDNSs32 *timenow);
+extern mDNSu32  mDNSPlatformRandomSeed  (void);
+extern mStatus  mDNSPlatformTimeInit    (void);
+extern mDNSs32  mDNSPlatformRawTime     (void);
+extern mDNSs32  mDNSPlatformUTC         (void);
 
 // Platform support modules should provide the following functions to map between opaque interface IDs
 // and interface indexes in order to support the DNS-SD API. If your target platform does not support
@@ -1935,9 +2473,9 @@ extern mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(const mDNS *const m, mD
 // 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
+// asynchronously fails, the TCPConnectionCallback should be invoked as usual, with the error being
 // returned in subsequent calls to PlatformReadTCP or PlatformWriteTCP.  (This allows for platforms
-// with limited asyncronous error detection capabilities.)  PlatformReadTCP and PlatformWriteTCP must
+// with limited asynchronous error detection capabilities.)  PlatformReadTCP and PlatformWriteTCP must
 // return the number of bytes read/written, 0 if the call would block, and -1 if an error.
 // 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.
@@ -1957,9 +2495,9 @@ extern int mDNSPlatformWriteTCP(int sd, const char *msg, int len);
 
 typedef struct DNameListElem
 	{
-    domainname name;
-    struct DNameListElem *next;
-    } DNameListElem;
+	domainname name;
+	struct DNameListElem *next;
+	} DNameListElem;
 
 extern DNameListElem *mDNSPlatformGetSearchDomainList(void);
 extern DNameListElem *mDNSPlatformGetRegDomainList(void);
@@ -1968,16 +2506,22 @@ extern DNameListElem *mDNSPlatformGetRegDomainList(void);
 extern DNameListElem *mDNS_CopyDNameList(const DNameListElem *orig);
 extern void mDNS_FreeDNameList(DNameListElem *list);
 
+#ifdef _LEGACY_NAT_TRAVERSAL_
+// Support for legacy NAT traversal protocols, implemented by the platform layer and callable by the core.
+
+#define DYN_PORT_MIN 49152 // ephemeral port range
+#define DYN_PORT_MAX 65535
+#define LEGACY_NATMAP_MAX_TRIES 4 // if our desired mapping is taken, how many times we try mapping to a random port
+
+extern mStatus LNT_GetPublicIP(mDNSOpaque32 *ip);
+extern mStatus LNT_MapPort(mDNSIPPort priv, mDNSIPPort pub, mDNSBool tcp);
+extern mStatus LNT_UnmapPort(mDNSIPPort PubPort, mDNSBool tcp);
+#endif // _LEGACY_NAT_TRAVERSAL_
+
 // 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_SetFQDN() is called once on startup (typically from mDNSPlatformInit())
+// and then again on each subsequent change of the 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.
@@ -1989,9 +2533,9 @@ extern void mDNS_FreeDNameList(DNameListElem *list);
 // -- 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_RegisterInterface does not result in the registration of global hostnames via dynamic update -
+// see mDNS_SetPrimaryInterfaceInfo, mDNS_AddDynDNSHostName, etc. for this purpose.
+// Note that the set may be deallocated immediately after it is deregistered via mDNS_DeegisterInterface.
 //
 // 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
@@ -2009,18 +2553,13 @@ extern void mDNS_FreeDNameList(DNameListElem *list);
 // (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  void    mDNS_GenerateGlobalFQDN(mDNS *const m);
+extern void     mDNS_SetFQDN(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,
+extern void     mDNSCoreReceive(mDNS *const m, void *const msg, const mDNSu8 *const end,
 								const mDNSAddr *const srcaddr, const mDNSIPPort srcport,
-								const mDNSAddr *const dstaddr, const mDNSIPPort dstport, const mDNSInterfaceID InterfaceID, mDNSu8 ttl);
+								const mDNSAddr *const dstaddr, const mDNSIPPort dstport, const mDNSInterfaceID InterfaceID);
 extern void     mDNSCoreMachineSleep(mDNS *const m, mDNSBool wake);
 
 extern mDNSBool mDNSAddrIsDNSMulticast(const mDNSAddr *ip);
diff --git a/mDNSCore/uDNS.c b/mDNSCore/uDNS.c
index 90fd363..b2f8f3f 100755
--- a/mDNSCore/uDNS.c
+++ b/mDNSCore/uDNS.c
@@ -3,8 +3,6 @@
  *
  * @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
@@ -25,11 +23,327 @@
     Change History (most recent first):
 
 $Log: uDNS.c,v $
+Revision 1.151  2004/12/13 21:45:08  ksekar
+uDNS_DeregisterService should return NoError if called twice (to follow mDNS behavior expected by daemon layer)
+
+Revision 1.150  2004/12/13 20:42:41  ksekar
+Fixed LogMsg
+
+Revision 1.149  2004/12/13 18:10:03  ksekar
+Fixed LogMsg
+
+Revision 1.148  2004/12/13 01:18:04  ksekar
+Fixed unused variable warning for non-debug builds
+
+Revision 1.147  2004/12/12 23:51:42  ksekar
+<rdar://problem/3845683> Wide-area registrations should fallback to using DHCP hostname as target
+
+Revision 1.146  2004/12/12 23:30:40  ksekar
+<rdar://problem/3916987> Extra RRs not properly unlinked when parent service registration fails
+
+Revision 1.145  2004/12/12 22:56:29  ksekar
+<rdar://problem/3668508> Need to properly handle duplicate long-lived queries
+
+Revision 1.144  2004/12/11 20:55:29  ksekar
+<rdar://problem/3916479> Clean up registration state machines
+
+Revision 1.143  2004/12/10 01:21:27  cheshire
+<rdar://problem/3914089> Get rid of "LLQ Responses over TCP not currently supported" message
+
+Revision 1.142  2004/12/08 02:03:31  ksekar
+<rdar://problem/3865124> Looping on NAT Traversal error - check for
+NULL RR on error
+
+Revision 1.141  2004/12/07 01:39:28  cheshire
+Don't fail if the same server is responsible for more than one domain
+(e.g. the same DNS server may be responsible for both apple.com. and 17.in-addr.arpa.)
+
+Revision 1.140  2004/12/06 21:15:22  ksekar
+<rdar://problem/3884386> mDNSResponder crashed in CheckServiceRegistrations
+
+Revision 1.139  2004/12/06 19:08:03  cheshire
+Add clarifying comment -- CountLabels() excludes the final root label.
+
+Revision 1.138  2004/12/06 01:45:54  ksekar
+Correct wording in LogMsg
+
+Revision 1.137  2004/12/03 20:40:35  ksekar
+<rdar://problem/3865124> Looping on NAT Traversal error
+
+Revision 1.136  2004/12/03 07:20:50  ksekar
+<rdar://problem/3674208> Wide-Area: Registration of large TXT record fails
+
+Revision 1.135  2004/12/03 05:18:33  ksekar
+<rdar://problem/3810596> mDNSResponder needs to return more specific TSIG errors
+
+Revision 1.134  2004/12/02 20:03:49  ksekar
+<rdar://problem/3889647> Rendezvous still publishes wide-area domains even after switching to a local subnet
+
+Revision 1.133  2004/12/02 18:37:52  ksekar
+<rdar://problem/3758233> Registering with port number zero should not create a port mapping
+
+Revision 1.132  2004/12/01 20:57:19  ksekar
+<rdar://problem/3873921> Wide Area Rendezvous must be split-DNS aware
+
+Revision 1.131  2004/12/01 19:59:27  cheshire
+<rdar://problem/3882643> Crash in mDNSPlatformTCPConnect
+If a TCP response has the TC bit set, don't respond by just trying another TCP connection
+
+Revision 1.130  2004/12/01 02:43:23  cheshire
+Don't call StatusCallback if function pointer is null
+
+Revision 1.129  2004/11/30 23:51:06  cheshire
+Remove double semicolons
+
+Revision 1.128  2004/11/25 01:48:30  ksekar
+<rdar://problem/3878991> Logging into VPN does not trigger registration of address record
+
+Revision 1.127  2004/11/25 01:41:36  ksekar
+Changed unnecessary LogMsgs to debugfs
+
+Revision 1.126  2004/11/23 23:54:17  ksekar
+<rdar://problem/3890318> Wide-Area DNSServiceRegisterRecord() failures
+can crash mDNSResponder
+
+Revision 1.125  2004/11/23 04:16:48  cheshire
+Removed receiveMsg() routine.
+
+Revision 1.124  2004/11/23 04:06:51  cheshire
+Get rid of floating point constant -- in a small embedded device, bringing in all
+the floating point libraries just to halve an integer value is a bit too heavyweight.
+
+Revision 1.123  2004/11/22 17:16:20  ksekar
+<rdar://problem/3854298> Unicast services don't disappear when you disable all networking
+
+Revision 1.122  2004/11/19 18:00:34  ksekar
+<rdar://problem/3682646> Security: use random ID for one-shot unicast queries
+
+Revision 1.121  2004/11/19 04:24:08  ksekar
+<rdar://problem/3682609> Security: Enforce a "window" on one-shot wide-area queries
+
+Revision 1.120  2004/11/19 02:32:43  ksekar
+<rdar://problem/3682608> Wide-Area Rendezvous Security: Add LLQ-ID to events
+
+Revision 1.119  2004/11/18 23:21:24  ksekar
+<rdar://problem/3764544> LLQ Security: Need to verify src port/address for LLQ handshake
+
+Revision 1.118  2004/11/18 22:58:37  ksekar
+Removed old comment.
+
+Revision 1.117  2004/11/18 18:04:21  ksekar
+Restore checkins lost due to repository disk failure: Update comments & <rdar://problem/3880688>
+
+Revision 1.xxx  2004/11/17 06:17:57  cheshire
+Update comments to show correct SRV names: _dns-update._udp.<zone>. and _dns-llq._udp.<zone>.
+
+Revision 1.xxx  2004/11/17 00:45:28  ksekar
+<rdar://problem/3880688> Result of putUpdateLease not error-checked
+
+Revision 1.116  2004/11/16 01:41:47  ksekar
+Fixed typo in debugf
+
+Revision 1.115  2004/11/15 20:09:24  ksekar
+<rdar://problem/3719050> Wide Area support for Add/Remove record
+
+Revision 1.114  2004/11/13 02:32:47  ksekar
+<rdar://problem/3868216> LLQ mobility fragile on non-primary interface
+- fixed incorrect state comparison in CheckQueries
+
+Revision 1.113  2004/11/13 02:29:52  ksekar
+<rdar://problem/3878386> LLQ refreshes not reliable
+
+Revision 1.112  2004/11/11 20:45:14  ksekar
+<rdar://problem/3876052> self-conflict test not compatible with some BIND servers
+
+Revision 1.111  2004/11/11 20:14:55  ksekar
+<rdar://problem/3719574> Wide-Area registrations not deregistered on sleep
+
+Revision 1.110  2004/11/10 23:53:53  ksekar
+Remove no longer relevant comment
+
+Revision 1.109  2004/11/10 20:40:53  ksekar
+<rdar://problem/3868216> LLQ mobility fragile on non-primary interface
+
+Revision 1.108  2004/11/01 20:36:16  ksekar
+<rdar://problem/3802395> mDNSResponder should not receive Keychain Notifications
+
+Revision 1.107  2004/10/26 06:11:41  cheshire
+Add improved logging to aid in diagnosis of <rdar://problem/3842714> mDNSResponder crashed
+
+Revision 1.106  2004/10/26 03:52:03  cheshire
+Update checkin comments
+
+Revision 1.105  2004/10/26 01:15:06  cheshire
+Use "#if 0" instead of commenting out code
+
+Revision 1.104  2004/10/25 21:41:38  ksekar
+<rdar://problem/3852958> wide-area name conflicts can cause crash
+
+Revision 1.103  2004/10/25 19:30:52  ksekar
+<rdar://problem/3827956> Simplify dynamic host name structures
+
+Revision 1.102  2004/10/23 01:16:00  cheshire
+<rdar://problem/3851677> uDNS operations not always reliable on multi-homed hosts
+
+Revision 1.101  2004/10/22 20:52:07  ksekar
+<rdar://problem/3799260> Create NAT port mappings for Long Lived Queries
+
+Revision 1.100  2004/10/20 02:16:41  cheshire
+Improve "could not confirm existence of NS record" error message
+Don't call newRR->RecordCallback if it is NULL
+
+Revision 1.99  2004/10/19 21:33:18  cheshire
+<rdar://problem/3844991> Cannot resolve non-local registrations using the mach API
+Added flag 'kDNSServiceFlagsForceMulticast'. Passing through an interface id for a unicast name
+doesn't force multicast unless you set this flag to indicate explicitly that this is what you want
+
+Revision 1.98  2004/10/16 00:16:59  cheshire
+<rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check
+
+Revision 1.97  2004/10/15 23:00:18  ksekar
+<rdar://problem/3799242> Need to update LLQs on location changes
+
+Revision 1.96  2004/10/12 23:30:44  ksekar
+<rdar://problem/3609944> mDNSResponder needs to follow CNAME referrals
+
+Revision 1.95  2004/10/12 03:15:09  ksekar
+<rdar://problem/3835612> mDNS_StartQuery shouldn't return transient no-server error
+
+Revision 1.94  2004/10/12 02:49:20  ksekar
+<rdar://problem/3831228> Clean up LLQ sleep/wake, error handling
+
+Revision 1.93  2004/10/08 04:17:25  ksekar
+<rdar://problem/3831819> Don't use DNS extensions if the server does not advertise required SRV record
+
+Revision 1.92  2004/10/08 03:54:35  ksekar
+<rdar://problem/3831802> Refine unicast polling intervals
+
+Revision 1.91  2004/09/30 17:45:34  ksekar
+<rdar://problem/3821119> lots of log messages: mDNS_SetPrimaryIP: IP address unchanged
+
+Revision 1.90  2004/09/25 00:22:13  ksekar
+<rdar://problem/3815534> Crash in uDNS_RegisterService
+
+Revision 1.89  2004/09/24 19:14:53  cheshire
+Remove unused "extern mDNS mDNSStorage"
+
+Revision 1.88  2004/09/23 20:48:15  ksekar
+Clarify retransmission debugf messages.
+
+Revision 1.87  2004/09/22 00:41:59  cheshire
+Move tcp connection status codes into the legal range allocated for mDNS use
+
+Revision 1.86  2004/09/21 23:40:11  ksekar
+<rdar://problem/3810349> mDNSResponder to return errors on NAT traversal failure
+
+Revision 1.85  2004/09/21 22:38:27  ksekar
+<rdar://problem/3810286> PrimaryIP type uninitialized
+
+Revision 1.84  2004/09/18 00:30:39  cheshire
+<rdar://problem/3806643> Infinite loop in CheckServiceRegistrations
+
+Revision 1.83  2004/09/17 00:31:51  cheshire
+For consistency with ipv6, renamed rdata field 'ip' to 'ipv4'
+
+Revision 1.82  2004/09/16 21:36:36  cheshire
+<rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
+Changes to add necessary locking calls around unicast DNS operations
+
+Revision 1.81  2004/09/16 02:29:39  cheshire
+Moved mDNS_Lock/mDNS_Unlock to DNSCommon.c; Added necessary locking around
+uDNS_ReceiveMsg, uDNS_StartQuery, uDNS_UpdateRecord, uDNS_RegisterService
+
+Revision 1.80  2004/09/16 01:58:21  cheshire
+Fix compiler warnings
+
+Revision 1.79  2004/09/16 00:24:48  cheshire
+<rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
+
+Revision 1.78  2004/09/15 01:16:57  ksekar
+<rdar://problem/3797598> mDNSResponder printing too many messages
+
+Revision 1.77  2004/09/14 23:27:47  cheshire
+Fix compile errors
+
+Revision 1.76  2004/09/14 22:22:00  ksekar
+<rdar://problem/3800920> Legacy browses broken against some BIND versions
+
+Revision 1.75  2004/09/03 19:23:05  ksekar
+<rdar://problem/3788460>: Need retransmission mechanism for wide-area service registrations
+
+Revision 1.74  2004/09/02 17:49:04  ksekar
+<rdar://problem/3785135>: 8A246: mDNSResponder crash while logging on restart
+Fixed incorrect conversions, changed %s to %##s for all domain names.
+
+Revision 1.73  2004/09/02 01:39:40  cheshire
+For better readability, follow consistent convention that QR bit comes first, followed by OP bits
+
+Revision 1.72  2004/09/01 03:59:29  ksekar
+<rdar://problem/3783453>: Conditionally compile out uDNS code on Windows
+
+Revision 1.71  2004/08/27 17:51:53  ksekar
+Replaced unnecessary LogMsg with debugf.
+
+Revision 1.70  2004/08/25 00:37:27  ksekar
+<rdar://problem/3774635>: Cleanup DynDNS hostname registration code
+
+Revision 1.69  2004/08/18 17:35:41  ksekar
+<rdar://problem/3651443>: Feature #9586: Need support for Legacy NAT gateways
+
+Revision 1.68  2004/08/14 03:22:41  cheshire
+<rdar://problem/3762579> Dynamic DNS UI <-> mDNSResponder glue
+Add GetUserSpecifiedDDNSName() routine
+Convert ServiceRegDomain to domainname instead of C string
+Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs
+
+Revision 1.67  2004/08/13 23:46:58  cheshire
+"asyncronous" -> "asynchronous"
+
+Revision 1.66  2004/08/13 23:37:02  cheshire
+Now that we do both uDNS and mDNS, global replace "uDNS_info.hostname" with
+"uDNS_info.UnicastHostname" for clarity
+
+Revision 1.65  2004/08/13 23:12:32  cheshire
+Don't use strcpy() and strlen() on "struct domainname" objects;
+use AssignDomainName() and DomainNameLength() instead
+(A "struct domainname" is a collection of packed pascal strings, not a C string.)
+
+Revision 1.64  2004/08/13 23:01:05  cheshire
+Use platform-independent mDNSNULL instead of NULL
+
+Revision 1.63  2004/08/12 00:32:36  ksekar
+<rdar://problem/3759567>: LLQ Refreshes never terminate if unanswered
+
+Revision 1.62  2004/08/10 23:19:14  ksekar
+<rdar://problem/3722542>: DNS Extension daemon for Wide Area Rendezvous
+Moved routines/constants to allow extern access for garbage collection daemon
+
+Revision 1.61  2004/07/30 17:40:06  ksekar
+<rdar://problem/3739115>: TXT Record updates not available for wide-area services
+
+Revision 1.60  2004/07/29 19:40:05  ksekar
+NATPMP Support - minor fixes and cleanup
+
+Revision 1.59  2004/07/29 19:27:15  ksekar
+NATPMP Support - minor fixes and cleanup
+
+Revision 1.58  2004/07/27 07:35:38  shersche
+fix syntax error, variables declared in the middle of a block
+
+Revision 1.57  2004/07/26 22:49:30  ksekar
+<rdar://problem/3651409>: Feature #9516: Need support for NATPMP in client
+
+Revision 1.56  2004/07/26 19:14:44  ksekar
+<rdar://problem/3737814>: 8A210: mDNSResponder crashed in startLLQHandshakeCallback
+
+Revision 1.55  2004/07/15 19:01:33  ksekar
+<rdar://problem/3681029>: Check for incorrect time comparisons
+
 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
+<rdar://problem/3690436>: mDNSResponder crash while location cycling
 
 Revision 1.52  2004/06/17 01:13:11  ksekar
 <rdar://problem/3696616>: polling interval too short
@@ -162,9 +476,9 @@ 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
+Added an asynchronous state machine mechanism to uDNS.c, including
 calls to find the parent zone for a domain name.  Changes include code
-in repository previously dissabled via "#if 0 //incomplete".  Codepath
+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
@@ -220,20 +534,12 @@ Revision 1.1  2003/12/13 03:05:27  ksekar
 	#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
+// Asynchronous operation types
 
 typedef enum
 	{
@@ -269,28 +575,70 @@ typedef void AsyncOpCallback(mStatus err, mDNS *const m, void *info, const Async
 // 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 mStatus startGetZoneData(domainname *name, mDNS *m, mDNSBool findUpdatePort, mDNSBool findLLQPort, AsyncOpCallback callback, void *callbackInfo);
 mDNSlocal mDNSBool recvLLQResponse(mDNS *m, DNSMessage *msg, const mDNSu8 *end, const mDNSAddr *srcaddr, mDNSIPPort srcport, const mDNSInterfaceID InterfaceID);
 mDNSlocal void sendRecordRegistration(mDNS *const m, AuthRecord *rr);
 mDNSlocal void SendServiceRegistration(mDNS *m, ServiceRecordSet *srs);
+mDNSlocal void SendServiceDeregistration(mDNS *m, ServiceRecordSet *srs);
+mDNSlocal void serviceRegistrationCallback(mStatus err, mDNS *const m, void *srsPtr, const AsyncOpResult *result);
+mDNSlocal void SendRecordUpdate(mDNS *m, AuthRecord *rr, uDNS_RegInfo *info);
+mDNSlocal mStatus RegisterService(mDNS *m, ServiceRecordSet *srs);
+mDNSlocal void SuspendLLQs(mDNS *m, mDNSBool DeregisterActive);
+mDNSlocal void RestartQueries(mDNS *m);
+mDNSlocal void startLLQHandshake(mDNS *m, LLQ_Info *info, mDNSBool defer);
+mDNSlocal void llqResponseHndlr(mDNS * const m, DNSMessage *msg, const  mDNSu8 *end, DNSQuestion *question, void *context);
+
+// ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark - Temporary workaround
+#endif
+
+// 17 Places in this file directly call mDNSPlatformTimeNow(), which is unsafe
+// The platform function is now called mDNSPlatformRawTime(), and
+// mDNSPlatformTimeNow() is defined here as a temporary workaround.
+// This is a gross hack, and after this change has been tested for a while,
+// all these calls should be replaced by simple references to m->timenow
+
+mDNSlocal mDNSs32 mDNSPlatformTimeNow(mDNS *m)
+	{
+	if (m->mDNS_busy && m->timenow) return(m->timenow);
+	LogMsg("ERROR: uDNS.c code executing without holding main mDNS lock");
+
+	// To get a quick and easy stack trace to find out *how* this routine
+	// is being called without holding main mDNS lock, uncomment the line below:
+	// *(long*)0=0;
+	
+	return(mDNS_TimeNow(m));
+	}
 
 // ***************************************************************************
 #if COMPILER_LIKES_PRAGMA_MARK
 #pragma mark - General Utility Functions
 #endif
 
+// CountLabels() returns number of labels in name, excluding final root label
+// (e.g. for "apple.com." CountLabels returns 2.)
+mDNSlocal int CountLabels(const domainname *d)
+	{
+	int count = 0;
+	const mDNSu8 *ptr;
+	
+	for (ptr = d->c; *ptr; ptr = ptr + ptr[0] + 1) count++;
+	return count;
+	}
+
 mDNSlocal mDNSOpaque16 newMessageID(uDNS_GlobalInfo *u)
 	{
-	// if NextMessageID is 0 (ininitialized) or 0xffff (reserved for TCP packets) reset to 1
-	if (!u->NextMessageID || u->NextMessageID == (mDNSu16)~0) u->NextMessageID = 1;
+	static mDNSBool randomized = mDNSfalse;
+
+	if (!randomized) { u->NextMessageID = mDNSRandom(~0); randomized = mDNStrue; }
 	return mDNSOpaque16fromIntVal(u->NextMessageID++);
 	}
 
 // unlink an AuthRecord from a linked list
 mDNSlocal mStatus unlinkAR(AuthRecord **list, AuthRecord *const rr)
 	{
-	AuthRecord *rptr, *prev = NULL;
+	AuthRecord *rptr, *prev = mDNSNULL;
 	
 	for (rptr = *list; rptr; rptr = rptr->next)
 		{
@@ -298,7 +646,7 @@ mDNSlocal mStatus unlinkAR(AuthRecord **list, AuthRecord *const rr)
 			{
 			if (prev) prev->next = rptr->next;
 			else *list  = rptr->next;
-			rptr->next = NULL;
+			rptr->next = mDNSNULL;
 			return mStatus_NoError;
 			}
 		prev = rptr;
@@ -307,106 +655,154 @@ mDNSlocal mStatus unlinkAR(AuthRecord **list, AuthRecord *const rr)
 	return mStatus_UnknownErr;
 	}
 
+mDNSlocal void unlinkSRS(uDNS_GlobalInfo *u, ServiceRecordSet *srs)
+	{
+	ServiceRecordSet **p;
+	for (p = &u->ServiceRegistrations; *p; p = &(*p)->next)
+		if (*p == srs) { *p = srs->next; srs->next = mDNSNULL; return; }
+	LogMsg("ERROR: unlinkSRS - SRS not found in ServiceRegistrations list");
+	}
+
 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; }
+	if (uDNS_IsActiveQuery(q, u))
+		{ LogMsg("LinkActiveQuestion - %##s (%d) already in list!", q->qname.c, q->qtype); return; }
 	
 	q->next = u->ActiveQueries;
 	u->ActiveQueries = q;
 	}
 
+mDNSlocal void SwapRData(mDNS *m, AuthRecord *rr, mDNSBool DeallocOld)
+	{
+	RData *oldrd = rr->resrec.rdata;
+	mDNSu16 oldrdlen = rr->resrec.rdlength;
+
+	if (!rr->uDNS_info.UpdateRData) { LogMsg("SwapRData invoked with NULL UpdateRData field"); return; }
+	SetNewRData(&rr->resrec, rr->uDNS_info.UpdateRData, rr->uDNS_info.UpdateRDLen);
+	if (DeallocOld)
+		{
+		rr->uDNS_info.UpdateRData = mDNSNULL;							    // Clear the NewRData pointer ...
+		if (rr->uDNS_info.UpdateRDCallback) rr->uDNS_info.UpdateRDCallback(m, rr, oldrd);					// ... and let the client know
+		}
+	else
+		{
+		rr->uDNS_info.UpdateRData = oldrd;
+		rr->uDNS_info.UpdateRDLen = oldrdlen;
+		}
+	}
+
+// set retry timestamp for record with exponential backoff
+// (for service record sets, use RR_SRV as representative for time checks
+mDNSlocal void SetRecordRetry(mDNS *const m, AuthRecord *rr)
+	{
+	rr->LastAPTime = mDNSPlatformTimeNow(m);	
+	if (rr->ThisAPInterval < INIT_UCAST_POLL_INTERVAL)   { rr->ThisAPInterval = INIT_UCAST_POLL_INTERVAL; return; }
+	if (rr->ThisAPInterval*2 <= MAX_UCAST_POLL_INTERVAL) { rr->ThisAPInterval *= 2;                       return; }
+	if (rr->ThisAPInterval != MAX_UCAST_POLL_INTERVAL)   { rr->ThisAPInterval = MAX_UCAST_POLL_INTERVAL;          }
+	}
+	
 
 // ***************************************************************************
 #if COMPILER_LIKES_PRAGMA_MARK
 #pragma mark - Name Server List Management
 #endif
 
-mDNSexport void mDNS_RegisterDNS(mDNS *const m, mDNSv4Addr *const dnsAddr)
+mDNSexport void mDNS_AddDNSServer(mDNS *const m, const mDNSAddr *addr, const domainname *d)
     {
-    //!!!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;
-        }
+	DNSServer *s, **p = &u->Servers;
+	
+	mDNS_Lock(m);
+	if (!d) d = (domainname *)"";
 
-    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");  }
+	while (*p)		// Check if we already have this {server,domain} pair registered
+		{
+		if (mDNSSameAddress(&(*p)->addr, addr) && SameDomainName(&(*p)->domain, d))
+			LogMsg("Note: DNS Server %#a for domain %##s registered more than once", addr, d->c);
+		p=&(*p)->next;
+		}
 
+	// allocate, add to list
+	s = umalloc(sizeof(*s));
+	if (!s) { LogMsg("Error: mDNS_AddDNSServer - malloc"); goto end; }
+	s->addr = *addr;
+	AssignDomainName(s->domain, *d);
+	s->next = mDNSNULL;
+	*p = s;
+	
+	end:
+	mDNS_Unlock(m);
     }
 
-mDNSexport void mDNS_DeregisterDNS(mDNS *const m, mDNSv4Addr *const dnsAddr)
+mDNSexport void mDNS_DeleteDNSServers(mDNS *const m)
     {
-    uDNS_GlobalInfo *u = &m->uDNS_info;
-    int i;
+	DNSServer *s;
+	mDNS_Lock(m);
 
-    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");  }
-    }
+	s = m->uDNS_info.Servers;
+	m->uDNS_info.Servers = mDNSNULL;
+	while (s)
+		{
+		DNSServer *tmp = s;
+		s = s->next;
+		ufree(tmp);
+		}
 
-mDNSexport void mDNS_DeregisterDNSList(mDNS *const m)
-    {
-    ubzero(m->uDNS_info.Servers, 32 * sizeof(mDNSAddr));
+	mDNS_Unlock(m);
     }
 
-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
 
+mDNSlocal uDNS_AuthInfo *GetAuthInfoForZone(const uDNS_GlobalInfo *u, const domainname *zone)
+	{
+	uDNS_AuthInfo *ptr;
+	while (zone->c[0])
+		{
+		for (ptr = u->AuthInfoList; ptr; ptr = ptr->next)
+			if (SameDomainName(&ptr->zone, zone)) return(ptr);
+		zone = (const domainname *)(zone->c + 1 + zone->c[0]);
+		}
+	return mDNSNULL;
+	}	
+
+mDNSlocal void DeleteAuthInfoForZone(uDNS_GlobalInfo *u, const domainname *zone)
+	{
+	uDNS_AuthInfo *ptr, *prev = mDNSNULL;
+
+	for (ptr = u->AuthInfoList; ptr; ptr = ptr->next)
+		{
+		if (SameDomainName(&ptr->zone, zone))
+			{
+			if (prev) prev->next = ptr->next;
+			else u->AuthInfoList = ptr->next;
+			ufree(ptr);
+			return;
+			}
+		prev = ptr;
+		}
+	}
 
-mDNSexport mStatus mDNS_UpdateDomainRequiresAuthentication(mDNS *m, domainname *zone, domainname *key,
-    mDNSu8 *sharedSecret, mDNSu32 ssLen, mDNSBool base64)
+mDNSexport mStatus mDNS_SetSecretForZone(mDNS *m, const domainname *zone, const domainname *key, const mDNSu8 *sharedSecret, mDNSu32 ssLen, mDNSBool base64)
 	{
 	uDNS_AuthInfo *info;
 	mDNSu8 keybuf[1024];
 	mDNSs32 keylen;
+	uDNS_GlobalInfo *u = &m->uDNS_info;
+	mStatus status = mStatus_NoError;
+
+	mDNS_Lock(m);
+	
+	if (GetAuthInfoForZone(u, zone)) DeleteAuthInfoForZone(u, zone);
+	if (!key) goto exit;
 	
 	info = (uDNS_AuthInfo*)umalloc(sizeof(uDNS_AuthInfo) + ssLen);
-	if (!info) { LogMsg("ERROR: umalloc"); return mStatus_NoMemoryErr; }
+	if (!info) { LogMsg("ERROR: umalloc"); status = mStatus_NoMemoryErr; goto exit; }
    	ubzero(info, sizeof(uDNS_AuthInfo));
-	ustrcpy(info->zone.c, zone->c);
-	ustrcpy(info->keyname.c, key->c);
+	AssignDomainName(info->zone, *zone);
+	AssignDomainName(info->keyname, *key);
 
 	if (base64)
 		{
@@ -415,181 +811,836 @@ mDNSexport mStatus mDNS_UpdateDomainRequiresAuthentication(mDNS *m, domainname *
 			{
 			LogMsg("ERROR: mDNS_UpdateDomainRequiresAuthentication - could not convert shared secret from base64");
 			ufree(info);
-			return mStatus_UnknownErr;
+			status = mStatus_UnknownErr;
+			goto exit;
 			}		
 		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;
+exit:
+	mDNS_Unlock(m);
+	return status;
+	}
+	
+ // ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark - NAT Traversal
+#endif
+
+mDNSlocal mDNSBool MapServicePort(mDNS *m)
+	{
+	uDNS_HostnameInfo *i;
+
+	//!!!KRS this could be cached
+	for (i = m->uDNS_info.Hostnames; i; i= i->next)
+		if (i->ar->uDNS_info.NATinfo && i->ar->uDNS_info.NATinfo->state != NATState_Error) return mDNStrue;
+	
+	return mDNSfalse;
+	}
+
+mDNSlocal mDNSBool DomainContainsLabelString(const domainname *d, const char *str)
+	{
+	const domainlabel *l;
+	domainlabel buf;
+
+	if (!MakeDomainLabelFromLiteralString(&buf, str)) return mDNSfalse;
+
+	for (l = (const domainlabel *)d; l->c[0]; l = (const domainlabel *)(l->c + l->c[0]+1))
+		if (SameDomainLabel(l->c, buf.c)) return mDNStrue;
+	return mDNSfalse;
+	}
+
+// allocate struct, link into global list, initialize
+mDNSlocal NATTraversalInfo *AllocNATInfo(mDNS *const m, NATOp_t op, NATResponseHndlr callback)
+	{
+	uDNS_GlobalInfo *u = &m->uDNS_info;
+	NATTraversalInfo *info = umalloc(sizeof(NATTraversalInfo));
+	if (!info) { LogMsg("ERROR: malloc"); return mDNSNULL; }
+	ubzero(info, sizeof(NATTraversalInfo));
+	info->next = u->NATTraversals;
+	u->NATTraversals = info;
+	info->retry = mDNSPlatformTimeNow(m) + NATMAP_INIT_RETRY;
+	info->op = op;
+	info->state = NATState_Init;
+	info->ReceiveResponse = callback;
+	info->PublicPort.NotAnInteger = 0;
+	return info;
 	}
 
-mDNSexport void mDNS_ClearAuthenticationList(mDNS *m)
+// unlink from list, deallocate
+mDNSlocal mDNSBool FreeNATInfo(mDNS *m, NATTraversalInfo *n)
 	{
-	uDNS_AuthInfo *fptr, *ptr = m->uDNS_info.AuthInfoList;
+	NATTraversalInfo *ptr, *prev = mDNSNULL;
 	
+	if (n == m->uDNS_info.LLQNatInfo) m->uDNS_info.LLQNatInfo = mDNSNULL;
+	ptr = m->uDNS_info.NATTraversals;
 	while (ptr)
 		{
-		fptr = ptr;
+		if (ptr == n)
+			{
+			if (prev) prev->next = ptr->next;
+			else m->uDNS_info.NATTraversals = ptr->next;
+			ufree(n);
+			return mDNStrue;
+			}
+		prev = ptr;
 		ptr = ptr->next;
-		ufree(fptr);
 		}
-	m->uDNS_info.AuthInfoList = NULL;
+	LogMsg("FreeNATInfo: NATTraversalInfo not found in list");
+	return mDNSfalse;
 	}
 
-mDNSlocal uDNS_AuthInfo *GetAuthInfoForZone(const uDNS_GlobalInfo *u, const domainname *zone)
+mDNSlocal void SendNATMsg(NATTraversalInfo *info, mDNS *m)
 	{
-	uDNS_AuthInfo *ptr;
-	domainname *z;
-	mDNSu32 zoneLen, ptrZoneLen;
+	mStatus err;
+	mDNSAddr dst;
+	mDNSIPPort dstport;
+	uDNS_GlobalInfo *u = &m->uDNS_info;
 
-	zoneLen = ustrlen(zone->c);
-	for (ptr = u->AuthInfoList; ptr; ptr = ptr->next)
+	if (info->state != NATState_Request && info->state != NATState_Refresh)
+		{ LogMsg("SendNATMsg: Bad state %d", info->state); return; }
+
+	if (u->Router.ip.v4.NotAnInteger)
 		{
-		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;
-	}	
+		// send msg	if we have a router
+		dst.type = u->Router.type;
+		dst.ip.v4 = u->Router.ip.v4;
+		dstport = mDNSOpaque16fromIntVal(NATMAP_PORT);
+		err = mDNSPlatformSendUDP(m, info->request, info->request+info->requestlen, 0, &dst, dstport);
+		if (!err) (info->ntries++);  // don't increment attempt counter if the send failed
+		}
 	
+	// set retry
+	if (info->RetryInterval < NATMAP_INIT_RETRY) info->RetryInterval = NATMAP_INIT_RETRY;
+	else if (info->RetryInterval * 2 > NATMAP_MAX_RETRY) info->RetryInterval = NATMAP_MAX_RETRY;
+	else info->RetryInterval *= 2;
+	info->retry = mDNSPlatformTimeNow(m) + info->RetryInterval;
+	}
 
-
-
- // ***************************************************************************
-#if COMPILER_LIKES_PRAGMA_MARK
-#pragma mark - host name and interface management
-#endif
-
-
-mDNSlocal void hostnameCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
+mDNSlocal void ReceiveNATAddrResponse(NATTraversalInfo *n, mDNS *m, mDNSu8 *pkt, mDNSu16 len)
 	{
-	// note that the rr is already unlinked if result is non-zero
+	NATErr_t NatErr = NATErr_None;
+	mStatus err = mStatus_NoError;
+	AuthRecord *rr = mDNSNULL;
+	mDNSAddr addr; 
 
-	if (result == mStatus_MemFree) return;
-	if (result == mStatus_NameConflict && rr->resrec.RecordType == kDNSRecordTypeUnique)
+	if (n->state != NATState_Request)
 		{
-		// 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;
+		LogMsg("ReceiveNATAddrResponse: bad state %d", n->state);
+		err = mStatus_UnknownErr;
+		goto end;
 		}
-
-	if (rr->resrec.RecordType == kDNSRecordTypeKnownUnique)
-		// we've already tried to re-register.  reset RecordType before returning RR to client
+		
+	rr = n->reg.RecordRegistration;
+	if (!rr)
 		{
-		if (result == mStatus_NoSuchRecord)  // name is advertised for some other address
-			result = mStatus_NameConflict;
-		rr->resrec.RecordType = kDNSRecordTypeUnique;
+		LogMsg("ReceiveNATAddrResponse: registration cancelled");
+		err = mStatus_UnknownErr;
+		goto end;
 		}
-		
-	if (!result) rr->resrec.RecordType = kDNSRecordTypeVerified;
-	if (result)
-		((NetworkInterfaceInfo *)(rr->RecordContext))->uDNS_info.registered = mDNSfalse;
-	mDNS_HostNameCallback(m, rr, result);	
-	}
 
+	addr.type = mDNSAddrType_IPv4;
+	addr.ip.v4 = rr->resrec.rdata->u.ipv4;
 
-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;
+	if (!pkt) // timeout
+		{
+#ifdef _LEGACY_NAT_TRAVERSAL_
+		err = LNT_GetPublicIP(&addr.ip.v4);
+		if (err) goto end;
+		else n->state = NATState_Legacy;
+#else
+		debugf("ReceiveNATAddrResponse: timeout");
+		err = mStatus_NATTraversal;
+		goto end;
+#endif // _LEGACY_NAT_TRAVERSAL_
+		}
+	else
+		{
+		if (len < ADDR_REPLY_PKTLEN)
+			{
+			LogMsg("ReceiveNATAddrResponse: response too short (%d bytes)", len);
+			err = mStatus_NATTraversal;
+			goto end;
+			}
+		if (pkt[0] != NATMAP_VERS)
+			{
+			LogMsg("ReceiveNATAddrResponse: received  version %d (expect version %d)", pkt[0], NATMAP_VERS);
+			err = mStatus_NATTraversal;
+			goto end;
+			}
+		if (pkt[1] != (NATOp_AddrRequest | NATMAP_RESPONSE_MASK))
+			{
+			LogMsg("ReceiveNATAddrResponse: bad response code %d", pkt[1]);
+			err = mStatus_NATTraversal;
+			goto end;
+			}
+		NatErr = (NATErr_t)((NATErr_t)pkt[2] << 8 | (NATErr_t)pkt[3]);
+		if (NatErr) { LogMsg("ReceiveAddrResponse: received error %d", err); err = mStatus_NATTraversal; goto end; }
 		
-		// unlink the original
-		unlinkAR(&m->uDNS_info.RecordRegistrations, rr);
-		rr->uDNS_info.state = regState_Unregistered;
-		set->uDNS_info.registered = mDNSfalse;
-		uDNS_DeregisterRecord(m, copy);
+		addr.ip.v4.b[0] = pkt[4];
+		addr.ip.v4.b[1] = pkt[5];
+		addr.ip.v4.b[2] = pkt[6];
+		addr.ip.v4.b[3] = pkt[7];
+		n->state = NATState_Established;
+		}
+	
+	if (IsPrivateV4Addr(&addr))
+		{
+		LogMsg("ReceiveNATAddrResponse: Double NAT");
+		err = mStatus_DblNAT;
+		goto end;
+		}
+	
+	end:
+	if (err)
+		{
+		FreeNATInfo(m, n);
+		if (rr)
+			{
+			rr->uDNS_info.NATinfo = mDNSNULL;
+			rr->uDNS_info.state = regState_Unregistered;    // note that rr is not yet in global list
+			rr->RecordCallback(m, rr, mStatus_NATTraversal);
+			// note - unsafe to touch rr after callback
+			}
+		return;
+		}
+	else LogMsg("Received public IP address %d.%d.%d.%d from NAT.", addr.ip.v4.b[0], addr.ip.v4.b[1], addr.ip.v4.b[2], addr.ip.v4.b[3]);	
+	rr->resrec.rdata->u.ipv4 = addr.ip.v4;  // replace rdata w/ public address
+	uDNS_RegisterRecord(m, rr);
+	}
+
+
+mDNSlocal void StartGetPublicAddr(mDNS *m, uDNS_HostnameInfo *hInfo)
+	{
+	mDNSu8 *msg;
+	uDNS_GlobalInfo *u = &m->uDNS_info;
+	
+	NATTraversalInfo *info = AllocNATInfo(m, NATOp_AddrRequest, ReceiveNATAddrResponse);
+	if (!info) { uDNS_RegisterRecord(m, hInfo->ar); return; } 
+	hInfo->ar->uDNS_info.NATinfo = info;
+	info->reg.RecordRegistration = hInfo->ar;
+	info->state = NATState_Request;
+	
+    // format message
+	msg = info->request;
+	msg[0] = NATMAP_VERS;
+	msg[1] = NATOp_AddrRequest;
+	info->requestlen = ADDR_REQUEST_PKTLEN;	
+	
+	if (!u->Router.ip.v4.NotAnInteger)
+		{
+		debugf("No router.  Will retry NAT traversal in %ld ticks", NATMAP_INIT_RETRY);
+		return;
 		}
-	else debugf("uDNS_DeadvertiseInterface - interface not registered");
-	return;	
+   
+	SendNATMsg(info, m);
+	}
+
+
+mDNSlocal void RefreshNATMapping(NATTraversalInfo *n, mDNS *m)
+	{
+	n->state = NATState_Refresh;
+	n->RetryInterval = NATMAP_INIT_RETRY;
+	n->ntries = 0;
+	SendNATMsg(n, m);
 	}
 
-mDNSexport void uDNS_AdvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set) 
+mDNSlocal void LLQNatMapComplete(mDNS *m)
 	{
-	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;		
+	uDNS_GlobalInfo *u = &m->uDNS_info;
+	LLQ_Info *llqInfo;
+	NATTraversalInfo *n = u->LLQNatInfo;
 	
-	if (set->uDNS_info.registered && SameDomainName(&m->uDNS_info.hostname, &set->uDNS_info.regname))		
-	  return; // already registered
+	if (!n) { LogMsg("Error: LLQNatMapComplete called with NULL LLQNatInfo"); return; }
+	if (n->state != NATState_Established && n->state != NATState_Legacy && n->state != NATState_Error)
+		{ LogMsg("LLQNatMapComplete - bad nat state %d", n->state); return; }
+
+	u->CurrentQuery = u->ActiveQueries;
+	while (u->CurrentQuery)
+		{
+		DNSQuestion *q = u->CurrentQuery;
+		u->CurrentQuery = u->CurrentQuery->next;
+		llqInfo = q->uDNS_info.llq;
+		if (q->LongLived && llqInfo->state == LLQ_NatMapWait)
+			{
+			if (n->state == NATState_Error)
+				{
+				llqInfo->NATMap = mDNSfalse;
+				llqInfo->question->uDNS_info.responseCallback = llqResponseHndlr;
+				llqInfo->state = LLQ_Poll;
+				llqInfo->question->LastQTime = mDNSPlatformTimeNow(m) - (2 * INIT_UCAST_POLL_INTERVAL);  // trigger immediate poll
+				llqInfo->question->ThisQInterval = INIT_UCAST_POLL_INTERVAL;
+				}
+			else { llqInfo->state = LLQ_GetZoneInfo; startLLQHandshake(m, llqInfo, mDNSfalse); }	
+			}
+		}
+	}
 
-	if (!m->uDNS_info.hostname.c[0])
+mDNSlocal void ReceivePortMapReply(NATTraversalInfo *n, mDNS *m, mDNSu8 *pkt, mDNSu16 len)
+	{
+	NATErr_t err;
+	ServiceRecordSet *srs;
+	mDNSIPPort priv, pktpriv, pub;
+	mDNSu32 lease;
+	mDNSBool deletion;
+	
+	if (n->state != NATState_Request && n->state != NATState_Refresh)
+		{ LogMsg("ReceivePortMapReply: bad state %d", n->state);  return; }
+
+	deletion = !(n->request[8] |  n->request[9] | n->request[10] | n->request[11]);  // zero lease
+	if (deletion) { n->state = NATState_Deleted; return; }
+	// note that we explicitly ignore timeouts here
+	// we keep the context struct around so that the SendServiceDeregistration code can reference
+	// it to determine the public port to delete in the SRV record.
+	
+	srs = n->reg.ServiceRegistration;
+	if (!srs && n != m->uDNS_info.LLQNatInfo)
 		{
-		// no hostname available
-		set->uDNS_info.registered = mDNSfalse;
+		debugf("ReceivePortMapReply: registration cancelled");
+		FreeNATInfo(m, n);
 		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); 
+	
+	priv = srs ? srs->RR_SRV.resrec.rdata->u.srv.port : m->UnicastPort4;
+	
+	if (!pkt) // timeout
+		{
+#ifdef _LEGACY_NAT_TRAVERSAL_
+		int ntries = 0;
+		mStatus err;
+		mDNSBool tcp = (srs && DomainContainsLabelString(&srs->RR_PTR.resrec.name, "_tcp"));
+	   
+		pub = priv; // initially request priv == pub
+		while (1)
+			{
+			err = LNT_MapPort(priv, pub, tcp);
+			if (!err)
+				{
+				n->PublicPort = pub;
+				n->state = NATState_Legacy;
+				goto end;
+				}
+			else if (err != mStatus_AlreadyRegistered || ++ntries > LEGACY_NATMAP_MAX_TRIES)
+				{
+				n->state = NATState_Error;
+				goto end;
+				}
+			else
+				{
+				// the mapping we want is taken - try a random port
+				mDNSu16 RandPort = mDNSRandom(DYN_PORT_MAX - DYN_PORT_MIN) + DYN_PORT_MIN;
+				pub = mDNSOpaque16fromIntVal(RandPort);
+				}
+			}
+#else
+		goto end;
+#endif // _LEGACY_NAT_TRAVERSAL_
+		}
+
+	if (len < PORTMAP_PKTLEN) { LogMsg("ReceivePortMapReply: response too short (%d bytes)", len); goto end; }
+	if (pkt[0] != NATMAP_VERS) { LogMsg("ReceivePortMapReply: received  version %d (expect version %d)", pkt[0], NATMAP_VERS);  goto end; }
+	if (pkt[1] != (n->op | NATMAP_RESPONSE_MASK)) { LogMsg("ReceivePortMapReply: bad response code %d", pkt[1]); goto end; }
+	err = (NATErr_t)((NATErr_t)pkt[2] << 8 | (NATErr_t)pkt[3]);
+	if (err) { LogMsg("ReceivePortMapReply: received error %d", err);  goto end; }
+
+	pktpriv.b[0] = pkt[4];
+	pktpriv.b[1] = pkt[5];
+	pub.b[0]  = pkt[6];
+	pub.b[1]  = pkt[7];
+
+	lease = (mDNSu32) ((mDNSu32)pkt[8] << 24 | (mDNSu32)pkt[9] << 16 | (mDNSu32)pkt[10] << 8 | pkt[11]);
+	if (lease > 0x70000000UL / mDNSPlatformOneSecond)
+		lease = 0x70000000UL / mDNSPlatformOneSecond;
+
+	if (priv.NotAnInteger != pktpriv.NotAnInteger)
+		{ LogMsg("ReceivePortMapReply: reply private port does not match requested private port");  goto end; }
+	
+	if (n->state == NATState_Refresh && pub.NotAnInteger != n->PublicPort.NotAnInteger) 					
+		LogMsg("ReceivePortMapReply: NAT refresh changed public port from %d to %d", mDNSVal16(n->PublicPort), mDNSVal16(pub));
+      	// !!!KRS we need to update the SRV here!
+	n->PublicPort = pub;
+
+	n->retry = mDNSPlatformTimeNow(m) + ((mDNSs32)lease * mDNSPlatformOneSecond/2);  // retry half way to expiration
+	
+	if (n->state == NATState_Refresh) { n->state = NATState_Established; return; }
+	n->state = NATState_Established;
+
+	end:
+	if (n->state != NATState_Established && n->state != NATState_Legacy)
+		{
+		LogMsg("NAT Port Mapping: timeout");
+		n->state = NATState_Error;
+		if (!srs) { LLQNatMapComplete(m); return; }
+		FreeNATInfo(m, n);
+		srs->uDNS_info.NATinfo = mDNSNULL;
+		unlinkSRS(&m->uDNS_info, srs);
+		srs->uDNS_info.state = regState_Unregistered;
+		srs->ServiceCallback(m, srs, mStatus_NATTraversal);
+		return;  // note - unsafe to touch srs here
+		}
+
+	LogMsg("Mapped private port %d to public port %d", mDNSVal16(priv), mDNSVal16(n->PublicPort));
+	if (!srs) { LLQNatMapComplete(m); return; }
+	srs->uDNS_info.state = regState_FetchingZoneData;
+	startGetZoneData(&srs->RR_SRV.resrec.name, m, mDNStrue, mDNSfalse, serviceRegistrationCallback, srs);
 	}
 
+mDNSlocal void FormatPortMaprequest(NATTraversalInfo *info, mDNSIPPort port)
+	{
+	mDNSu8 *msg = info->request;
+	mDNSOpaque32 lease = mDNSOpaque32fromIntVal(NATMAP_DEFAULT_LEASE);
+	
+	msg[0] = NATMAP_VERS;
+	msg[1] = info->op;
+	msg[2] = 0; // reserved
+	msg[3] = 0; // reserved
+	msg[4] = port.b[0];  // private port
+	msg[5] = port.b[1];
+	msg[6] = port.b[0];  // requested pub. port
+	msg[7] = port.b[1];
+	
+	msg[8]  = lease.b[0];
+	msg[9]  = lease.b[1];
+	msg[10] = lease.b[2];
+	msg[11] = lease.b[3];
+	}
 
-// ***************************************************************************
+mDNSlocal void SendInitialPMapReq(mDNS *m, NATTraversalInfo *info)
+	{
+	if (!m->uDNS_info.Router.ip.v4.NotAnInteger)
+		{
+		debugf("No router.  Will retry NAT traversal in %ld seconds", NATMAP_INIT_RETRY);
+		info->retry = mDNSPlatformTimeNow(m) + NATMAP_INIT_RETRY;
+		info->RetryInterval = NATMAP_INIT_RETRY;
+		return;
+		}
+    SendNATMsg(info, m);
+	return;
+	}
+
+mDNSlocal void StartNATPortMap(mDNS *m, ServiceRecordSet *srs)
+	{
+	NATOp_t op;
+	NATTraversalInfo *info;
+
+   	if (DomainContainsLabelString(&srs->RR_PTR.resrec.name, "_tcp")) op = NATOp_MapTCP;
+	else if (DomainContainsLabelString(&srs->RR_PTR.resrec.name, "_udp")) op = NATOp_MapUDP;
+	else { LogMsg("StartNATPortMap: could not determine transport protocol of service %##s", srs->RR_SRV.resrec.name.c); goto error; }
+
+	info = AllocNATInfo(m, op, ReceivePortMapReply);
+	srs->uDNS_info.NATinfo = info;
+	info->reg.ServiceRegistration = srs;
+	info->state = NATState_Request;
+	info->requestlen = PORTMAP_PKTLEN;
+	
+	FormatPortMaprequest(info, srs->RR_SRV.resrec.rdata->u.srv.port);
+	SendInitialPMapReq(m, info);
+	return;
+	
+	error:
+	startGetZoneData(&srs->RR_SRV.resrec.name, m, mDNStrue, mDNSfalse, serviceRegistrationCallback, srs);
+	}
+
+mDNSlocal void DeleteNATPortMapping(mDNS *m, NATTraversalInfo *nat, ServiceRecordSet *srs)
+	{
+	if (nat->state == NATState_Established)  // let other edge-case states expire for simplicity
+		{
+		// zero lease
+		nat->request[8]  = 0;
+		nat->request[9]  = 0;
+		nat->request[10] = 0 ;
+		nat->request[11] = 0;
+		nat->state = NATState_Request;
+		SendNATMsg(nat, m); 
+		}
+#ifdef _LEGACY_NAT_TRAVERSAL_
+	else if (nat->state == NATState_Legacy)
+		{
+		mStatus err = mStatus_NoError;
+		mDNSBool tcp = srs ? DomainContainsLabelString(&srs->RR_PTR.resrec.name, "_tcp") : mDNSfalse;
+		err = LNT_UnmapPort(nat->PublicPort, tcp);
+		if (err) LogMsg("Legacy NAT Traversal - unmap request failed with error %ld", err);
+		}
+#else
+	(void)srs; // unused
+#endif // _LEGACY_NAT_TRAVERSAL_
+	}
+
+mDNSlocal void StartLLQNatMap(mDNS *m)
+	{
+	NATTraversalInfo *info = AllocNATInfo(m, NATOp_MapUDP, ReceivePortMapReply);
+	uDNS_GlobalInfo *u = &m->uDNS_info;
+	
+	u->LLQNatInfo = info;
+
+	info->reg.RecordRegistration = mDNSNULL;	
+	info->reg.ServiceRegistration = mDNSNULL;
+    info->state = NATState_Request;
+	info->requestlen = PORTMAP_PKTLEN;
+	FormatPortMaprequest(info, m->UnicastPort4);
+    SendInitialPMapReq(m, info);
+	return;
+	}
+
+// if  LLQ NAT context unreferenced, delete the mapping
+mDNSlocal void CheckForUnreferencedLLQMapping(mDNS *m)
+	{
+	NATTraversalInfo *nat = m->uDNS_info.LLQNatInfo;
+	DNSQuestion *q;
+	
+	if (!nat) return;
+
+	for (q = m->uDNS_info.ActiveQueries; q; q = q->next)
+		if (q->LongLived && q->uDNS_info.llq->NATMap) return;
+
+	//to avoid race condition if we need to recreate before this finishes, we do one-shot deregistration
+	if (nat->state == NATState_Established || nat->state == NATState_Legacy)
+		DeleteNATPortMapping(m, nat, mDNSNULL); // for simplicity we allow other states to expire
+	FreeNATInfo(m, nat); // note: this clears the global LLQNatInfo pointer
+	}
+
+ // ***************************************************************************
 #if COMPILER_LIKES_PRAGMA_MARK
-#pragma mark - Incoming Message Processing
+#pragma mark - host name and interface management
 #endif
 
-mDNSlocal mDNSBool sameResourceRecord(ResourceRecord *r1, ResourceRecord *r2)
+// if we ever want to refine support for multiple hostnames, we can add logic matching service names to a particular hostname
+// for now, we grab the first registered DynDNS name, if any, or a static name we learned via a reverse-map query
+mDNSlocal mDNSBool GetServiceTarget(uDNS_GlobalInfo *u, AuthRecord *srv, domainname *dst)
+	{
+	uDNS_HostnameInfo *hi = u->Hostnames;
+	(void)srv;  // unused
+
+	dst->c[0] = 0;
+	while (hi)
+		{
+		if (hi->ar->uDNS_info.state == regState_Registered || hi->ar->uDNS_info.state == regState_Refresh)
+			{ AssignDomainName(*dst, hi->ar->resrec.name); return mDNStrue; }
+		hi = hi->next;
+		}
+
+	if (u->StaticHostname.c[0]) { AssignDomainName(*dst, u->StaticHostname); return mDNStrue; }
+	return mDNSfalse;
+	}
+
+mDNSlocal void UpdateSRV(mDNS *m, ServiceRecordSet *srs)
+	{	
+	uDNS_GlobalInfo *u = &m->uDNS_info;
+	ExtraResourceRecord *e;
+	domainname newtarget;
+	domainname *curtarget = &srs->RR_SRV.resrec.rdata->u.srv.target;
+	mDNSBool havetarget = GetServiceTarget(u, &srs->RR_SRV, &newtarget);
+	
+	if ((!havetarget && srs->uDNS_info.state == regState_NoTarget) || (havetarget && SameDomainName(curtarget, &newtarget))) return;  // target unchanged
+	
+	switch(srs->uDNS_info.state)
+		{
+		case regState_FetchingZoneData:
+		case regState_Cancelled:
+		case regState_DeregPending:
+		case regState_DeregDeferred:
+		case regState_Unregistered:
+		case regState_NATMap:
+		case regState_ExtraQueued:
+			// In these states, the SRV has either not yet been registered (it will get up-to-date information when it is)
+			// or is in the process of, or has already been, deregistered
+			return;
+			
+		case regState_Pending:
+		case regState_Refresh:
+		case regState_UpdatePending:
+			// let the in-flight operation complete before updating
+			srs->uDNS_info.SRVUpdateDeferred = mDNStrue;
+			return;
+			
+		case regState_NoTarget:
+			// Service has not been registered due to lack of a target hostname
+			if (havetarget) SendServiceRegistration(m, srs);
+			return;
+			
+		case regState_Registered:
+			// target lost or changed.  deregister service.  upon completion, we'll look for a new target
+			// extra will be re-registed if the service is re-registered
+			for (e = srs->Extras; e; e = e->next) e->r.uDNS_info.state = regState_ExtraQueued;
+			
+			srs->uDNS_info.LostTarget = mDNStrue;
+			SendServiceDeregistration(m, srs);
+			return;
+		}
+	}
+
+mDNSlocal void UpdateSRVRecords(mDNS *m)
+	{
+	ServiceRecordSet *srs;
+
+	for (srs = m->uDNS_info.ServiceRegistrations; srs; srs = srs->next) UpdateSRV(m, srs);
+	}
+
+mDNSlocal void HostnameCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
+	{
+	uDNS_HostnameInfo *hi = (uDNS_HostnameInfo *)rr->RecordContext;
+	mDNSu8 *ip = rr->resrec.rdata->u.ipv4.b;
+	
+	if (result == mStatus_MemFree)
+		{
+		debugf("MemFree:  %##s IP %d.%d.%d.%d", rr->resrec.name.c, ip[0], ip[1], ip[2], ip[3]);
+		if (hi) ufree(hi);
+		ufree(rr);        
+		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
+		debugf("Name in use - retrying as type KnownUnique");
+		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;
+		}
+	
+	if (result)
+		{
+		// don't unlink or free - we can retry when we get a new address/router
+		LogMsg("HostnameCallback: Error %ld for registration of %##s IP %d.%d.%d.%d", result, rr->resrec.name.c, ip[0], ip[1], ip[2], ip[3]);
+		if (!hi) { ufree(rr); return; }
+		if (hi->ar->uDNS_info.state != regState_Unregistered) LogMsg("Error: HostnameCallback invoked with error code for record not in regState_Unregistered!");
+		(const void *)rr->RecordContext = hi->StatusContext;
+		if (hi->StatusCallback)
+			hi->StatusCallback(m, rr, result); // client may NOT make API calls here
+		rr->RecordContext = (void *)hi;
+		return;
+		}
+
+	// register any pending services that require a target
+	UpdateSRVRecords(m);
+	
+	// Deliver success to client
+	if (!hi) { LogMsg("HostnameCallback invoked with orphaned address record"); return; }
+	LogMsg("Registered hostname %##s IP %d.%d.%d.%d", rr->resrec.name.c, ip[0], ip[1], ip[2], ip[3]);	
+	(const void *)rr->RecordContext = hi->StatusContext;
+	if (hi->StatusCallback)
+		hi->StatusCallback(m, rr, result); // client may NOT make API calls here
+	rr->RecordContext = (void *)hi;
+	}
+
+// register record or begin NAT traversal
+mDNSlocal void AdvertiseHostname(mDNS *m, uDNS_HostnameInfo *h)
+	{
+	if (IsPrivateV4Addr(&m->uDNS_info.PrimaryIP)) 
+		StartGetPublicAddr(m, h);
+	else 
+	  {
+	  mDNSu8 *ip = m->uDNS_info.PrimaryIP.ip.v4.b;
+	  LogMsg("Advertising %##s IP %d.%d.%d.%d", h->ar->resrec.name.c, ip[0], ip[1], ip[2], ip[3]);
+	  uDNS_RegisterRecord(m, h->ar); 
+	  }
+	}
+
+mDNSlocal void FoundStaticHostname(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
+	{
+	const domainname *pktname = &answer->rdata->u.name;
+	domainname *storedname = &m->uDNS_info.StaticHostname;
+	(void)question;
+	
+	debugf("FoundStaticHostname: %##s -> %##s (%s)", question->qname.c, answer->rdata->u.name.c, AddRecord ? "added" : "removed");
+	if (AddRecord && !SameDomainName(pktname, storedname))
+		{
+		AssignDomainName(*storedname, *pktname);
+		UpdateSRVRecords(m);
+		}
+	else if (!AddRecord && SameDomainName(pktname, storedname))
+		{
+		storedname->c[0] = 0;
+		UpdateSRVRecords(m);
+		}
+	}
+
+mDNSlocal void GetStaticHostname(mDNS *m)
+	{
+	char buf[MAX_ESCAPED_DOMAIN_NAME];
+	DNSQuestion *q = &m->uDNS_info.ReverseMap;
+	mDNSu8 *ip = m->uDNS_info.PrimaryIP.ip.v4.b;
+	mStatus err;
+
+	ubzero(q, sizeof(*q));
+	
+	if (m->uDNS_info.ReverseMapActive)
+		{
+		uDNS_StopQuery(m, q);
+		m->uDNS_info.ReverseMapActive = mDNSfalse;
+		}
+
+	if (!m->uDNS_info.PrimaryIP.ip.v4.NotAnInteger) return;
+	mDNS_snprintf(buf, MAX_ESCAPED_DOMAIN_NAME, "%d.%d.%d.%d.in-addr.arpa.", ip[3], ip[2], ip[1], ip[0]);
+    if (!MakeDomainNameFromDNSNameString(&q->qname, buf)) { LogMsg("Error: GetStaticHostname - bad name %s", buf); return; }	
+
+	q->InterfaceID       = mDNSInterface_Any;
+    q->Target           = zeroAddr;
+    q->qtype            = kDNSType_PTR;
+    q->qclass           = kDNSClass_IN;
+    q->LongLived        = mDNSfalse;
+    q->ExpectUnique     = mDNSfalse;
+    q->ForceMCast       = mDNSfalse;
+    q->QuestionCallback = FoundStaticHostname;
+    q->QuestionContext  = mDNSNULL;
+
+	err = uDNS_StartQuery(m, q);
+	if (err) LogMsg("Error: GetStaticHostname - StartQuery returned error %d", err);
+	else m->uDNS_info.ReverseMapActive = mDNStrue;
+	}
+
+// Deregister hostnames and  register new names for each host domain with the current global 
+// values for the hostlabel and primary IP address
+mDNSlocal void UpdateHostnameRegistrations(mDNS *m)
+	{
+	uDNS_GlobalInfo *u = &m->uDNS_info;	
+	AuthRecord *new;
+	uDNS_HostnameInfo *i;
+
+	for (i = u->Hostnames; i; i = i->next)
+		{
+		// only allocate new record if existing record is actually registered (i.e. it wasn't pending the hostname or IP being set)
+		if (i->ar->uDNS_info.state == regState_Unregistered) new = i->ar;
+		else
+			{
+			new = umalloc(sizeof(AuthRecord));
+			if (!new) { LogMsg("ERROR: UpdateHostnameRegistration - malloc"); return; }
+			mDNS_SetupResourceRecord(new, mDNSNULL, 0, kDNSType_A,  1, kDNSRecordTypeUnique, HostnameCallback, i);
+			}
+
+		// setup new record
+		AssignDomainName(new->resrec.name, i->ar->resrec.name);
+		new->resrec.rdata->u.ipv4 = u->PrimaryIP.ip.v4;
+
+		if (i->ar->uDNS_info.state != regState_Unregistered)
+			{			
+			// delete old record
+			i->ar->RecordContext = mDNSNULL;  // clear backpointer to HostnameInfo
+			uDNS_DeregisterRecord(m, i->ar);  
+			i->ar = new;
+			}
+		
+		// advertise new
+		AdvertiseHostname(m, i);
+		}	
+	}
+
+mDNSexport void mDNS_AddDynDNSHostName(mDNS *m, const domainname *fqdn, mDNSRecordCallback *StatusCallback, const void *StatusContext)
 	{
-	return (r1->namehash == r2->namehash &&
-			r1->rrtype == r2->rrtype && 
-			SameDomainName(&r1->name, &r2->name) &&
-			SameRData(r1, r2));
+	uDNS_GlobalInfo *u = &m->uDNS_info;
+	uDNS_HostnameInfo *ptr, *new;
+
+	mDNS_Lock(m);
+
+	// check if domain already registered
+	for (ptr = u->Hostnames; ptr; ptr = ptr->next)
+		{
+		if (SameDomainName(fqdn, &ptr->ar->resrec.name))
+			{ LogMsg("Host Domain %##s already in list", fqdn->c); goto exit; }
+		}
+
+	// allocate and format new address record
+	new = umalloc(sizeof(*new));
+	if (new) new->ar = umalloc(sizeof(AuthRecord));
+	if (!new || !new->ar) { LogMsg("ERROR: mDNS_AddDynDNSHostname - malloc"); goto exit; }
+	new->StatusCallback = StatusCallback;
+	new->StatusContext = StatusContext;
+	mDNS_SetupResourceRecord(new->ar, mDNSNULL, 0, kDNSType_A,  1, kDNSRecordTypeUnique, HostnameCallback, new);	
+	AppendDomainName(&new->ar->resrec.name, fqdn);
+	new->next = u->Hostnames;
+	u->Hostnames = new;
+	if (u->PrimaryIP.ip.v4.NotAnInteger)
+		{
+		// only set RData if we have a valid IP
+		if (u->MappedPrimaryIP.ip.v4.NotAnInteger) new->ar->resrec.rdata->u.ipv4 = u->MappedPrimaryIP.ip.v4;  //!!!KRS implement code that caches this
+		else                                       new->ar->resrec.rdata->u.ipv4 = u->PrimaryIP.ip.v4;
+		AdvertiseHostname(m, new);
+		}
+	else new->ar->uDNS_info.state = regState_Unregistered;
+exit:
+	mDNS_Unlock(m);
 	}
 
+mDNSexport void mDNS_RemoveDynDNSHostName(mDNS *m, const domainname *fqdn)
+	{
+	uDNS_GlobalInfo *u = &m->uDNS_info;
+	uDNS_HostnameInfo **ptr = &u->Hostnames;
+
+	mDNS_Lock(m);
+
+	while (*ptr && !SameDomainName(fqdn, &(*ptr)->ar->resrec.name)) ptr = &(*ptr)->next;
+	if (!*ptr) LogMsg("mDNS_RemoveDynDNSHostName: no such domainname %##s", fqdn->c);		
+	else
+		{
+		uDNS_HostnameInfo *hi = *ptr;
+		*ptr = (*ptr)->next; // unlink
+		hi->ar->RecordContext = mDNSNULL; // about to free wrapper struct		
+		if (hi->ar->uDNS_info.state != regState_Unregistered) uDNS_DeregisterRecord(m, hi->ar);
+		else { ufree(hi->ar); hi->ar = mDNSNULL; }
+		ufree(hi);
+		}
+	UpdateSRVRecords(m);
+	mDNS_Unlock(m);
+	}
+
+mDNSexport void mDNS_SetPrimaryInterfaceInfo(mDNS *m, const mDNSAddr *addr, const mDNSAddr *router)
+	{
+	uDNS_GlobalInfo *u = &m->uDNS_info;
+	mDNSBool AddrChanged, RouterChanged;
+   
+	if (addr && addr->type !=mDNSAddrType_IPv4) { LogMsg("mDNS_SetPrimaryInterfaceInfo passed non-V4 address.  Discarding."); return; }
+	if (router && router->type !=mDNSAddrType_IPv4) { LogMsg("mDNS_SetPrimaryInterfaceInfo passed non-V4 address.  Discarding."); return; }
+	mDNS_Lock(m);
+
+	AddrChanged = addr ? (addr->ip.v4.NotAnInteger != u->PrimaryIP.ip.v4.NotAnInteger) : u->PrimaryIP.ip.v4.NotAnInteger;
+	RouterChanged = router ? (router->ip.v4.NotAnInteger != u->Router.ip.v4.NotAnInteger) : u->Router.ip.v4.NotAnInteger;
+	
+#if MDNS_DEBUGMSGS
+	if (addr && (AddrChanged || RouterChanged))
+		LogMsg("mDNS_SetPrimaryInterfaceInfo: address changed from %d.%d.%d.%d to %d.%d.%d.%d:%d",
+			   u->PrimaryIP.ip.v4.b[0], u->PrimaryIP.ip.v4.b[1], u->PrimaryIP.ip.v4.b[2], u->PrimaryIP.ip.v4.b[3],
+			   addr->ip.v4.b[0], addr->ip.v4.b[1], addr->ip.v4.b[2], addr->ip.v4.b[3], mDNSVal16(m->UnicastPort4));
+#endif // MDNS_DEBUGMSGS
+										   	
+	if (addr)   u->PrimaryIP = *addr;
+	if (router) u->Router = *router;
+	else        u->Router.ip.v4.NotAnInteger = 0; // setting router to zero indicates that nat mappings must be reestablished when router is reset
+	
+	if (AddrChanged)
+		{
+		if (addr)
+			{
+			UpdateHostnameRegistrations(m);
+			UpdateSRVRecords(m);
+			}
+		GetStaticHostname(m);  // look up reverse map record to find any static hostnames for our IP address
+		}
+	
+	mDNS_Unlock(m);
+	}
+
+// ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark - Incoming Message Processing
+#endif
+
 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;
+		if (SameResourceRecord(&ptr->resrec, &rr->resrec)) return mDNStrue;
 
 	return mDNSfalse;
 	}
@@ -597,11 +1648,11 @@ mDNSlocal mDNSBool kaListContainsAnswer(DNSQuestion *question, CacheRecord *rr)
 
 mDNSlocal void removeKnownAnswer(DNSQuestion *question, CacheRecord *rr)
 	{
-	CacheRecord *ptr, *prev = NULL;
+	CacheRecord *ptr, *prev = mDNSNULL;
 
 	for (ptr = question->uDNS_info.knownAnswers; ptr; ptr = ptr->next)
 		{
-		if (sameResourceRecord(&ptr->resrec, &rr->resrec))
+		if (SameResourceRecord(&ptr->resrec, &rr->resrec))
 			{
 			if (prev) prev->next = ptr->next;
 			else question->uDNS_info.knownAnswers = ptr->next;
@@ -616,7 +1667,7 @@ mDNSlocal void removeKnownAnswer(DNSQuestion *question, CacheRecord *rr)
 
 mDNSlocal void addKnownAnswer(DNSQuestion *question, const CacheRecord *rr)
 	{
-	CacheRecord *newCR = NULL;
+	CacheRecord *newCR = mDNSNULL;
 	mDNSu32 size;	
 
 	size = sizeof(CacheRecord) + rr->resrec.rdlength - InlineCacheRDSize;
@@ -633,7 +1684,7 @@ mDNSlocal void deriveGoodbyes(mDNS * const m, DNSMessage *msg, const  mDNSu8 *en
 	{
 	const mDNSu8 *ptr;
 	int i;
-	CacheRecord *fptr, *ka, *cr, *answers = NULL, *prev = NULL;
+	CacheRecord *fptr, *ka, *cr, *answers = mDNSNULL, *prev = mDNSNULL;
 	LargeCacheRecord *lcr;
 	
 	if (question != m->uDNS_info.CurrentQuery) { LogMsg("ERROR: deriveGoodbyes called without CurrentQuery set!"); return; }
@@ -647,8 +1698,11 @@ mDNSlocal void deriveGoodbyes(mDNS * const m, DNSMessage *msg, const  mDNSu8 *en
 		ka = question->uDNS_info.knownAnswers;
 		while (ka)
 			{
-			debugf("deriving goodbye for %s", ka->resrec.name.c);
+			debugf("deriving goodbye for %##s", ka->resrec.name.c);
+			
+			m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
 			question->QuestionCallback(m, question, &ka->resrec, mDNSfalse);
+			m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
 			if (question != m->uDNS_info.CurrentQuery)
 				{
 				debugf("deriveGoodbyes - question removed via callback.  returning.");
@@ -658,7 +1712,7 @@ mDNSlocal void deriveGoodbyes(mDNS * const m, DNSMessage *msg, const  mDNSu8 *en
 			ka = ka->next;
 			ufree(fptr);
 			}
-		question->uDNS_info.knownAnswers = NULL;
+		question->uDNS_info.knownAnswers = mDNSNULL;
 		return;
 		}
 	
@@ -684,14 +1738,16 @@ mDNSlocal void deriveGoodbyes(mDNS * const m, DNSMessage *msg, const  mDNSu8 *en
 	while (ka)
 		{
 		for (cr = answers; cr; cr = cr->next)
-			{ if (sameResourceRecord(&ka->resrec, &cr->resrec)) break; }
+			{ 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);
+			debugf("deriving goodbye for %##s", ka->resrec.name.c);
+			m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
 			question->QuestionCallback(m, question, &ka->resrec, mDNSfalse);
+			m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
 			if (question != m->uDNS_info.CurrentQuery)
 				{
 				debugf("deriveGoodbyes - question removed via callback.  returning.");
@@ -715,7 +1771,7 @@ mDNSlocal void deriveGoodbyes(mDNS * const m, DNSMessage *msg, const  mDNSu8 *en
 	return;
 	
 	pkt_error:
-	LogMsg("ERROR: deriveGoodbyes - received malformed response to query for %s (%d)",
+	LogMsg("ERROR: deriveGoodbyes - received malformed response to query for %##s (%d)",
 		   question->qname.c, question->qtype);
 	return;
 
@@ -729,12 +1785,15 @@ mDNSlocal void pktResponseHndlr(mDNS * const m, DNSMessage *msg, const  mDNSu8 *
 	int i;
 	LargeCacheRecord lcr;
 	CacheRecord *cr = &lcr.r;
-	mDNSBool goodbye, inKAList;
+	mDNSBool goodbye, inKAList, followedCName = mDNSfalse;
 	LLQ_Info *llqInfo = question->uDNS_info.llq;
+	domainname origname;
 	
 	if (question != m->uDNS_info.CurrentQuery)
 		{ LogMsg("ERROR: pktResponseHdnlr called without CurrentQuery ptr set!");  return; }
-		
+
+	question->uDNS_info.Answered = mDNStrue;
+	
 	ptr = LocateAnswers(msg, end);
 	if (!ptr) goto pkt_error;
 
@@ -744,32 +1803,53 @@ mDNSlocal void pktResponseHndlr(mDNS * const m, DNSMessage *msg, const  mDNSu8 *
 		if (!ptr) goto pkt_error;
 		if (ResourceRecordAnswersQuestion(&cr->resrec, question))
 			{
+			if (cr->resrec.rrtype == kDNSType_CNAME)
+				{
+				if (followedCName) LogMsg("Error: multiple CNAME referals for question %##s", question->qname.c);
+				else
+					{
+					debugf("Following cname %##s -> %##s", question->qname.c, cr->resrec.rdata->u.name.c);
+					AssignDomainName(origname, question->qname);					
+					AssignDomainName(question->qname, cr->resrec.rdata->u.name);
+					question->qnamehash = DomainNameHashValue(&question->qname);
+					followedCName = mDNStrue;
+					i = -1; // restart packet answer matching					
+					ptr = LocateAnswers(msg, end);
+					continue;
+					}
+				}
+			
 			goodbye = llq ? ((mDNSs32)cr->resrec.rroriginalttl == -1) : mDNSfalse;
 			inKAList = kaListContainsAnswer(question, cr);
 
 			if ((goodbye && !inKAList) || (!goodbye && inKAList)) continue;  // list up to date
 			if (!inKAList) addKnownAnswer(question, cr);
 			if (goodbye) removeKnownAnswer(question, cr);
+			m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
 			question->QuestionCallback(m, question, &cr->resrec, !goodbye);
+			m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
 			if (question != m->uDNS_info.CurrentQuery)
 				{
 				debugf("pktResponseHndlr - CurrentQuery changed by QuestionCallback - returning");
 				return;
 				}
 			}			
-		else
-			{
-			LogMsg("unexpected answer: %s", cr->resrec.name.c);
-			}
+		else if (!followedCName || !SameDomainName(&cr->resrec.name, &origname))
+			LogMsg("Question %##s type %d - unexpected answer %##s type %d", question->qname.c, question->qtype, cr->resrec.name.c, cr->resrec.rrtype);
+		}
+	
+	if (!llq || llqInfo->state == LLQ_Poll || llqInfo->deriveRemovesOnResume)
+		{
+		deriveGoodbyes(m, msg, end,question);
+		if (llq && llqInfo->deriveRemovesOnResume) llqInfo->deriveRemovesOnResume = mDNSfalse;
 		}
-	if (llq && (llqInfo->state == LLQ_Poll || llqInfo->deriveRemovesOnResume))	
-		{ deriveGoodbyes(m, msg, end,question);  llqInfo->deriveRemovesOnResume = mDNSfalse; }
-	//!!!KRS should we derive goodbyes for non-LLQs?
 
+	// our interval may be set lower to recover from failures - now that we have an answer, fully back off retry
+	if (question->ThisQInterval < MAX_UCAST_POLL_INTERVAL) question->ThisQInterval = MAX_UCAST_POLL_INTERVAL;
 	return;
 
 	pkt_error:
-	LogMsg("ERROR: pktResponseHndlr - received malformed response to query for %s (%d)",
+	LogMsg("ERROR: pktResponseHndlr - received malformed response to query for %##s (%d)",
 		   question->qname.c, question->qtype);
 	return;
 	}
@@ -786,134 +1866,248 @@ mDNSlocal void llqResponseHndlr(mDNS * const m, DNSMessage *msg, const  mDNSu8 *
 	pktResponseHndlr(m, msg, end, question, mDNStrue);
 	}
 
-
-
-mDNSlocal void unlinkSRS(uDNS_GlobalInfo *u, ServiceRecordSet *srs)
+mDNSlocal mStatus ParseTSIGError(mDNS *m, const DNSMessage *msg, const mDNSu8 *end, const domainname *displayname)
 	{
-	ServiceRecordSet *ptr, *prev = NULL;
+	LargeCacheRecord lcr;
+	const mDNSu8 *ptr;
+	mStatus err = mStatus_NoError;
+	int i;
+	
+	ptr = LocateAdditionals(msg, end);
+	if (!ptr) goto finish;
 	
-	for (ptr = u->ServiceRegistrations; ptr; ptr = ptr->next)
+	for (i = 0; i < msg->h.numAdditionals; i++)
 		{
-		if (ptr == srs)
+		ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &lcr);;
+		if (!ptr) goto finish;
+		if (lcr.r.resrec.rrtype == kDNSType_TSIG)
 			{
-			if (prev) prev->next = ptr->next;
-			else u->ServiceRegistrations = ptr->next;
-			ptr->next = NULL;
-			return;
+			mDNSu32 macsize;
+		    mDNSu8 *rd = lcr.r.resrec.rdata->u.data;
+			mDNSu8 *rdend = rd + MaximumRDSize;
+			int alglen = DomainNameLength(&lcr.r.resrec.rdata->u.name);
+			
+			if (rd +  alglen > rdend) goto finish;
+			rd += alglen;                                       // algorithm name
+			if (rd + 6 > rdend) goto finish;         
+			rd += 6;                                            // 48-bit timestamp
+			if (rd + sizeof(mDNSOpaque16) > rdend) goto finish;
+			rd += sizeof(mDNSOpaque16);                         // fudge
+			if (rd + sizeof(mDNSOpaque16) > rdend) goto finish;
+			macsize = mDNSVal16(*(mDNSOpaque16 *)rd);
+			rd += sizeof(mDNSOpaque16);                         // MAC size
+			if (rd + macsize > rdend) goto finish;
+			rd += macsize;
+			if (rd + sizeof(mDNSOpaque16) > rdend) goto finish;
+			rd += sizeof(mDNSOpaque16);                         // orig id
+			if (rd + sizeof(mDNSOpaque16) > rdend) goto finish;
+			err = mDNSVal16(*(mDNSOpaque16 *)rd);               // error code
+
+			if (err ==  TSIG_ErrBadSig)      { LogMsg("%##s: bad signature", displayname->c); err = mStatus_BadSig; }
+			else if (err == TSIG_ErrBadKey)  { LogMsg("%##s: bad key", displayname->c);       err = mStatus_BadKey; }
+			else if (err == TSIG_ErrBadTime) { LogMsg("%##s: bad time", displayname->c);      err = mStatus_BadTime; }
+			else if (err)                    { LogMsg("%##s: unknown tsig error %d", err);    err = mStatus_UnknownErr; }
+			goto finish;
 			}
-		prev = ptr;
 		}
-	LogMsg("ERROR: unlinkSRS - SRS not found in ServiceRegistrations list");
+			
+	finish:
+	return err;
 	}
 
-
-mDNSlocal mStatus checkUpdateResult(domainname *name, mDNSu8 rcode, const DNSMessage *msg)
-	{
+mDNSlocal mStatus checkUpdateResult(domainname *displayname, mDNSu8 rcode, mDNS *m, const DNSMessage *msg, const mDNSu8 *end)
+	{	
 	(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);
+		LogMsg("name in use: %##s", displayname->c);
 		return mStatus_NameConflict;
 		}
 	else if (rcode == kDNSFlag1_RC_Refused)
 		{
-		LogMsg("Update %s refused", name->c);
-		return mStatus_Refused;
+		LogMsg("Update %##s refused", displayname->c);
+		return mStatus_Refused;			
 		}
 	else if (rcode == kDNSFlag1_RC_NXRRSet)
 		{
-		LogMsg("Reregister refusted (NXRRSET): %s", name->c);
+		LogMsg("Reregister refused (NXRRSET): %##s", displayname->c);
 		return mStatus_NoSuchRecord;
 		}
 	else if (rcode == kDNSFlag1_RC_NotAuth)
 		{
-		LogMsg("Permission denied (NOAUTH): %s", name->c);
-		return mStatus_NoAuth;
+		// TSIG errors should come with FmtErr as per RFC 2845, but BIND 9 sends them with NotAuth so we look here too
+		mStatus tsigerr = ParseTSIGError(m, msg, end, displayname);
+		if (!tsigerr)
+			{
+			LogMsg("Permission denied (NOAUTH): %##s", displayname->c);
+			return mStatus_UnknownErr;
+			}
+		else return tsigerr;
 		}
 	else if (rcode == kDNSFlag1_RC_FmtErr)
 		{
-		LogMsg("Format Error: %s", name->c);
-		return mStatus_UnknownErr;
-		//!!!KRS need to parse message for TSIG errors
+		mStatus tsigerr = ParseTSIGError(m, msg, end, displayname);
+		if (!tsigerr)
+			{
+			LogMsg("Format Error: %##s", displayname->c);		
+			return mStatus_UnknownErr;
+			}
+		else return tsigerr;
 		}
 	else
 		{
-		LogMsg("Update %s failed with rcode %d", name->c, rcode);
+		LogMsg("Update %##s failed with rcode %d", displayname->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
+	mDNSBool InvokeCallback = mDNSfalse;	
+	AuthRecord *UpdateR = mDNSNULL;
+	uDNS_RegInfo *info = &srs->uDNS_info;
+	NATTraversalInfo *nat = srs->uDNS_info.NATinfo;
+	ExtraResourceRecord **e = &srs->Extras;
 	
-	switch (srs->uDNS_info.state)
+	switch (info->state)
 		{
 		case regState_Pending:
-		case regState_Refresh:
-			if (err)
+			if (err == mStatus_NameConflict && !info->TestForSelfConflict)
 				{
-				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;
-					}
+				info->TestForSelfConflict = mDNStrue;
+				debugf("checking for self-conflict of service %##s", srs->RR_SRV.resrec.name.c);
+				SendServiceRegistration(m, srs);
+				return;
+				}
+			else if (info->TestForSelfConflict)
+				{
+				info->TestForSelfConflict = mDNSfalse;
+				if (err == mStatus_NoSuchRecord) err = mStatus_NameConflict;  // NoSuchRecord implies that our prereq was not met, so we actually have a name conflict
+				if (err) info->state = regState_Unregistered;
+				else info->state = regState_Registered;				
+				InvokeCallback = mDNStrue;
+				break;
+				}
+			else if (err == mStatus_UnknownErr && info->lease)
+				{
+				LogMsg("Re-trying update of service %##s without lease option", srs->RR_SRV.resrec.name.c);
+				info->lease = mDNSfalse;
+				info->expire = -1;
+				SendServiceRegistration(m, srs);
+				return;
 				}
 			else
 				{
-				if (srs->uDNS_info.state == regState_Refresh)
-					{
-					srs->uDNS_info.state = regState_Registered;				
-					return;
-					}
-				srs->uDNS_info.state = regState_Registered;
+				if (err) { LogMsg("Error %ld for registration of service %##s", err, srs->RR_SRV.resrec.name.c); info->state = regState_Unregistered; } //!!!KRS make sure all structs will still get cleaned up when client calls DeregisterService with this state
+				else info->state = regState_Registered;
+				InvokeCallback = mDNStrue;
 				break;
-				}				
+				}
+		case regState_Refresh:
+			if (err)
+				{
+				LogMsg("Error %ld for refresh of service %##s", err, srs->RR_SRV.resrec.name.c);
+				InvokeCallback = mDNStrue;
+				info->state = regState_Unregistered;				
+				}
+			else info->state = regState_Registered;
+			break;
 		case regState_DeregPending:
-			if (err) LogMsg("hndlServiceUpdateReply: Error %d returned for dereg of %s",
-							err, srs->RR_SRV.resrec.name.c);
-			else err = mStatus_MemFree;
+			if (err) LogMsg("Error %ld for deregistration of service %##s", err, srs->RR_SRV.resrec.name.c);
+			if (info->LostTarget)
+				{
+				info->state = regState_NoTarget;
+				break;
+				} 
+			err = mStatus_MemFree;
+			InvokeCallback = mDNStrue;
+			if (nat)
+				{
+				if (nat->state == NATState_Deleted) { FreeNATInfo(m, nat); info->NATinfo = mDNSNULL; } // deletion copmleted
+				else nat->reg.ServiceRegistration = mDNSNULL;  // allow mapping deletion to continue
+				}
+			info->state = regState_Unregistered;
 			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) { debugf("Error %ld received prior to deferred derigstration of %##s", err, srs->RR_SRV.resrec.name.c); }
+			debugf("Performing deferred deregistration of %##s", srs->RR_SRV.resrec.name.c); 
+			info->state = regState_Registered; // benign to set even if we've got an error
+			SendServiceDeregistration(m, srs);
+			return;		   
+		case regState_UpdatePending:
+			// find the record being updated
+			UpdateR = &srs->RR_TXT;
 			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
+				LogMsg("hndlServiceUpdateReply: error updating resource record");				
+				UpdateR->uDNS_info.state = regState_Unregistered;
+				InvokeCallback = mDNStrue;        // signal error via service callback
 				}
-			else srs->uDNS_info.state = regState_Registered;
+			else
+				{
+				UpdateR->uDNS_info.state = regState_Registered;
+				SwapRData(m, UpdateR, mDNStrue);				
+				}
+			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);
+		case regState_FetchingZoneData:
+		case regState_Registered:
+		case regState_Cancelled:
+		case regState_Unregistered:
+		case regState_NATMap:
+		case regState_NoTarget:
+		case regState_ExtraQueued:
+			LogMsg("hndlServiceUpdateReply called for service %##s in unexpected state %d with error %ld.  Unlinking.",
+				   srs->RR_SRV.resrec.name.c, info->state, err);
 			err = mStatus_UnknownErr;
 		}
 
-	if (err)
+	if ((info->LostTarget || info->SRVUpdateDeferred) && (info->state == regState_NoTarget || info->state == regState_Registered))
 		{
-		unlinkSRS(&m->uDNS_info, srs);		// name conflicts, force dereg, and errors
-		srs->uDNS_info.state = regState_Unregistered;
+		UpdateSRV(m, srs);
+		return;
 		}
-	
-	srs->ServiceCallback(m, srs, err);
+
+	while (*e)
+		{
+		uDNS_RegInfo *einfo = &(*e)->r.uDNS_info;
+		if (einfo->state == regState_ExtraQueued)
+			{			
+			if (info->state == regState_Registered && !err)
+				{
+				// extra resource record queued for this service - copy zone info and register
+				AssignDomainName(einfo->zone, info->zone);
+				einfo->ns = info->ns;
+				einfo->port = info->port;
+				einfo->lease = info->lease;
+				sendRecordRegistration(m, &(*e)->r);
+				e = &(*e)->next;
+				}
+			else if (err && einfo->state != regState_Unregistered)
+				{
+				// unlink extra from list
+				einfo->state = regState_Unregistered;
+				*e = (*e)->next;
+				}
+			else e = &(*e)->next;
+			}
+		else e = &(*e)->next;
+		}
+
+	srs->RR_SRV.ThisAPInterval = INIT_UCAST_POLL_INTERVAL - 1;  // reset retry delay for future refreshes, dereg, etc.		
+	if (srs->RR_TXT.uDNS_info.UpdateQueued) SendRecordUpdate(m, &srs->RR_TXT, &srs->uDNS_info);		
+
+	if (info->state == regState_Unregistered) unlinkSRS(&m->uDNS_info, srs);
+
+	m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
+	if (InvokeCallback) srs->ServiceCallback(m, srs, err);
+	else if (info->ClientCallbackDeferred)
+		{
+		info->ClientCallbackDeferred = mDNSfalse;
+		srs->ServiceCallback(m, srs, info->DeferredStatus);
+		}
+	m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
 	// NOTE: do not touch structures after calling ServiceCallback
 	}
 
@@ -921,16 +2115,37 @@ mDNSlocal void hndlRecordUpdateReply(mDNS *m, AuthRecord *rr, mStatus err)
 	{
 	uDNS_GlobalInfo *u = &m->uDNS_info;
 	
+	if (rr->uDNS_info.state == regState_UpdatePending)
+		{
+		if (err)
+			{
+			LogMsg("Update record failed for %##s (err %d)", rr->resrec.name.c, err);
+			rr->uDNS_info.state = regState_Unregistered;
+			}
+		else
+			{
+			debugf("Update record %##s - success", rr->resrec.name.c);
+			rr->uDNS_info.state = regState_Registered;
+			SwapRData(m, rr, mDNStrue);
+			}
+		m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
+		if (rr->RecordCallback) rr->RecordCallback(m, rr, err);
+		m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
+		return;
+		}
+
 	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",
+		debugf("Received reply for deregister record %##s type %d", rr->resrec.name.c, rr->resrec.rrtype);
+		if (err) LogMsg("ERROR: Deregistration of record %##s type %d failed with error %ld",
 						rr->resrec.name.c, rr->resrec.rrtype, err);
-		else err = mStatus_MemFree;
+		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);
+		m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
+		if (rr->RecordCallback) rr->RecordCallback(m, rr, err);
+		m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
 		return;
 		}
 
@@ -938,13 +2153,13 @@ mDNSlocal void hndlRecordUpdateReply(mDNS *m, AuthRecord *rr, mStatus err)
 		{
 		if (err)
 			{
-			LogMsg("Cancelling deferred deregistration record %s type %d due to registration error %d",
+			LogMsg("Cancelling deferred deregistration record %##s type %d due to registration error %ld",
 				   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",
+		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);					
@@ -957,32 +2172,45 @@ mDNSlocal void hndlRecordUpdateReply(mDNS *m, AuthRecord *rr, mStatus err)
 			{
 			if (rr->uDNS_info.lease && err == mStatus_UnknownErr)
 				{
-				LogMsg("Re-trying update of record %s without lease option", rr->resrec.name.c);
+				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",
+			LogMsg("Registration of record %##s type %d failed with error %ld",
 				   rr->resrec.name.c, rr->resrec.rrtype, err);
 			unlinkAR(&u->RecordRegistrations, rr); 
 			rr->uDNS_info.state = regState_Unregistered;
+			m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
+			if (rr->RecordCallback) rr->RecordCallback(m, rr, err);
+			m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
+			return;
 			}
 		else
 			{
+			if (rr->uDNS_info.UpdateQueued)
+				{
+				debugf("%##s: sending queued update", rr->resrec.name.c);
+				rr->uDNS_info.state = regState_Registered;
+				SendRecordUpdate(m ,rr, &rr->uDNS_info);
+				return;
+				}
 			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);
+				m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
+				if (rr->RecordCallback) rr->RecordCallback(m, rr, err);
+				m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
 				}
 			return;
 			}
 		}
 	
-	LogMsg("Received unexpected response for record %s type %d, in state %d, with response error %d",
+	LogMsg("Received unexpected response for record %##s type %d, in state %d, with response error %ld",
 		   rr->resrec.name.c, rr->resrec.rrtype, rr->uDNS_info.state, err);
 	}
 
@@ -993,7 +2221,8 @@ mDNSlocal void SetUpdateExpiration(mDNS *m, DNSMessage *msg, const mDNSu8 *end,
 	const mDNSu8 *ptr;
 	int i;
 	mDNSu32 lease = 0;
-
+	mDNSs32 expire;
+	
 	ptr = LocateAdditionals(msg, end);
 
 	if (info->lease && (ptr = LocateAdditionals(msg, end)))
@@ -1013,13 +2242,43 @@ mDNSlocal void SetUpdateExpiration(mDNS *m, DNSMessage *msg, const mDNSu8 *end,
 		}
 	
 	if (lease > 0)
-		info->expire = (mDNSPlatformTimeNow() + (((mDNSs32)lease * mDNSPlatformOneSecond)) * 3/4);
+		{
+		expire = (mDNSPlatformTimeNow(m) + (((mDNSs32)lease * mDNSPlatformOneSecond)) * 3/4);
+		if (info->state == regState_UpdatePending)  
+            // if updating individual record, the service record set may expire sooner
+			{ if (expire - info->expire < 0) info->expire = expire; }
+		else info->expire = expire;
+		}
 	else info->expire = -1;
 	}
 
+mDNSexport void uDNS_ReceiveNATMap(mDNS *m, mDNSu8 *pkt, mDNSu16 len)
+	{
+	uDNS_GlobalInfo *u = &m->uDNS_info;
+	NATTraversalInfo *ptr, *cur;
+	NATOp_t op;
+	
+	// check length, version, opcode
+	if (len < ADDR_REPLY_PKTLEN && len < PORTMAP_PKTLEN) { LogMsg("NAT Traversal message too short (%d bytes)", len); return; }
+	if (pkt[0] != NATMAP_VERS) { LogMsg("Received NAT Traversal response with version %d (expect version %d)", pkt[0], NATMAP_VERS); return; }
+	op = pkt[1];
+	if (!(op & NATMAP_RESPONSE_MASK)) { LogMsg("Received NAT Traversal message that is not a response (opcode %d)", op); return; }
+
+	ptr = u->NATTraversals;
+	while (ptr)
+		{
+		cur = ptr;
+		ptr = ptr->next;
+		if ((cur->state == NATState_Request || cur->state == NATState_Refresh) &&
+			(cur->op | NATMAP_RESPONSE_MASK) == op)
+			cur->ReceiveResponse(cur, m, pkt, len);  // callback may delete "cur"
+     		// specific request/reply matching logic handled by callback - we don't know if this was a match, so we don't break here  
+		}
+	}
+
 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)
+	const mDNSIPPort dstport, const mDNSInterfaceID InterfaceID)
 	{
 	DNSQuestion *qptr;
 	AuthRecord *rptr;
@@ -1028,35 +2287,37 @@ mDNSexport void uDNS_ReceiveMsg(mDNS *const m, DNSMessage *const msg, const mDNS
 	uDNS_GlobalInfo *u = &m->uDNS_info;
 	
 	mDNSu8 StdR    = kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery;
-	mDNSu8 UpdateR = kDNSFlag0_OP_Update   | kDNSFlag0_QR_Response;
+	mDNSu8 UpdateR = kDNSFlag0_QR_Response | kDNSFlag0_OP_Update;
 	mDNSu8 QR_OP   = (mDNSu8)(msg->h.flags.b[0] & kDNSFlag0_QROP_Mask);
 	mDNSu8 rcode   = (mDNSu8)(msg->h.flags.b[1] & kDNSFlag1_RC);
-   	
+
+	mDNSs32 timenow = mDNSPlatformTimeNow(m);
+	
     // 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;
+		// LLQ Responses over TCP not currently supported
+		if (srcaddr && 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 (timenow - (qptr->LastQTime + RESPONSE_WINDOW) > 0)
+					{ LogMsg("uDNS_ReceiveMsg - response received after maximum allowed window.  Discarding"); return; }
 				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;
+					u->CurrentQuery = mDNSNULL;
 					// Note: responseCallback can invalidate qptr
 					return;
 					}
@@ -1069,7 +2330,7 @@ mDNSexport void uDNS_ReceiveMsg(mDNS *const m, DNSMessage *const msg, const mDNS
 			{
 			if (sptr->uDNS_info.id.NotAnInteger == msg->h.id.NotAnInteger)
 				{
-				err = checkUpdateResult(&sptr->RR_SRV.resrec.name, rcode, msg);
+				err = checkUpdateResult(&sptr->RR_SRV.resrec.name, rcode, m, msg, end);
 				if (!err) SetUpdateExpiration(m, msg, end, &sptr->uDNS_info);
 				hndlServiceUpdateReply(m, sptr, err);
 				return;
@@ -1079,7 +2340,7 @@ mDNSexport void uDNS_ReceiveMsg(mDNS *const m, DNSMessage *const msg, const mDNS
 			{
 			if (rptr->uDNS_info.id.NotAnInteger == msg->h.id.NotAnInteger)
 				{
-				err = checkUpdateResult(&rptr->resrec.name, rcode, msg);
+				err = checkUpdateResult(&rptr->resrec.name, rcode, m, msg, end);
 				if (!err) SetUpdateExpiration(m, msg, end, &rptr->uDNS_info);				
 				hndlRecordUpdateReply(m, rptr, err);
 				return;
@@ -1089,28 +2350,35 @@ mDNSexport void uDNS_ReceiveMsg(mDNS *const m, DNSMessage *const msg, const mDNS
 	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)
+// lookup a DNS Server, matching by name in split-dns configurations.  Result stored in addr parameter if successful
+mDNSlocal mDNSBool GetServerForName(uDNS_GlobalInfo *u, const domainname *name, mDNSAddr *addr)
     {
-    int i;
-    for (i = 0; i < 32; i++)
-		if (u->Servers[i].ip.v4.NotAnInteger) return &u->Servers[i];
+	DNSServer *curmatch = mDNSNULL, *p = u->Servers;
+	int i, ncount, scount, curmatchlen = -1;
 
-	return NULL;
-    }
+	*addr = zeroAddr;
+	ncount = name ? CountLabels(name) : 0;
+	while (p)
+		{		
+		scount = CountLabels(&p->domain);
+		if (scount <= ncount && scount > curmatchlen)
+			{
+			// only inspect if server's domain is longer than current best match and shorter than the name itself
+			const domainname *tail = name;
+			for (i = 0; i < ncount - scount; i++)
+				tail = (domainname *)(tail->c + 1 + tail->c[0]);  // find "tail" (scount labels) of name
+			if (SameDomainName(tail, &p->domain)) { curmatch = p; curmatchlen = scount; }
+			}
+		p = p->next;
+		}
+
+	if (curmatch)
+		{
+		*addr = curmatch->addr;
+		return mDNStrue;
+		}
+	else return mDNSfalse;
+	}
 
 // ***************************************************************************
 #if COMPILER_LIKES_PRAGMA_MARK
@@ -1151,7 +2419,7 @@ mDNSlocal mDNSu8 *putLLQ(DNSMessage *const msg, mDNSu8 *ptr, DNSQuestion *questi
 	if (includeQuestion)
 		{
 		ptr = putQuestion(msg, ptr, msg->data + AbsoluteMaxDNSMessageData, &question->qname, question->qtype, question->qclass);
-		if (!ptr) { LogMsg("ERROR: putLLQ - putQuestion"); return NULL; }
+		if (!ptr) { LogMsg("ERROR: putLLQ - putQuestion"); return mDNSNULL; }
 		}
 	// locate OptRR if it exists, set pointer to end 
 	// !!!KRS implement me
@@ -1170,8 +2438,8 @@ mDNSlocal mDNSu8 *putLLQ(DNSMessage *const msg, mDNSu8 *ptr, DNSQuestion *questi
 	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; }
+	ptr = PutResourceRecordTTLJumbo(msg, ptr, &msg->h.numAdditionals, opt, 0);
+	if (!ptr) { LogMsg("ERROR: putLLQ - PutResourceRecordTTLJumbo"); return mDNSNULL; }
 
 	return ptr;
 	}
@@ -1193,7 +2461,7 @@ mDNSlocal mDNSBool getLLQAtIndex(mDNS *m, DNSMessage *msg, const mDNSu8 *end, LL
 		{ 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));
+	umemcpy(llq, (mDNSu8 *)&lcr.r.resrec.rdata->u.opt.OptData.llq + (index * sizeof(LLQOptData)), sizeof(LLQOptData));	// !!! Should convert to host byte order?
 	return mDNStrue;
 	}
 
@@ -1204,12 +2472,12 @@ mDNSlocal void recvRefreshReply(mDNS *m, DNSMessage *msg, const mDNSu8 *end, DNS
 
 	qInfo = q->uDNS_info.llq;
 	if (!getLLQAtIndex(m, msg, end, &pktData, 0)) { LogMsg("ERROR recvRefreshReply - getLLQAtIndex"); return; }
-	if (pktData.llqOp != kLLQ_Refresh) return;
+	if (pktData.llqOp != kLLQOp_Refresh) return;
 	if (!sameID(pktData.id, qInfo->id)) { LogMsg("recvRefreshReply - ID mismatch.  Discarding");  return; }
 	if (pktData.err != LLQErr_NoError) { LogMsg("recvRefreshReply: received error %d from server", pktData.err); return; }
 
-	qInfo->expire = mDNSPlatformTimeNow() + ((mDNSs32)pktData.lease * mDNSPlatformOneSecond);
-	qInfo->retry = qInfo->expire + ((mDNSs32)pktData.lease * mDNSPlatformOneSecond * 3/4);
+	qInfo->expire = mDNSPlatformTimeNow(m) + ((mDNSs32)pktData.lease * mDNSPlatformOneSecond);
+	qInfo->retry = qInfo->expire - ((mDNSs32)pktData.lease * mDNSPlatformOneSecond/2);
  
 	qInfo->origLease = pktData.lease;
 	qInfo->state = LLQ_Established;	
@@ -1222,19 +2490,22 @@ mDNSlocal void sendLLQRefresh(mDNS *m, DNSQuestion *q, mDNSu32 lease)
 	LLQOptData llq;
 	LLQ_Info *info = q->uDNS_info.llq;
 	mStatus err;
+	mDNSs32 timenow;
 
-	if (info->state == kLLQ_Refresh && info->ntries >= kLLQ_MAX_TRIES)
+	timenow = mDNSPlatformTimeNow(m);
+	if ((info->state == LLQ_Refresh && info->ntries >= kLLQ_MAX_TRIES) ||
+		info->expire - timenow < 0)
 		{
-		LogMsg("sendLLQRefresh - %d failed attempts for llq %s", info->ntries, q->qname.c);
+		LogMsg("Unable to refresh LLQ %##s - will retry in %d minutes", q->qname.c, kLLQ_DEF_RETRY/60);
 		info->state = LLQ_Retry;
-		info->retry = mDNSPlatformTimeNow() + kLLQ_DEF_RETRY * mDNSPlatformOneSecond;
+		info->retry = mDNSPlatformTimeNow(m) + 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.llqOp = kLLQOp_Refresh;
 	llq.err = LLQErr_NoError;
 	umemcpy(llq.id, info->id, 8);
 	llq.lease = lease;
@@ -1243,34 +2514,44 @@ mDNSlocal void sendLLQRefresh(mDNS *m, DNSQuestion *q, mDNSu32 lease)
 	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);
+	err = mDNSSendDNSMessage(m, &msg, end, mDNSInterface_Any, &info->servAddr, info->servPort, -1, mDNSNULL);
+	if (err) LogMsg("ERROR: sendLLQRefresh - mDNSSendDNSMessage returned %ld", err);
 
 	if (info->state == LLQ_Established) info->ntries = 1;
 	else info->ntries++;
 	info->state = LLQ_Refresh;
-	q->LastQTime = mDNSPlatformTimeNow();
+	q->LastQTime = timenow;
 	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)
+mDNSlocal mDNSBool recvLLQEvent(mDNS *m, DNSQuestion *q, DNSMessage *msg, const mDNSu8 *end, const mDNSAddr *srcaddr, mDNSIPPort srcport, mDNSInterfaceID InterfaceID)
 	{
 	DNSMessage ack;
 	mDNSu8 *ackEnd = ack.data;
 	mStatus err;
+	LLQOptData opt;
+	
+	(void)InterfaceID;  // unused
+
+    // find Opt RR, verify correct ID
+	if (!getLLQAtIndex(m, msg, end, &opt, 0)) { debugf("Pkt does not contain LLQ Opt"); return mDNSfalse; }
+	if (opt.llqOp != kLLQOp_Event) { LogMsg("recvLLQEvent - Bad LLQ Opcode %d", opt.llqOp); return mDNSfalse; }
+	if (!q->uDNS_info.llq) { LogMsg("Error: recvLLQEvent - question onject does not contain LLQ metadata"); return mDNSfalse; }
+	if (!sameID(opt.id, q->uDNS_info.llq->id)) { LogMsg("recvLLQEvent - incorrect ID. Discarding"); return mDNSfalse; }
 
     // invoke response handler
 	m->uDNS_info.CurrentQuery = q;
 	q->uDNS_info.responseCallback(m, msg, end, q, q->uDNS_info.context);
-	if (m->uDNS_info.CurrentQuery != q) return;
+	if (m->uDNS_info.CurrentQuery != q) return mDNStrue;
 	
     //  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);
-    }
+	if (!ackEnd) { LogMsg("ERROR: recvLLQEvent - putQuestion");  return mDNSfalse; }
+	err = mDNSSendDNSMessage(m, &ack, ackEnd, mDNSInterface_Any, srcaddr, srcport, -1, mDNSNULL); 
+	if (err) LogMsg("ERROR: recvLLQEvent - mDNSSendDNSMessage returned %ld", err);
+	return mDNStrue;
+	}
 
 
 
@@ -1280,13 +2561,14 @@ mDNSlocal void hndlChallengeResponseAck(mDNS *m, DNSMessage *pktMsg, const mDNSu
 	
 	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->expire = mDNSPlatformTimeNow(m) + ((mDNSs32)llq->lease * mDNSPlatformOneSecond);
+	info->retry = info->expire - ((mDNSs32)llq->lease * mDNSPlatformOneSecond / 2);
  
 	info->origLease = llq->lease;
 	info->state = LLQ_Established;	
+	
 	q->uDNS_info.responseCallback = llqResponseHndlr;
-	llqResponseHndlr(m, pktMsg, end, q, NULL);
+	llqResponseHndlr(m, pktMsg, end, q, mDNSNULL);
 	return;
 
 	error:
@@ -1300,11 +2582,11 @@ mDNSlocal void sendChallengeResponse(mDNS *m, DNSQuestion *q, LLQOptData *llq)
 	mDNSu8 *responsePtr = response.data;
 	mStatus err;
 	LLQOptData llqBuf;
-	mDNSs32 timenow = mDNSPlatformTimeNow();
+	mDNSs32 timenow = mDNSPlatformTimeNow(m);
 	
 	if (info->ntries++ == kLLQ_MAX_TRIES)
 		{
-		LogMsg("sendChallengeResponse: %d failed attempts for LLQ %s. Will re-try in %d minutes",
+		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);
@@ -1317,7 +2599,7 @@ mDNSlocal void sendChallengeResponse(mDNS *m, DNSQuestion *q, LLQOptData *llq)
 		{
 		llq = &llqBuf;
 		llq->vers    = kLLQ_Vers;
-		llq->llqOp   = kLLQ_Setup;
+		llq->llqOp   = kLLQOp_Setup;
 		llq->err     = LLQErr_NoError;
 		umemcpy(llq->id, info->id, 8);
 		llq->lease    = info->origLease;
@@ -1330,8 +2612,8 @@ mDNSlocal void sendChallengeResponse(mDNS *m, DNSQuestion *q, LLQOptData *llq)
 	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);
+	err = mDNSSendDNSMessage(m, &response, responsePtr, mDNSInterface_Any, &info->servAddr, info->servPort, -1, mDNSNULL);
+	if (err) LogMsg("ERROR: sendChallengeResponse - mDNSSendDNSMessage returned %ld", err);
 	// on error, we procede as normal and retry after the appropriate interval
 
 	return;
@@ -1345,43 +2627,43 @@ mDNSlocal void sendChallengeResponse(mDNS *m, DNSQuestion *q, LLQOptData *llq)
 mDNSlocal void hndlRequestChallenge(mDNS *m, DNSMessage *pktMsg, const mDNSu8 *end, LLQOptData *llq, DNSQuestion *q)
 	{
 	LLQ_Info *info = q->uDNS_info.llq;
-	mDNSs32 timenow = mDNSPlatformTimeNow();
+	mDNSs32 timenow = mDNSPlatformTimeNow(m);
 	switch(llq->err)
 		{
 		case LLQErr_NoError: break;
 		case LLQErr_ServFull:
-			LogMsg("hndlRequestChallenge - received ServFull from server for LLQ %s.  Retry in %d sec", q->qname.c, llq->lease);
+			LogMsg("hndlRequestChallenge - received ServFull from server for LLQ %##s.  Retry in %lu sec", q->qname.c, llq->lease);
 			info->retry = timenow + ((mDNSs32)llq->lease * mDNSPlatformOneSecond);
 			info->state = LLQ_Retry;
-			simpleResponseHndlr(m, pktMsg, end, q, NULL);  // get available answers
+			simpleResponseHndlr(m, pktMsg, end, q, mDNSNULL);  // get available answers
 			info->deriveRemovesOnResume = mDNStrue;
 		case LLQErr_Static:
 			info->state = LLQ_Static;
-			LogMsg("LLQ %s: static", q->qname.c);
-			simpleResponseHndlr(m, pktMsg, end, q, NULL);
+			LogMsg("LLQ %##s: static", q->qname.c);
+			simpleResponseHndlr(m, pktMsg, end, q, mDNSNULL);
 			return;
 		case LLQErr_FormErr:
-			LogMsg("ERROR: hndlRequestChallenge - received FormErr from server for LLQ %s", q->qname.c);
+			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);
+			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);
+			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);
+		LogMsg("hndlRequestChallenge: requested lease %lu, granted lease %lu", info->origLease, llq->lease);
 
 	// cache expiration in case we go to sleep before finishing setup
 	info->origLease = llq->lease;
 	info->expire = timenow + ((mDNSs32)llq->lease * mDNSPlatformOneSecond);
 
-	// update state and timestamp
+	// update state
 	info->state = LLQ_SecondaryRequest;
 	umemcpy(info->id, llq->id, 8);
 	info->ntries = 0; // first attempt to send response
@@ -1406,58 +2688,61 @@ mDNSlocal void recvSetupResponse(mDNS *m, DNSMessage *pktMsg, const mDNSu8 *end,
 
 	(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;
-		}
+	if (rcode && rcode != kDNSFlag1_RC_NXDomain) goto poll;
 	
 	ptr = getQuestion(pktMsg, ptr, end, 0, &pktQuestion);
-	if (!ptr) { LogMsg("ERROR: recvSetupResponse - getQuestion"); goto error; }
+	if (!ptr) { LogMsg("ERROR: recvSetupResponse - getQuestion"); goto poll; }
 	if (!SameDomainName(&q->qname, &pktQuestion.qname))
-		{ LogMsg("ERROR: recvSetupResponse - mismatched question in response for llq setup %s", q->qname.c);   goto error; }
+		{ LogMsg("ERROR: recvSetupResponse - mismatched question in response for llq setup %##s", q->qname.c);   goto poll; }
 
-	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 (!getLLQAtIndex(m, pktMsg, end, &llq, 0)) { debugf("recvSetupResponse - GetLLQAtIndex"); goto poll; }
+	if (llq.llqOp != kLLQOp_Setup) { LogMsg("ERROR: recvSetupResponse - bad op %d", llq.llqOp); goto poll; } 
+	if (llq.vers != kLLQ_Vers) { LogMsg("ERROR: recvSetupResponse - bad vers %d", llq.vers);  goto poll; } 
 
 	if (info->state == LLQ_InitialRequest) { hndlRequestChallenge(m, pktMsg, end, &llq, q); return; }
 	if (info->state == LLQ_SecondaryRequest) { hndlChallengeResponseAck(m, pktMsg, end, &llq, q); return; }
 	LogMsg("recvSetupResponse - bad state %d", info->state);
 
-
-	error:
-	info->state = LLQ_Error;
+	poll:
+	info->state = LLQ_Poll;
+	q->uDNS_info.responseCallback = llqResponseHndlr;
+	info->question->LastQTime = mDNSPlatformTimeNow(m) - (2 * INIT_UCAST_POLL_INTERVAL);  // trigger immediate poll
+	info->question->ThisQInterval = INIT_UCAST_POLL_INTERVAL;
 	}
 
-
-
-mDNSlocal void startLLQHandshake(mDNS *m, LLQ_Info *info)
+mDNSlocal void startLLQHandshake(mDNS *m, LLQ_Info *info, mDNSBool defer)
 	{
 	DNSMessage msg;
 	mDNSu8 *end;
 	LLQOptData llqData;
 	DNSQuestion *q = info->question; 
-	mStatus err;
-	mDNSs32 timenow = mDNSPlatformTimeNow();
+	mStatus err = mStatus_NoError;
+	mDNSs32 timenow = mDNSPlatformTimeNow(m);
+	uDNS_GlobalInfo *u = &m->uDNS_info;
 	
-	if (info->ntries++ == kLLQ_MAX_TRIES)
+	if (IsPrivateV4Addr(&u->PrimaryIP))
 		{
-		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;
+		if (!u->LLQNatInfo)
+			{
+			info->state = LLQ_NatMapWait;
+			StartLLQNatMap(m);
+			return;
+			}
+		if (u->LLQNatInfo->state == NATState_Error) goto poll;		
+		if (u->LLQNatInfo->state != NATState_Established && u->LLQNatInfo->state != NATState_Legacy)
+			{ info->state = LLQ_NatMapWait; info->NATMap = mDNStrue; return; }
+		info->NATMap = mDNStrue;  // this llq references the global llq nat mapping
+		}
+	
+	if (info->ntries++ >= kLLQ_MAX_TRIES)
+		{
+		debugf("startLLQHandshake: %d failed attempts for LLQ %##s.  Polling.", kLLQ_MAX_TRIES, q->qname.c, kLLQ_DEF_RETRY / 60);
+		goto poll;
 		}	
 	
     // set llq rdata
 	llqData.vers    = kLLQ_Vers;
-	llqData.llqOp   = kLLQ_Setup;
+	llqData.llqOp   = kLLQOp_Setup;
 	llqData.err     = LLQErr_NoError;
 	ubzero(llqData.id, 8);
 	llqData.lease    = kLLQ_DefLease;
@@ -1471,10 +2756,13 @@ mDNSlocal void startLLQHandshake(mDNS *m, LLQ_Info *info)
 		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
-
+	if (!defer) // if we are to defer, we simply set the retry timers so the request goes out in the future
+		{
+		err = mDNSSendDNSMessage(m, &msg, end, mDNSInterface_Any, &info->servAddr, info->servPort, -1, mDNSNULL);
+		if (err) LogMsg("ERROR: startLLQHandshake - mDNSSendDNSMessage returned %ld", 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;
@@ -1482,44 +2770,67 @@ mDNSlocal void startLLQHandshake(mDNS *m, LLQ_Info *info)
 	q->LastQTime = timenow;
 	q->uDNS_info.responseCallback = recvSetupResponse;
 	q->uDNS_info.internal = mDNStrue;
+	return;
+
+	poll:
+	info->question->uDNS_info.responseCallback = llqResponseHndlr;
+	info->state = LLQ_Poll;
+	info->question->LastQTime = mDNSPlatformTimeNow(m) - (2 * INIT_UCAST_POLL_INTERVAL);  // trigger immediate poll
+	info->question->ThisQInterval = INIT_UCAST_POLL_INTERVAL;
 	}
 
 // wrapper for startLLQHandshake, invoked by async op callback
 mDNSlocal void startLLQHandshakeCallback(mStatus err, mDNS *const m, void *llqInfo, const AsyncOpResult *result)
 	{
 	LLQ_Info *info = (LLQ_Info *)llqInfo;
-	const zoneData_t *zoneInfo = &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;
-		}
-
+	const zoneData_t *zoneInfo = mDNSNULL;
+	
+    // check state first to make sure it is OK to touch question object
 	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
+		debugf("startLLQHandshake - LLQ Cancelled.");
+		info->question = mDNSNULL;  // question may be deallocated
 		ufree(info);
 		return;
 		}
 
+	if (!info->question)
+		{ LogMsg("ERROR: startLLQHandshakeCallback invoked with NULL question"); goto error; }
+
 	if (info->state != LLQ_GetZoneInfo)
-		{
-		LogMsg("ERROR: startLLQHandshake - bad state %d", info->state);
-		return;
-		}
+		{ LogMsg("ERROR: startLLQHandshake - bad state %d", info->state); goto error; }
+
+	if (err)
+		{ LogMsg("ERROR: startLLQHandshakeCallback invoked with error code %ld", err); goto poll; }
+
+	if (!result)
+		{ LogMsg("ERROR: startLLQHandshakeCallback invoked with NULL result and no error code"); goto error; }
 	
+	zoneInfo = &result->zoneData;
+
+	if (!zoneInfo->llqPort.NotAnInteger)
+		{ debugf("LLQ port lookup failed - reverting to polling"); goto poll; }
+		
     // 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);
+
+	if (info->state == LLQ_SuspendDeferred) info->state = LLQ_Suspended;
+	else startLLQHandshake(m, info, mDNSfalse);
+	return;
+
+	poll:
+	info->question->uDNS_info.responseCallback = llqResponseHndlr;
+	info->state = LLQ_Poll;
+	info->question->LastQTime = mDNSPlatformTimeNow(m) - (2 * INIT_UCAST_POLL_INTERVAL);  // trigger immediate poll
+	info->question->ThisQInterval = INIT_UCAST_POLL_INTERVAL;
+	return;
+
+	error:
+	info->state = LLQ_Error;
 	}
 
 mDNSlocal mStatus startLLQ(mDNS *m, DNSQuestion *question)
@@ -1542,10 +2853,10 @@ mDNSlocal mStatus startLLQ(mDNS *m, DNSQuestion *question)
 	err = startGetZoneData(&question->qname, m, mDNSfalse, mDNStrue, startLLQHandshakeCallback, info);
     if (err)
 		{
-		LogMsg("ERROR: startLLQ - startGetZoneData returned %d", err);
-		info->question = NULL;
+		LogMsg("ERROR: startLLQ - startGetZoneData returned %ld", err);
+		info->question = mDNSNULL;
 		ufree(info);
-		question->uDNS_info.llq = NULL;
+		question->uDNS_info.llq = mDNSNULL;
 		return err;
 		}
 
@@ -1559,15 +2870,13 @@ mDNSlocal mDNSBool recvLLQResponse(mDNS *m, DNSMessage *msg, const mDNSu8 *end,
 	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)
 		{
@@ -1580,20 +2889,24 @@ mDNSlocal mDNSBool recvLLQResponse(mDNS *m, DNSMessage *msg, const mDNSu8 *end,
 			{
 			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; }			
+				{ if (recvLLQEvent(m, q, msg, end, srcaddr, srcport, InterfaceID)) return mDNStrue; }
+			else if (msg->h.id.NotAnInteger == q->uDNS_info.id.NotAnInteger)
+				{
+				if (llqInfo->state == LLQ_Refresh && msg->h.numAdditionals && !msg->h.numAnswers)
+					{ recvRefreshReply(m, msg, end, q); return mDNStrue; }
+				if (llqInfo->state < LLQ_Static)
+					{
+					if ((llqInfo->state != LLQ_InitialRequest && llqInfo->state != LLQ_SecondaryRequest) || mDNSSameAddress(srcaddr, &llqInfo->servAddr))
+						{ q->uDNS_info.responseCallback(m, msg, end, q, q->uDNS_info.context); return mDNStrue; }
+					}
+				}
 			}
 		q = q->next;
 		}
 	return mDNSfalse;
 	}
 
-mDNSexport mDNSBool IsActiveUnicastQuery(DNSQuestion *const question, uDNS_GlobalInfo *u)
+mDNSexport mDNSBool uDNS_IsActiveQuery(DNSQuestion *const question, uDNS_GlobalInfo *u)
     {
 	DNSQuestion *q;
 
@@ -1601,8 +2914,8 @@ mDNSexport mDNSBool IsActiveUnicastQuery(DNSQuestion *const question, uDNS_Globa
 		{
 		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",
+			if (!question->uDNS_info.id.NotAnInteger || question->InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(&question->qname))
+				LogMsg("Warning: Question %##s in Active Unicast Query list with id %d, interfaceID %p",
 					   question->qname.c, question->uDNS_info.id.NotAnInteger, question->InterfaceID);
 			return mDNStrue;
 			}
@@ -1612,7 +2925,7 @@ mDNSexport mDNSBool IsActiveUnicastQuery(DNSQuestion *const question, uDNS_Globa
 
 // stopLLQ happens IN ADDITION to stopQuery
 mDNSlocal void stopLLQ(mDNS *m, DNSQuestion *question)
-	{	
+	{
 	LLQ_Info *info = question->uDNS_info.llq;
 	(void)m;  // unused
 
@@ -1626,30 +2939,33 @@ mDNSlocal void stopLLQ(mDNS *m, DNSQuestion *question)
 			//!!!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
+		case LLQ_SuspendDeferred:		
+			info->question = mDNSNULL; // remove ref to question, as it may be freed when we get called back from async op
 			info->state = LLQ_Cancelled;
 			return;			
 		case LLQ_Established:
 		case LLQ_Refresh:
 			// refresh w/ lease 0
 			sendLLQRefresh(m, question, 0);
-			goto free_info;	
+			goto end;	
 		default:			
 			debugf("stopLLQ - silently discarding LLQ in state %d", info->state);				
-			goto free_info;
+			goto end;
 		}
 	
-	free_info:
-	info->question = NULL;
+	end:
+	if (info->NATMap) info->NATMap = mDNSfalse;
+	CheckForUnreferencedLLQMapping(m);
+	info->question = mDNSNULL;
 	ufree(info);
-	question->uDNS_info.llq = NULL;
-	
+	question->uDNS_info.llq = mDNSNULL;
+	question->LongLived = mDNSfalse;
 	}
 
 mDNSexport mStatus uDNS_StopQuery(mDNS *const m, DNSQuestion *const question)
 	{
 	uDNS_GlobalInfo *u = &m->uDNS_info;
-	DNSQuestion *qptr, *prev = NULL;
+	DNSQuestion *qptr, *prev = mDNSNULL;
 	CacheRecord *ka;
 	
 	qptr = u->ActiveQueries;
@@ -1674,93 +2990,58 @@ mDNSexport mStatus uDNS_StopQuery(mDNS *const m, DNSQuestion *const question)
         prev = qptr;
 		qptr = qptr->next;
         }
-    LogMsg("uDNS_StopQuery: no such active query (%s)", question->qname.c);
+    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;
+	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));
+		LogMsg("Attempt to start query with invalid qname %##s %##s", question->qname.c, DNSTypeName(question->qtype));
 		return mStatus_Invalid;
 		}
 		
-	question->next = NULL;
+	question->next = mDNSNULL;
 	question->qnamehash = DomainNameHashValue(&question->qname);    // to do quick domain name comparisons
     question->uDNS_info.id = newMessageID(u);
+	question->uDNS_info.Answered = mDNSfalse;
 	
 	// break here if its and LLQ
 	if (question->LongLived) return startLLQ(m, question);
 
+	// else send the query to our server
 	err = constructQueryMsg(&msg, &endPtr, question);
 	if (err) return err;
 
-	// else send the query to our server
-
-	question->LastQTime = mDNSPlatformTimeNow();
+	question->LastQTime = mDNSPlatformTimeNow(m);
 	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); }
+	question->uDNS_info.knownAnswers = mDNSNULL;
+	if (GetServerForName(u, &question->qname, &server))
+		{
+		err = mDNSSendDNSMessage(m, &msg, endPtr, mDNSInterface_Any, &server, UnicastDNSPort, -1, mDNSNULL);
+		if (err) { debugf("ERROR: startQuery - %ld (keeping question in list for retransmission", err); }
+		}
 
-	return err;
+	return mStatus_NoError;  // don't return transient errors to caller
 	}
 	
 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;
+	question->uDNS_info.context = mDNSNULL;
+	//LogOperation("uDNS_StartQuery %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
 	return startQuery(m, question, 0);
     }
 
@@ -1784,17 +3065,17 @@ mDNSlocal mStatus startInternalQuery(DNSQuestion *q, mDNS *m, InternalResponseHn
 
 /* startGetZoneData
  *
- * asyncronously find the address of the nameserver for the enclosing zone for a given domain name,
+ * Asynchronously find the address of the nameserver for the enclosing zone for a given domain name,
  * i.e. the server to which update and LLQ requests will be sent for a given name.  Once the address is
  * derived, it will be passed to the callback, along with a context pointer.  If the zone cannot
  * be determined or if an error occurs, an all-zeros address will be passed and a message will be
  * written to the syslog.
  *
  * If the FindUpdatePort arg is set, the port on which the server accepts dynamic updates is determined
- * by querying for the _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.
+ * by querying for the _dns-update._udp.<zone>. SRV record.  Likewise, if the FindLLQPort arg is set,
+ * the port on which the server accepts long lived queries is determined by querying for
+ * _dns-llq._udp.<zone>. record.  If either of these queries fail, or flags are not specified,
+ * the llqPort and updatePort fields in the result structure are set to zero.
  *
  *  Steps for deriving the zone name are as follows:
  *
@@ -1878,14 +3159,14 @@ mDNSlocal mStatus startGetZoneData(domainname *name, mDNS *m, mDNSBool findUpdat
     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);
+    AssignDomainName(context->origName, *name);
     context->state = init;
     context->m = m;
 	context->callback = callback;
 	context->callbackInfo = callbackInfo;
 	context->findUpdatePort = findUpdatePort;
 	context->findLLQPort = findLLQPort;
-    getZoneData(m, NULL, NULL, NULL, context);
+    getZoneData(m, mDNSNULL, mDNSNULL, mDNSNULL, context);
     return mStatus_NoError;
     }
 
@@ -1955,7 +3236,7 @@ mDNSlocal void getZoneData(mDNS *const m, DNSMessage *msg, const mDNSu8 *end, DN
 	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);
+	AssignDomainName(result.zoneData.zoneName, context->zone);
 	result.zoneData.zoneClass = context->zoneClass;
 	result.zoneData.llqPort    = context->findLLQPort    ? context->llqPort    : zeroIPPort;
 	result.zoneData.updatePort = context->findUpdatePort ? context->updatePort : zeroIPPort;
@@ -1964,7 +3245,7 @@ mDNSlocal void getZoneData(mDNS *const m, DNSMessage *msg, const mDNSu8 *end, DN
 			
 error:
 	if (context && context->callback)
-		context->callback(mStatus_UnknownErr, context->m, context->callbackInfo, NULL);	
+		context->callback(mStatus_UnknownErr, context->m, context->callbackInfo, mDNSNULL);	
 cleanup:
 	if (context && context->questionActive)
 		{
@@ -2014,7 +3295,7 @@ mDNSlocal smAction hndlLookupSOA(DNSMessage *msg, const mDNSu8 *end, ntaContext
     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", 
+        LogMsg("ERROR: hndlLookupSOA - recursed to root label of %##s without finding SOA", 
                 context->origName.c);
 		return smError;
         }
@@ -2025,21 +3306,21 @@ mDNSlocal smAction hndlLookupSOA(DNSMessage *msg, const mDNSu8 *end, ntaContext
     else                         context->curSOA = (domainname *)(context->curSOA->c + context->curSOA->c[0]+1);
     
     context->state = lookupSOA;
-    ustrcpy(query->qname.c, context->curSOA->c);
+    AssignDomainName(query->qname, *context->curSOA);
     query->qtype = kDNSType_SOA;
     query->qclass = kDNSClass_IN;
     err = startInternalQuery(query, context->m, getZoneData, context);
 	context->questionActive = mDNStrue;
-	if (err) LogMsg("hndlLookupSOA: startInternalQuery returned error %d (breaking until next periodic retransmission)", err);
+	if (err) LogMsg("hndlLookupSOA: startInternalQuery returned error %ld (breaking until next periodic retransmission)", err);
 
     return smBreak;     // break from state machine until we receive another packet	
     }
 
 mDNSlocal void processSOA(ntaContext *context, ResourceRecord *rr)
 	{
-	ustrcpy(context->zone.c, rr->name.c);
+	AssignDomainName(context->zone, rr->name);
 	context->zoneClass = rr->rrclass;
-	ustrcpy(context->ns.c, rr->rdata->u.soa.mname.c);
+	AssignDomainName(context->ns, rr->rdata->u.soa.mname);
 	context->state = foundZone;
 	}
 
@@ -2049,19 +3330,19 @@ mDNSlocal smAction confirmNS(DNSMessage *msg, const mDNSu8 *end, ntaContext *con
 	DNSQuestion *query = &context->question;
 	mStatus err;
 	LargeCacheRecord lcr;
-	ResourceRecord *rr = &lcr.r.resrec;
+	const ResourceRecord *const rr = &lcr.r.resrec;
 	const mDNSu8 *ptr;
 	int i;
 		
 	if (context->state == foundZone)
 		{
 		// we've just learned the zone.  confirm that an NS record exists
-		ustrcpy(query->qname.c, context->zone.c);
+		AssignDomainName(query->qname, context->zone);
 		query->qtype = kDNSType_NS;
 		query->qclass = kDNSClass_IN;
 		err = startInternalQuery(query, context->m, getZoneData, context);
 		context->questionActive = mDNStrue;	   
-		if (err) LogMsg("confirmNS: startInternalQuery returned error %d (breaking until next periodic retransmission", err);
+		if (err) LogMsg("confirmNS: startInternalQuery returned error %ld (breaking until next periodic retransmission", err);
 		context->state = lookupNS;
 		return smBreak;  // break from SM until we receive another packet
 		}
@@ -2079,7 +3360,7 @@ mDNSlocal smAction confirmNS(DNSMessage *msg, const mDNSu8 *end, ntaContext *con
 				return smContinue;  // next routine will examine additionals section of A record				
 				}				
 			}
-		LogMsg("ERROR: could not confirm existance of NS record %s", context->zone.c);
+		LogMsg("ERROR: could not confirm existence of record %##s NS %##s", context->zone.c, context->ns.c);
 		return smError;
 		}
 	else { LogMsg("ERROR: confirmNS - bad state %d", context->state); return smError; }
@@ -2090,12 +3371,12 @@ mDNSlocal smAction queryNSAddr(ntaContext *context)
 	mStatus err;
 	DNSQuestion *query = &context->question;
 	
-	ustrcpy(query->qname.c, context->ns.c);
+	AssignDomainName(query->qname, context->ns);
 	query->qtype = kDNSType_A;
 	query->qclass = kDNSClass_IN;
 	err = startInternalQuery(query, context->m, getZoneData, context);
 	context->questionActive = mDNStrue;	
-	if (err) LogMsg("confirmNS: startInternalQuery returned error %d (breaking until next periodic retransmission)", err);
+	if (err) LogMsg("confirmNS: startInternalQuery returned error %ld (breaking until next periodic retransmission)", err);
 	context->state = lookupA;
 	return smBreak;
 	}
@@ -2129,7 +3410,7 @@ mDNSlocal smAction lookupNSAddr(DNSMessage *msg, const mDNSu8 *end, ntaContext *
 					}
 				if (rr->rrtype == kDNSType_A && SameDomainName(&context->ns, &rr->name))
 					{
-					context->addr.NotAnInteger = rr->rdata->u.ip.NotAnInteger;
+					context->addr.NotAnInteger = rr->rdata->u.ipv4.NotAnInteger;
 					context->state = foundA;
 					return smContinue;
 					}
@@ -2148,7 +3429,7 @@ mDNSlocal smAction lookupNSAddr(DNSMessage *msg, const mDNSu8 *end, ntaContext *
 			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->addr.NotAnInteger = rr->rdata->u.ipv4.NotAnInteger;
 				context->state = foundA;
 				return smContinue;
 				}
@@ -2182,8 +3463,8 @@ mDNSlocal smAction lookupDNSPort(DNSMessage *msg, const mDNSu8 *end, ntaContext
 				return smContinue;
 				}
 			}
-		LogMsg("hndlLookupUpdatePort %s - answer not contained in reply.  Guessing port %d", portName, UnicastDNSPort);
-		*port = UnicastDNSPort;
+		debugf("hndlLookupUpdatePort - no answer for type %s", portName);
+		port->NotAnInteger = 0;
 		context->state = foundPort;
 		return smContinue;
 		}
@@ -2192,12 +3473,12 @@ mDNSlocal smAction lookupDNSPort(DNSMessage *msg, const mDNSu8 *end, ntaContext
 	context->state = lookupPort;
 	q = &context->question;
 	MakeDomainNameFromDNSNameString(&q->qname, portName);
-	ustrcpy((q->qname.c + ustrlen(q->qname.c)), context->zone.c);
+	AppendDomainName(&q->qname, &context->zone);
     q->qtype = kDNSType_SRV;
     q->qclass = kDNSClass_IN;
     err = startInternalQuery(q, context->m, getZoneData, context);
 	context->questionActive = mDNStrue;
-    if (err) LogMsg("hndlLookupSOA: startInternalQuery returned error %d (breaking until next periodic retransmission)", err);
+    if (err) LogMsg("hndlLookupSOA: startInternalQuery returned error %ld (breaking until next periodic retransmission)", err);
     return smBreak;     // break from state machine until we receive another packet	
 	}
 
@@ -2241,18 +3522,19 @@ mDNSlocal void conQueryCallback(int sd, void *context, mDNSBool ConnectionEstabl
 	tcpInfo_t *info = (tcpInfo_t *)context;
 	DNSQuestion *question = info->question;
 	int n;
+	mDNS *m = info->m;
 
-	question->uDNS_info.id.NotAnInteger = (mDNSu16)~0;
-
+	mDNS_Lock(m);
+	
 	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;
+		if (err) { LogMsg("ERROR: conQueryCallback: constructQueryMsg - %ld", err);  goto error; }
+		err = mDNSSendDNSMessage(m, msg, end, mDNSInterface_Any, &zeroAddr, zeroIPPort, sd, mDNSNULL);
+		question->LastQTime = mDNSPlatformTimeNow(m);
+		if (err) { LogMsg("ERROR: conQueryCallback: mDNSSendDNSMessage_tcp - %ld", err);  goto error; }
 		}
 	else
 		{
@@ -2272,18 +3554,19 @@ mDNSlocal void conQueryCallback(int sd, void *context, mDNSBool ConnectionEstabl
 		if (info->nread == info->replylen)
 			{
 			// finished reading message
-			receiveMsg(info->m, &info->reply, ((mDNSu8 *)&info->reply) + info->replylen, question->InterfaceID);
+			uDNS_ReceiveMsg(m, &info->reply, ((mDNSu8 *)&info->reply) + info->replylen, mDNSNULL, zeroIPPort, mDNSNULL, zeroIPPort, question->InterfaceID);
 			mDNSPlatformTCPCloseConnection(sd);
 			ufree(info);
-			return;
 			}
-		else return;
 		}
+
+	mDNS_Unlock(m);
 	return;
 
 	error:
 	mDNSPlatformTCPCloseConnection(sd);
 	ufree(info);
+	mDNS_Unlock(m);
 	}
 
 mDNSlocal void hndlTruncatedAnswer(DNSQuestion *question, const  mDNSAddr *src, mDNS *m)
@@ -2292,23 +3575,23 @@ mDNSlocal void hndlTruncatedAnswer(DNSQuestion *question, const  mDNSAddr *src,
 	uDNS_QuestionInfo *info = &question->uDNS_info;
 	int sd;
 	tcpInfo_t *context;
+	
+	if (!src) { LogMsg("hndlTruncatedAnswer: TCP DNS response had TC bit set: ignoring"); return; }
 
 	context = (tcpInfo_t *)umalloc(sizeof(tcpInfo_t));
 	if (!context) { LogMsg("ERROR: hndlTruncatedAnswer - memallocate failed"); return; }
 	ubzero(context, sizeof(tcpInfo_t));
 	context->question = question;
 	context->m = m;
-
-	info->id.NotAnInteger = (mDNSu16)~0;             // all 1's indicates TCP queries
-	info->timestamp = mDNSPlatformTimeNow();         // reset timestamp
+	info->id = newMessageID(&m->uDNS_info);
 
 	connectionStatus = mDNSPlatformTCPConnect(src, UnicastDNSPort, question->InterfaceID, conQueryCallback, context, &sd);
-	if (connectionStatus == mStatus_ConnectionEstablished)  // manually invoke callback if connection completes
+	if (connectionStatus == mStatus_ConnEstablished)  // manually invoke callback if connection completes
 		{
 		conQueryCallback(sd, context, mDNStrue);
 		return;
 		}
-	if (connectionStatus == mStatus_ConnectionPending) return; // callback will be automatically invoked when connection completes
+	if (connectionStatus == mStatus_ConnPending) return; // callback will be automatically invoked when connection completes
 	LogMsg("hndlTruncatedAnswer: connection failed");
 	uDNS_StopQuery(m, question);  //!!!KRS can we really call this here?
 	}
@@ -2320,68 +3603,6 @@ mDNSlocal void hndlTruncatedAnswer(DNSQuestion *question, const  mDNSAddr *src,
 #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)
 	{
@@ -2390,7 +3611,6 @@ mDNSlocal void sendRecordRegistration(mDNS *const m, AuthRecord *rr)
 	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;
 
@@ -2403,67 +3623,68 @@ mDNSlocal void sendRecordRegistration(mDNS *const m, AuthRecord *rr)
 	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);
+	    ptr = PutResourceRecordTTLJumbo(&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);
+	ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numUpdates, &rr->resrec, rr->resrec.rroriginalttl);
 	if (!ptr) goto error;
 
 	if (rr->uDNS_info.lease)
-		ptr = putUpdateLease(&msg, ptr);
+		{ ptr = putUpdateLease(&msg, ptr, kLLQ_DefLease); if (!ptr) goto error; }
 	   
 	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; }
-		}
+	err = mDNSSendDNSMessage(m, &msg, ptr, mDNSInterface_Any, &regInfo->ns, regInfo->port, -1, GetAuthInfoForZone(u, &regInfo->zone));
+	if (err) LogMsg("ERROR: sendRecordRegistration - mDNSSendDNSMessage - %ld", err);
 
+	SetRecordRetry(m, rr);
+	
 	if (regInfo->state != regState_Refresh) regInfo->state = regState_Pending;
 	return;
 
 error:
+	LogMsg("sendRecordRegistration: Error formatting message");
 	if (rr->uDNS_info.state != regState_Unregistered)
 		{
 		unlinkAR(&u->RecordRegistrations, rr);
 		rr->uDNS_info.state = regState_Unregistered;
 		}
-	rr->RecordCallback(m, rr, err);
+	m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
+	if (rr->RecordCallback) rr->RecordCallback(m, rr, err);
+	m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
 	// NOTE: not safe to touch any client structures here	
 	}
 
 mDNSlocal void RecordRegistrationCallback(mStatus err, mDNS *const m, void *authPtr, const AsyncOpResult *result)	
 	{
 	AuthRecord *newRR = (AuthRecord*)authPtr;
-	const zoneData_t *zoneData = &result->zoneData;
+	const zoneData_t *zoneData = mDNSNULL;
 	uDNS_GlobalInfo *u = &m->uDNS_info;
 	AuthRecord *ptr;
 
+	// make sure record is still in list
 	for (ptr = u->RecordRegistrations; ptr; ptr = ptr->next)
 		if (ptr == newRR) break;
 	if (!ptr) { LogMsg("RecordRegistrationCallback - RR no longer in list.  Discarding."); return; }		
-	
-	if (err) { LogMsg("RecordRegistrationCallback: error %d", err); goto error; }
+
+	// check error/result
+	if (err) { LogMsg("RecordRegistrationCallback: error %ld", err); goto error; }
+	if (!result) { LogMsg("ERROR: RecordRegistrationCallback invoked with NULL result and no error"); goto error;  }
+	else zoneData = &result->zoneData;
+
 	if (newRR->uDNS_info.state == regState_Cancelled)
 		{
 		//!!!KRS we should send a memfree callback here!
-		LogMsg("Registration of %s type %d cancelled prior to update",
+		debugf("Registration of %##s type %d cancelled prior to update",
 			   newRR->resrec.name.c, newRR->resrec.rrtype);
 		newRR->uDNS_info.state = regState_Unregistered;
 		unlinkAR(&u->RecordRegistrations, newRR);
@@ -2484,10 +3705,16 @@ mDNSlocal void RecordRegistrationCallback(mStatus err, mDNS *const m, void *auth
 		}	
 	
 	// cache zone data
-	ustrcpy(newRR->uDNS_info.zone.c, zoneData->zoneName.c);
+	AssignDomainName(newRR->uDNS_info.zone, zoneData->zoneName);
     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;
+	if (zoneData->updatePort.NotAnInteger) newRR->uDNS_info.port = zoneData->updatePort;
+	else
+		{
+		debugf("Update port not advertised via SRV - guessing port 53, no lease option");
+		newRR->uDNS_info.port = UnicastDNSPort;
+		newRR->uDNS_info.lease = mDNSfalse;
+		}
 
 	sendRecordRegistration(m, newRR);
 	return;
@@ -2498,39 +3725,13 @@ error:
 		unlinkAR(&u->RecordRegistrations, newRR);
 		newRR->uDNS_info.state = regState_Unregistered;
 		}
-	newRR->RecordCallback(m, newRR, err);
+	m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
+	if (newRR->RecordCallback)
+		newRR->RecordCallback(m, newRR, err);
+	m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
 	// NOTE: not safe to touch any client structures here
 	}
 
-
-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;
@@ -2538,71 +3739,93 @@ mDNSlocal void SendServiceRegistration(mDNS *m, ServiceRecordSet *srs)
 	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;
+	mDNSIPPort privport;
+	NATTraversalInfo *nat = srs->uDNS_info.NATinfo;
+	mDNSBool mapped = mDNSfalse;
+	domainname target;
+	AuthRecord *srv = &srs->RR_SRV;
 	
 	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_PTR.resrec, mDNSNULL, 0);	
+	SetNewRData(&srs->RR_TXT.resrec, mDNSNULL, 0);
 	
-	//SetNewRData(&srs->RR_ADV.resrec, NULL, 0); //!!!KRS
-	SetNewRData(&srs->RR_PTR.resrec, NULL, 0);	
-	SetNewRData(&srs->RR_TXT.resrec, NULL, 0);
+	// replace port w/ NAT mapping if necessary
+ 	if (nat && nat->PublicPort.NotAnInteger &&
+		(nat->state == NATState_Established || nat->state == NATState_Refresh || nat->state == NATState_Legacy))
+		{
+		privport = srv->resrec.rdata->u.srv.port;
+		srv->resrec.rdata->u.srv.port = nat->PublicPort;
+		mapped = mDNStrue;
+		}
 	
 	// construct update packet
     // set zone
-	ptr = putZone(&msg, ptr, end, &rInfo->zone, mDNSOpaque16fromIntVal(srs->RR_SRV.resrec.rrclass));
+	ptr = putZone(&msg, ptr, end, &rInfo->zone, mDNSOpaque16fromIntVal(srv->resrec.rrclass));
 	if (!ptr) goto error;
-
-	if (srs->uDNS_info.state == regState_Refresh)
+	
+	if (srs->uDNS_info.TestForSelfConflict)
 		{
-		// 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;
+		// update w/ prereq that records already exist to make sure previous registration was ours
+		if (!(ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numPrereqs, &srs->RR_SRV.resrec, 0))) goto error;
+		if (!(ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numPrereqs, &srs->RR_TXT.resrec, 0))) goto error;
 		}
-	else
+	
+	else if (srs->uDNS_info.state != regState_Refresh)
 		{
-		// use SRV for prereq
-		ptr = putPrereqNameNotInUse(&srs->RR_SRV.resrec.name, &msg, ptr, end);
+		// use SRV name for prereq
+		ptr = putPrereqNameNotInUse(&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 (!(ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numUpdates, &srs->RR_PTR.resrec, srs->RR_PTR.resrec.rroriginalttl))) goto error;
+	if (!(ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numUpdates, &srs->RR_TXT.resrec, srs->RR_TXT.resrec.rroriginalttl))) goto error;
+
+	 if (!GetServiceTarget(u, srv, &target))
+		{
+		debugf("Couldn't get target for service %##s", srv->resrec.name.c);
+		rInfo->state = regState_NoTarget;		
+		return;
+		}	
+	if (!SameDomainName(&target, &srv->resrec.rdata->u.srv.target))
+		{
+		AssignDomainName(srv->resrec.rdata->u.srv.target, target);
+		SetNewRData(&srv->resrec, mDNSNULL, 0);
+		}
+
+	ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numUpdates, &srv->resrec, srv->resrec.rroriginalttl);
+	if (!ptr) goto error;
+	// !!!KRS do subtypes/extras etc.
 
 	if (srs->uDNS_info.lease)
-		ptr = putUpdateLease(&msg, ptr);
+		{ ptr = putUpdateLease(&msg, ptr, kLLQ_DefLease); if (!ptr) goto error; }
 	   
 	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; }
-		}
+	err = mDNSSendDNSMessage(m, &msg, ptr, mDNSInterface_Any, &rInfo->ns, rInfo->port, -1, GetAuthInfoForZone(u, &rInfo->zone));
+	if (err) { LogMsg("ERROR: SendServiceRegistration - mDNSSendDNSMessage - %ld", err); goto error; }
+
 	if (rInfo->state != regState_Refresh)
 		rInfo->state = regState_Pending;
+
+	SetRecordRetry(m, &srs->RR_SRV);
+	rInfo->id.NotAnInteger = id.NotAnInteger;
+	if (mapped) srv->resrec.rdata->u.srv.port = privport;
 	return;
 
 error:
+	LogMsg("SendServiceRegistration - Error formatting message");
+	if (mapped) srv->resrec.rdata->u.srv.port = privport;	
 	unlinkSRS(u, srs);
 	rInfo->state = regState_Unregistered;
+	m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
 	srs->ServiceCallback(m, srs, err);
+	m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
 	//!!!KRS will mem still be free'd on error?
 	// NOTE: not safe to touch any client structures here	
 	}
@@ -2610,10 +3833,13 @@ error:
 mDNSlocal void serviceRegistrationCallback(mStatus err, mDNS *const m, void *srsPtr, const AsyncOpResult *result)
 	{
 	ServiceRecordSet *srs = (ServiceRecordSet *)srsPtr;
-	const zoneData_t *zoneData = &result->zoneData;
+	const zoneData_t *zoneData = mDNSNULL;
 	uDNS_GlobalInfo *u = &m->uDNS_info;
 	
 	if (err) goto error;
+	if (!result) { LogMsg("ERROR: serviceRegistrationCallback invoked with NULL result and no error");  goto error; }
+	else zoneData = &result->zoneData;
+	
 	if (result->type != zoneDataResult)
 		{
 		LogMsg("ERROR: buildUpdatePacket passed incorrect result type %d", result->type);
@@ -2625,95 +3851,54 @@ mDNSlocal void serviceRegistrationCallback(mStatus err, mDNS *const m, void *srs
 		// client cancelled registration while fetching zone data
 		srs->uDNS_info.state = regState_Unregistered;
 		unlinkSRS(u, srs);
+		m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
 		srs->ServiceCallback(m, srs, mStatus_MemFree);
+		m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
 		return;
 		}
-
+	
 	if (srs->RR_SRV.resrec.rrclass != zoneData->zoneClass)
 		{
-		LogMsg("Service %s - class does not match zone", srs->RR_SRV.resrec.name.c);
+		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);
+	AssignDomainName(srs->uDNS_info.zone, zoneData->zoneName);
     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;
-
+	srs->uDNS_info.ns = zoneData->primaryAddr;
+	if (zoneData->updatePort.NotAnInteger) srs->uDNS_info.port = zoneData->updatePort;		
+	else
+		{
+		debugf("Update port not advertised via SRV - guessing port 53, no lease option");
+		srs->uDNS_info.port = UnicastDNSPort;
+		srs->uDNS_info.lease = mDNSfalse;
+		}
 	SendServiceRegistration(m, srs);
 	return;
 		
 error:
 	unlinkSRS(u, srs);
 	srs->uDNS_info.state = regState_Unregistered;
+	m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
 	srs->ServiceCallback(m, srs, err);
+	m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
 	//!!!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)
+mDNSlocal mStatus SetupRecordRegistration(mDNS *m, AuthRecord *rr)
 	{
 	domainname *target = GetRRDomainNameTarget(&rr->resrec);
+	AuthRecord *ptr = m->uDNS_info.RecordRegistrations;
+
+	while (ptr && ptr != rr) ptr = ptr->next;
+	if (ptr) { LogMsg("Error: SetupRecordRegistration - record %##s already in list!", rr->resrec.name.c); return mStatus_AlreadyRegistered; }
 	
 	if (rr->uDNS_info.state == regState_FetchingZoneData ||
 		rr->uDNS_info.state == regState_Pending ||
 		rr->uDNS_info.state ==  regState_Registered)
 		{
-		LogMsg("Requested double-registration of physical record %s type %s",
+		LogMsg("Requested double-registration of physical record %##s type %d",
 			   rr->resrec.name.c, rr->resrec.rrtype);
 		return mStatus_AlreadyRegistered;
 		}
@@ -2723,13 +3908,14 @@ mDNSexport mStatus uDNS_RegisterRecord(mDNS *const m, AuthRecord *const rr)
 
 	if (!ValidateDomainName(&rr->resrec.name))
 		{
-		LogMsg("Attempt to register record with invalid name: %s", GetRRDisplayString(m, rr));
+		LogMsg("Attempt to register record with invalid name: %s", ARDisplayString(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));
+		{ 
+		LogMsg("Attempt to register record with invalid rdata: %s", ARDisplayString(m, rr));
 		return mStatus_Invalid;
 		}
 
@@ -2740,262 +3926,812 @@ mDNSexport mStatus uDNS_RegisterRecord(mDNS *const m, AuthRecord *const rr)
 	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);
-	}
 
+	return mStatus_NoError;
+	}
 
+mDNSexport mStatus uDNS_RegisterRecord(mDNS *const m, AuthRecord *const rr)
+	{
+	mStatus err = SetupRecordRegistration(m, rr);
+	if (err) return err;
+	else return startGetZoneData(&rr->resrec.name, m, mDNStrue, mDNSfalse, RecordRegistrationCallback, rr);
+	}
 
-mDNSexport mStatus uDNS_DeregisterRecord(mDNS *const m, AuthRecord *const rr)
+mDNSlocal void SendRecordDeregistration(mDNS *m, AuthRecord *rr)
 	{
 	uDNS_GlobalInfo *u = &m->uDNS_info;
 	DNSMessage msg;
 	mDNSu8 *ptr = msg.data;
 	mDNSu8 *end = (mDNSu8 *)&msg + sizeof(DNSMessage);
 	mStatus err;
-	uDNS_AuthInfo *authInfo;
+	
+	InitializeDNSMessage(&msg.h, rr->uDNS_info.id, UpdateReqFlags);
+	
+	ptr = putZone(&msg, ptr, end, &rr->uDNS_info.zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass));
+	if (!ptr) goto error;
+	if (!(ptr = putDeletionRecord(&msg, ptr, &rr->resrec))) goto error;
+
+	err = mDNSSendDNSMessage(m, &msg, ptr, mDNSInterface_Any, &rr->uDNS_info.ns, rr->uDNS_info.port, -1, GetAuthInfoForZone(u, &rr->uDNS_info.zone));
+	if (err) LogMsg("ERROR: SendRecordDeregistration - mDNSSendDNSMessage - %ld", err); 
+
+	SetRecordRetry(m, rr);
+	rr->uDNS_info.state = regState_DeregPending;
+	return;
+
+	error:
+	LogMsg("Error: SendRecordDeregistration - could not contruct deregistration packet");
+	unlinkAR(&u->RecordRegistrations, rr);
+	rr->uDNS_info.state = regState_Unregistered;
+	}
+
+
+
+mDNSexport mStatus uDNS_DeregisterRecord(mDNS *const m, AuthRecord *const rr)
+	{
+	uDNS_GlobalInfo *u = &m->uDNS_info;
+	NATTraversalInfo *n = rr->uDNS_info.NATinfo;
+ 
 	switch (rr->uDNS_info.state)
 		{
+		case regState_NATMap:
+            // we're in the middle of a NAT traversal operation
+			if (!n) LogMsg("uDNS_DeregisterRecord: no NAT info context");		
+			else FreeNATInfo(m, n); // cause response to outstanding request to be ignored.
+			                        // Note: normally here we're trying to determine our public address, 
+			                        //in which case there is not state to be torn down.  For simplicity, 
+			                        //we allow other operations to expire.    
+            rr->uDNS_info.NATinfo = mDNSNULL;
+			rr->uDNS_info.state = regState_Unregistered;
+			break;
+		case regState_ExtraQueued:
+			rr->uDNS_info.state = regState_Unregistered;
+			break;			
 		case regState_FetchingZoneData:
 			rr->uDNS_info.state = regState_Cancelled;
 			return mStatus_NoError;
+		case regState_Refresh:
 		case regState_Pending:
+		case regState_UpdatePending:
 			rr->uDNS_info.state = regState_DeregDeferred;
-			debugf("Deferring deregistration of record %s until registration completes", rr->resrec.name.c);
+			LogMsg("Deferring deregistration of record %##s until registration completes", rr->resrec.name.c);
 			return mStatus_NoError;
 		case regState_Registered:			
-			break;
 		case regState_DeregPending:
+			break;
+		case regState_DeregDeferred:
 		case regState_Cancelled:
-			LogMsg("Double deregistration of record %s type %d",
+			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",
+			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);
+		case  regState_NoTarget:
+			LogMsg("ERROR: uDNS_DeregisterRecord called for record %##s with bad state (regState_NoTarget)", rr->resrec.name.c);
 			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
+	if (rr->uDNS_info.state == regState_Unregistered)
 		{
-		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; }
+		// unlink and deliver memfree
+		
+		unlinkAR(&u->RecordRegistrations, rr);		
+		m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
+		if (rr->RecordCallback) rr->RecordCallback(m, rr, mStatus_MemFree);
+		m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
+		return mStatus_NoError;
 		}
-	
-	return mStatus_NoError;
 
-	error:
-	if (rr->uDNS_info.state != regState_Unregistered)
-		{
-		unlinkAR(&u->RecordRegistrations, rr);
-		rr->uDNS_info.state = regState_Unregistered;
-		}
-	return mStatus_UnknownErr;
-	}
+	if (n) FreeNATInfo(m, n);
+	rr->uDNS_info.NATinfo = mDNSNULL;
 
+	SendRecordDeregistration(m, rr);
+	return mStatus_NoError;
+	}
 
-mDNSexport mStatus uDNS_RegisterService(mDNS *const m, ServiceRecordSet *srs)
+// register a service already in list with initialized state
+mDNSlocal mStatus RegisterService(mDNS *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;
-		}
+	uDNS_RegInfo *info = &srs->uDNS_info;	
 	
 	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;
+	info->lease = mDNStrue;
+
+	if (srs->RR_SRV.resrec.rdata->u.srv.port.NotAnInteger && MapServicePort(m))
+		{
+		// !!!KRS if interface is already in NATState_Legacy, don't try NATPMP
+		info->state = regState_NATMap;
+		StartNATPortMap(m, srs);
+		return mStatus_NoError;
+		}
+	
+	info->state = regState_FetchingZoneData;
+	return startGetZoneData(&srs->RR_SRV.resrec.name, m, mDNStrue, mDNSfalse, serviceRegistrationCallback, srs);
+	}	
+	
+mDNSexport mStatus uDNS_RegisterService(mDNS *const m, ServiceRecordSet *srs)
+	{
+	// Note: ServiceRegistrations list is in the order they were created; important for in-order event delivery
+	ServiceRecordSet **p = &m->uDNS_info.ServiceRegistrations;
+	while (*p && *p != srs) p=&(*p)->next;
+	if (*p) { LogMsg("uDNS_RegisterService: %p %##s already in list", srs, srs->RR_SRV.resrec.name.c); return(mStatus_AlreadyRegistered); }
+	ubzero(&srs->uDNS_info, sizeof(uDNS_RegInfo));
+	srs->uDNS_info.state = regState_Unregistered;
+	*p = srs;
+	srs->next = mDNSNULL;
+	return RegisterService(m, srs);
+	}	
+
+mDNSlocal void SendServiceDeregistration(mDNS *m, ServiceRecordSet *srs)
+	{
+	uDNS_RegInfo *info = &srs->uDNS_info;
+	uDNS_GlobalInfo *u = &m->uDNS_info;
+	DNSMessage msg;
+	mDNSOpaque16 id;
+	mDNSu8 *ptr = msg.data;
+	mDNSu8 *end = (mDNSu8 *)&msg + sizeof(DNSMessage);
+	mStatus err = mStatus_UnknownErr;
+
+	id = newMessageID(u);
+	InitializeDNSMessage(&msg.h, id, UpdateReqFlags);
+	
+    // put zone
+	ptr = putZone(&msg, ptr, end, &info->zone, mDNSOpaque16fromIntVal(srs->RR_SRV.resrec.rrclass));
+	if (!ptr) { LogMsg("ERROR: SendServiceDeregistration - putZone"); goto error; }
+		
+	if (!(ptr = putDeleteAllRRSets(&msg, ptr, &srs->RR_SRV.resrec.name))) goto error;  // this deletes SRV, TXT, and Extras
+	if (!(ptr = putDeletionRecord(&msg, ptr, &srs->RR_PTR.resrec))) goto error;
+
+	err = mDNSSendDNSMessage(m, &msg, ptr, mDNSInterface_Any, &info->ns, info->port, -1, GetAuthInfoForZone(u, &info->zone));
+	if (err) { LogMsg("ERROR: SendServiceDeregistration - mDNSSendDNSMessage - %ld", err); goto error; }
+
+	SetRecordRetry(m, &srs->RR_SRV);
+    info->id.NotAnInteger = id.NotAnInteger;
+	info->state = regState_DeregPending;
+ 
+	return;
 	
-	return startGetZoneData(&srs->RR_SRV.resrec.name, m, mDNStrue, mDNSfalse, serviceRegistrationCallback, srs);
+	error:
+	unlinkSRS(u, srs);
+	info->state = regState_Unregistered;
 	}
 
 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;
+	NATTraversalInfo *nat = srs->uDNS_info.NATinfo;
+	AuthRecord **r = &u->RecordRegistrations;
+	char *errmsg = "Unknown State";
 	
-	//!!!KRS make sure we're doing the right thing w/ memfree
+	// We "silently" unlink any Extras from our RecordRegistration list, as they are implicitly deleted from
+	// the server when we delete all RRSets for this name
+	while (*r)
+		{
+		if (SameDomainName(&srs->RR_SRV.resrec.name, &(*r)->resrec.name)) *r = (*r)->next;
+		else r = &(*r)->next;
+		}
+
+	// don't re-register with a new target following deregistration
+	srs->uDNS_info.LostTarget = srs->uDNS_info.SRVUpdateDeferred = mDNSfalse;
 	
 	switch (srs->uDNS_info.state)
 		{
+		case regState_NATMap:
+			// we're in the middle of nat mapping.  clear ptr from NAT info to RR, unlink and give memfree			
+			if (!nat) LogMsg("uDNS_DeregisterRecord: no NAT info context");
+			else { nat->reg.ServiceRegistration = mDNSNULL; FreeNATInfo(m, nat); }
+			unlinkSRS(u, srs);
+			srs->uDNS_info.state = regState_Unregistered;
+			m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
+			srs->ServiceCallback(m, srs, mStatus_MemFree);
+			m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
+			return mStatus_NoError;		
 		case regState_Unregistered:
-			LogMsg("ERROR: uDNS_DeregisterService - service not registerd");
-			return mStatus_UnknownErr;
+			errmsg = "service not registered";
+			goto error;
 		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_Pending:
+		case regState_Refresh:
+		case regState_UpdatePending:
+			// deregister following completion of in-flight operation
+			srs->uDNS_info.state = regState_DeregDeferred;
+			return mStatus_NoError;
 		case regState_DeregPending:
 		case regState_DeregDeferred:
 		case regState_Cancelled:
-			LogMsg("uDNS_DeregisterService - deregistration in process");
-			return mStatus_UnknownErr;
+			debugf("Double deregistration of service %##s", srs->RR_SRV.resrec.name.c);
+			return mStatus_NoError;
+		case regState_NoTarget:
+			unlinkSRS(u, srs);
+			srs->uDNS_info.state = regState_Unregistered;
+			m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
+			srs->ServiceCallback(m, srs, mStatus_MemFree);
+			m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
+			return mStatus_NoError;
+		case regState_Registered:
+			if (nat) DeleteNATPortMapping(m, nat, srs);			
+			srs->uDNS_info.state = regState_DeregPending;
+			SendServiceDeregistration(m, srs);
+			return mStatus_NoError;
+		case regState_ExtraQueued: // only for record registrations
+			errmsg = "bad state (regState_ExtraQueued)";
+			goto error;
 		}
 
-	srs->uDNS_info.state = regState_DeregPending;
-	InitializeDNSMessage(&msg.h, srs->uDNS_info.id, UpdateReqFlags);
+	error:
+	LogMsg("Error, uDNS_DeregisterService: %s", errmsg);
+	return mStatus_BadReferenceErr;
+	}
 
-    // 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; }
+// note that the RegInfo will be either for the record, or for the parent ServiceRecordSet
+mDNSlocal void SendRecordUpdate(mDNS *m, AuthRecord *rr, uDNS_RegInfo *info)
+	{
+	DNSMessage msg;
+	mDNSu8 *ptr = msg.data;
+	mDNSu8 *end = (mDNSu8 *)&msg + sizeof(DNSMessage);
+	uDNS_GlobalInfo *u = &m->uDNS_info;
+	mDNSOpaque16 id;
+	mStatus err = mStatus_UnknownErr;
+	
+	rr->uDNS_info.UpdateQueued = mDNSfalse;  // if this was queued, clear flag
+	id = newMessageID(u);
+	InitializeDNSMessage(&msg.h, id, UpdateReqFlags);
+	info->id.NotAnInteger = id.NotAnInteger;
+	
+    // set zone
+	ptr = putZone(&msg, ptr, end, &info->zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass));
+	if (!ptr) goto error;
+	        
+	// delete the original record
+	ptr = putDeletionRecord(&msg, ptr, &rr->resrec);
+	if (!ptr) goto error;
+
+	// change the rdata, add the new record
+	SwapRData(m, rr, mDNSfalse);
+	ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numUpdates, &rr->resrec, rr->resrec.rroriginalttl);
+	SwapRData(m, rr, mDNSfalse);  // swap rdata back to original in case we need to retransmit
+	if (!ptr) goto error;         // (rdata gets changed permanently on success)
+
+	if (info->lease)
+		{ ptr = putUpdateLease(&msg, ptr, kLLQ_DefLease); if (!ptr) 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; }
+	// don't report send errors - retransmission will occurr if necessary
+	err = mDNSSendDNSMessage(m, &msg, ptr, mDNSInterface_Any, &info->ns, info->port, -1, GetAuthInfoForZone(u, &info->zone));
+	if (err) debugf("ERROR: sendRecordRegistration - mDNSSendDNSMessage - %ld", err);
 
-	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
+	//!!! Update this when we implement retransmission for services	
+	SetRecordRetry(m, rr);
+	
+	rr->uDNS_info.state = regState_UpdatePending;
+	if (&rr->uDNS_info != info) info->state = regState_UpdatePending; // set parent SRS
+	return;
 
+error:
+	LogMsg("ERROR: SendRecordUpdate.  Error formatting update message.");
+	info ->state = regState_Registered;  
+	}
 
-	authInfo = GetAuthInfoForZone(u, &srs->uDNS_info.zone);
-	if (authInfo)
+mDNSexport mStatus uDNS_AddRecordToService(mDNS *const m, ServiceRecordSet *sr, ExtraResourceRecord *extra)
+	{
+	mStatus err = mStatus_UnknownErr;
+	
+	extra->r.resrec.RecordType = kDNSRecordTypeShared;  // don't want it to conflict with the service name
+	extra->r.RecordCallback = mDNSNULL;  // don't generate callbacks for extra RRs
+	
+	if (sr->uDNS_info.state == regState_Registered || sr->uDNS_info.state == regState_Refresh)	
+		err = uDNS_RegisterRecord(m, &extra->r);
+	else
 		{
-		err = 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; }
+		err = SetupRecordRegistration(m, &extra->r);
+		extra->r.uDNS_info.state = regState_ExtraQueued;
 		}
-	else
+	
+	if (!err)
+		{
+		extra->next = sr->Extras;
+		sr->Extras = extra;
+		}
+	return err;
+	}
+  
+mDNSexport mStatus uDNS_UpdateRecord(mDNS *m, AuthRecord *rr)
+	{
+	uDNS_GlobalInfo *u = &m->uDNS_info;
+	ServiceRecordSet *sptr, *parent = mDNSNULL;
+	AuthRecord *rptr;
+	uDNS_RegInfo *info = mDNSNULL;
+	
+	// find the record in registered service list
+	for (sptr = u->ServiceRegistrations; sptr; sptr = sptr->next)
+		if (&sptr->RR_TXT == rr) { info = &sptr->uDNS_info; parent = sptr; break; }
+
+	if (!parent)
 		{
-		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; }
+		// record not part of a service - check individual record registrations
+		for (rptr = u->RecordRegistrations; rptr; rptr = rptr->next)
+			if (rptr == rr) { info = &rr->uDNS_info; break; }
 		}
+
+	if (!info) goto unreg_error;
+
+	// uDNS-private pointers so that mDNS.c layer doesn't nuke rdata of an in-flight update
+	rr->uDNS_info.UpdateRData = rr->NewRData;
+	rr->uDNS_info.UpdateRDLen = rr->newrdlength;
+	rr->uDNS_info.UpdateRDCallback = rr->UpdateCallback;
+	rr->NewRData = mDNSNULL;
 	
-	return mStatus_NoError;
+	switch(info->state)
+		{
+		case regState_DeregPending:
+		case regState_DeregDeferred:
+		case regState_Cancelled:
+		case regState_Unregistered:
+			// not actively registered
+			goto unreg_error;
+			
+		case regState_FetchingZoneData:
+		case regState_NATMap:
+		case regState_ExtraQueued:
+			// change rdata directly since it hasn't been sent yet			
+			SwapRData(m, rr, mDNStrue);
+			return mStatus_NoError;
+			
+		case regState_Pending:
+		case regState_Refresh:
+		case regState_UpdatePending:
+			// registration in-flight.  mark for update after service registration completes
+			rr->uDNS_info.UpdateQueued = mDNStrue;  // note that we mark the record's Queued flag, not its parent's
+			return mStatus_NoError;
+			
+		case regState_Registered:
+			SendRecordUpdate(m, rr, info);
+			return mStatus_NoError;
 
-	error:
-	unlinkSRS(u, srs);
-	srs->uDNS_info.state = regState_Unregistered;
-	return err;
+		case regState_NoTarget:
+			LogMsg("Bad state (regState_NoTarget)"); return mStatus_UnknownErr;  // state for service records only
+		}
+
+	unreg_error:
+	LogMsg("Requested update of record %##s type %d, part of service not currently registered",
+		   rr->resrec.name.c, rr->resrec.rrtype);
+	return mStatus_Invalid;
 	}
 
-mDNSexport void uDNS_Execute(mDNS *const m)
+
+// ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark - Periodic Execution Routines
+#endif
+
+
+mDNSlocal mDNSs32 CheckNATMappings(mDNS *m, mDNSs32 timenow)
+	{
+	NATTraversalInfo *ptr, *cur;
+	mDNSs32 nextevent;
+
+	ptr = m->uDNS_info.NATTraversals;
+	nextevent = timenow + MIN_UCAST_PERIODIC_EXEC;
+	
+	while (ptr)
+		{
+		cur = ptr;
+		ptr = ptr->next;
+		if (cur->retry - timenow < 0)
+			{
+			if (cur->state == NATState_Established) RefreshNATMapping(cur, m);
+			else if (cur->state == NATState_Request || cur->state == NATState_Refresh)
+				{
+				if (cur->ntries >= NATMAP_MAX_TRIES) cur->ReceiveResponse(cur, m, mDNSNULL, 0); // may invalidate "cur"
+				else SendNATMsg(cur, m);
+				}
+			}
+		else if (cur->retry - nextevent < 0) nextevent = cur->retry;
+		}
+	return nextevent;
+	}
+
+mDNSlocal mDNSs32 CheckQueries(mDNS *m, mDNSs32 timenow)
 	{
 	DNSQuestion *q;
+	uDNS_GlobalInfo *u = &m->uDNS_info;
+	LLQ_Info *llq;
+	mDNSs32 sendtime;
+	mDNSs32 nextevent = timenow + MIN_UCAST_PERIODIC_EXEC;
 	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();
+	uDNS_QuestionInfo *info;
 	
-	u->nextevent = timenow + 0x78000000;
-	if (!server) { debugf("uDNS_Execute - no DNS server"); return; }	
-	
-	for (q = u->ActiveQueries; q; q = q->next)
+	u->CurrentQuery = u->ActiveQueries;
+	while (u->CurrentQuery)
 		{
-		llq = q->uDNS_info.llq;
-		if (q->LongLived && llq->state != LLQ_Poll)
+		q = u->CurrentQuery;		
+		info = &q->uDNS_info;
+		llq = info->llq;
+		
+		if (!info->internal && ((!q->LongLived && !info->Answered) || (llq && llq->state < LLQ_Established)) && 
+			info->RestartTime + RESTART_GOODBYE_DELAY - timenow < 0)
 			{
-			if (llq->state >= LLQ_InitialRequest && llq->state <= LLQ_Suspended && llq->retry <= timenow)				
+			// if we've been spinning on restart setup, and we have known answers, give goodbyes (they may be re-added later)
+			while (info->knownAnswers)
+				{						
+				CacheRecord *cr = info->knownAnswers;
+				info->knownAnswers = info->knownAnswers->next;
+				
+				m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
+				q->QuestionCallback(m, q, &cr->resrec, mDNSfalse);
+				m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
+				ufree(cr);
+				if (q != u->CurrentQuery) { debugf("CheckQueries - question removed via callback."); break; }
+				}											
+			}
+		if (q != u->CurrentQuery) continue;
+		
+		if (q->LongLived && llq->state != LLQ_Poll)
+			{			
+			if (llq->state >= LLQ_InitialRequest && llq->state <= LLQ_Established)
 				{
-
-				// 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); }			
+				if (llq->retry - timenow < 0)				
+					{
+					// sanity check to avoid packet flood bugs
+					if (!llq->retry) 
+						LogMsg("ERROR: retry timer not set for LLQ %##s in state %d", q->qname.c, llq->state);
+					else if (llq->state == LLQ_Established || llq->state == LLQ_Refresh)
+						sendLLQRefresh(m, q, llq->origLease);
+					else if (llq->state == LLQ_InitialRequest) 						
+						startLLQHandshake(m, llq, mDNSfalse);
+					else if (llq->state == LLQ_SecondaryRequest)
+						sendChallengeResponse(m, q, mDNSNULL);
+					else if (llq->state == LLQ_Retry) 
+						{ llq->ntries = 0; startLLQHandshake(m, llq, mDNSfalse); }
+					}
+				else if (llq->retry - nextevent < 0) nextevent = llq->retry;
 				}
 			}
 		else
 			{
 			sendtime = q->LastQTime + q->ThisQInterval;
-			if (sendtime <= timenow)
+			if (sendtime - timenow < 0)
 				{
-				err = constructQueryMsg(&msg, &end, q);
-				if (err)
+				mDNSAddr server;
+				if (GetServerForName(&m->uDNS_info, &q->qname, &server))
 					{
-					LogMsg("Error: uDNS_Idle - constructQueryMsg.  Skipping question %s",
-						   q->qname.c);
-					continue;
+					err = constructQueryMsg(&msg, &end, q);
+					if (err)  LogMsg("Error: uDNS_Idle - constructQueryMsg.  Skipping question %##s", q->qname.c);
+					else
+						{
+						err = mDNSSendDNSMessage(m, &msg, end, mDNSInterface_Any, &server, UnicastDNSPort, -1, mDNSNULL);
+						if (err) { debugf("ERROR: uDNS_idle - mDNSSendDNSMessage - %ld", err); } // surpress syslog messages if we have no network
+						q->LastQTime = timenow;
+						if (q->ThisQInterval < MAX_UCAST_POLL_INTERVAL) q->ThisQInterval = q->ThisQInterval * 2;
+						}
 					}
-				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;
+			else if (sendtime - nextevent < 0) nextevent = sendtime;
 			}
+		u->CurrentQuery = u->CurrentQuery->next;
 		}
+	return nextevent;
+	}
 
+mDNSlocal mDNSs32 CheckRecordRegistrations(mDNS *m, mDNSs32 timenow)
+	{
+	AuthRecord *rr;
+	uDNS_RegInfo *rInfo;
+	uDNS_GlobalInfo *u = &m->uDNS_info;
+ 	mDNSs32 nextevent = timenow + MIN_UCAST_PERIODIC_EXEC;
+	
 	//!!!KRS list should be pre-sorted by expiration
 	for (rr = u->RecordRegistrations; rr; rr = rr->next)
 		{
 		rInfo = &rr->uDNS_info;		
+		if (rInfo->state == regState_Pending || rInfo->state == regState_DeregPending || rInfo->state == regState_UpdatePending || rInfo->state == regState_DeregDeferred || rInfo->state == regState_Refresh)
+			{
+			if (rr->LastAPTime + rr->ThisAPInterval - timenow < 0)
+				{
+#if MDNS_DEBUGMSGS				
+				char *op = "(unknown operation)";
+				if (rInfo->state == regState_Pending) op = "registration";
+				else if (rInfo->state == regState_DeregPending) op = "deregistration";
+				else if (rInfo->state == regState_Refresh) op = "refresh";
+				debugf("Retransmit record %s %##s", op, rr->resrec.name.c);
+#endif
+				//LogMsg("Retransmit record %##s", rr->resrec.name.c);
+				if      (rInfo->state == regState_DeregPending)   SendRecordDeregistration(m, rr);
+				else if (rInfo->state == regState_UpdatePending)  SendRecordUpdate(m, rr, rInfo);
+				else                                              sendRecordRegistration(m, rr);
+				}
+			if (rr->LastAPTime + rr->ThisAPInterval - nextevent < 0) nextevent = rr->LastAPTime + rr->ThisAPInterval;
+			}
 		if (rInfo->lease && rInfo->state == regState_Registered && rInfo->expire > 0)
 		    {		    
-		    if (rInfo->expire < timenow)
+		    if (rInfo->expire - timenow < 0)
 		        {
-		        debugf("refreshing record %s", rr->resrec.name.c);
+		        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;
-		    }
+		    if (rInfo->expire - nextevent < 0) nextevent = rInfo->expire;
+		    }		
 		}
-	//!!!KRS list should be pre-sorted by expiration
-	for (srs = u->ServiceRegistrations; srs; srs = srs->next)
+	return nextevent;
+	}
+
+mDNSlocal mDNSs32 CheckServiceRegistrations(mDNS *m, mDNSs32 timenow)
+	{
+	ServiceRecordSet *s = m->uDNS_info.ServiceRegistrations;
+	uDNS_RegInfo *rInfo;
+	mDNSs32 nextevent = timenow + MIN_UCAST_PERIODIC_EXEC;
+	
+	// Note: ServiceRegistrations list is in the order they were created; important for in-order event delivery
+	while (s)
 		{
+		ServiceRecordSet *srs = s;
+		// NOTE: Must advance s here -- SendServiceDeregistration may delete the object we're looking at,
+		// and then if we tried to do srs = srs->next at the end we'd be referencing a dead object
+		s = s->next;
+		
 		rInfo = &srs->uDNS_info;	
+		if (rInfo->state == regState_Pending || rInfo->state == regState_DeregPending || rInfo->state == regState_DeregDeferred || rInfo->state == regState_Refresh)
+			{
+			if (srs->RR_SRV.LastAPTime + srs->RR_SRV.ThisAPInterval - timenow < 0)
+				{
+#if MDNS_DEBUGMSGS				
+				char *op = "unknown";
+				if (rInfo->state == regState_Pending) op = "registration";
+				else if (rInfo->state == regState_DeregPending) op = "deregistration";
+				else if (rInfo->state == regState_Refresh) op = "refresh";
+				debugf("Retransmit service %s %##s", op, srs->RR_SRV.resrec.name.c);
+#endif
+				if (rInfo->state == regState_DeregPending) { SendServiceDeregistration(m, srs); continue; }
+				else                                         SendServiceRegistration  (m, srs);
+				}
+			if (nextevent - srs->RR_SRV.LastAPTime + srs->RR_SRV.ThisAPInterval > 0)
+				nextevent = srs->RR_SRV.LastAPTime + srs->RR_SRV.ThisAPInterval;
+			}			
+
 		if (rInfo->lease && rInfo->state == regState_Registered && rInfo->expire > 0)
 		    {		    
-		    if (rInfo->expire < timenow)
+		    if (rInfo->expire - timenow < 0)
 		        {	
-			    debugf("refreshing service %s", srs->RR_SRV.resrec.name.c);
+			    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;
-		    }	
+		    if (rInfo->expire - nextevent < 0) nextevent = rInfo->expire;
+		    }		
+		}
+	return nextevent;
+	}
+
+mDNSexport void uDNS_Execute(mDNS *const m)
+	{
+	uDNS_GlobalInfo *u = &m->uDNS_info;
+	mDNSs32 nexte, timenow = mDNSPlatformTimeNow(m);	
+
+	u->nextevent = timenow + MIN_UCAST_PERIODIC_EXEC;
+	
+	nexte = CheckNATMappings(m, timenow);
+	if (nexte - u->nextevent < 0) u->nextevent = nexte;
+
+	nexte = CheckQueries(m, timenow);
+	if (nexte - u->nextevent < 0) u->nextevent = nexte;
+
+	nexte = CheckRecordRegistrations(m, timenow);
+	if (nexte - u->nextevent < 0) u->nextevent = nexte;
+
+	nexte = CheckServiceRegistrations(m, timenow);
+	if (nexte - u->nextevent < 0) u->nextevent = nexte;
+	
+	}
+
+// ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark - Startup, Shutdown, and Sleep
+#endif
+
+// DeregisterActive causes active LLQs to be removed from the server, e.g. before sleep.  Pass false
+// following a location change, as the server will reject deletions from a source address different
+// from the address on which the LLQ was created.
+
+mDNSlocal void SuspendLLQs(mDNS *m, mDNSBool DeregisterActive)
+	{
+	DNSQuestion *q;
+	LLQ_Info *llq;
+	for (q = m->uDNS_info.ActiveQueries; q; q = q->next)
+		{
+		llq = q->uDNS_info.llq;
+		if (q->LongLived && llq)
+			{
+			if (llq->state == LLQ_GetZoneInfo)
+				{
+				debugf("Marking %##s suspend-deferred", q->qname.c);
+				llq->state = LLQ_SuspendDeferred;  // suspend once we're done getting zone info
+				}
+			else if (llq->state < LLQ_Suspended)
+				{
+				if (DeregisterActive && (llq->state == LLQ_Established || llq->state == LLQ_Refresh))
+					{ debugf("Deleting LLQ %##s", q->qname.c); sendLLQRefresh(m, q, 0); }
+				debugf("Marking %##s suspended", q->qname.c);
+				llq->state = LLQ_Suspended;
+				ubzero(llq->id, 8);
+				}
+			else if (llq->state == LLQ_Poll) { debugf("Marking %##s suspended-poll", q->qname.c); llq->state = LLQ_SuspendedPoll; }
+			if (llq->NATMap) llq->NATMap = mDNSfalse;  // may not need nat mapping if we restart with new route
+			}
+		}
+	CheckForUnreferencedLLQMapping(m);
+	}
+
+mDNSlocal void RestartQueries(mDNS *m)
+	{
+	uDNS_GlobalInfo *u = &m->uDNS_info;
+	DNSQuestion *q;
+	LLQ_Info *llqInfo;
+	mDNSs32 timenow = mDNSPlatformTimeNow(m);
+	
+	u->CurrentQuery = u->ActiveQueries;
+	while (u->CurrentQuery)
+		{
+		q = u->CurrentQuery;
+		u->CurrentQuery = u->CurrentQuery->next;
+		llqInfo = q->uDNS_info.llq;
+		q->uDNS_info.RestartTime = timenow;
+		q->uDNS_info.Answered = mDNSfalse;
+		if (q->LongLived)
+			{
+			if (!llqInfo) { LogMsg("Error: RestartQueries - %##s long-lived with NULL info", q->qname.c); continue; } 
+			if (llqInfo->state == LLQ_Suspended || llqInfo->state == LLQ_NatMapWait)		
+				{
+				llqInfo->ntries = -1;
+				llqInfo->deriveRemovesOnResume = mDNStrue;
+				startLLQHandshake(m, llqInfo, mDNStrue);  // we set defer to true since several events that may generate restarts often arrive in rapid succession, and this cuts unnecessary packets
+				}
+			else if (llqInfo->state == LLQ_SuspendDeferred)
+				llqInfo->state = LLQ_GetZoneInfo; // we never finished getting zone data - proceed as usual
+			else if (llqInfo->state == LLQ_SuspendedPoll)
+				{
+				// if we were polling, we may have had bad zone data due to firewall, etc. - refetch
+				llqInfo->ntries = 0;
+				llqInfo->deriveRemovesOnResume = mDNStrue;
+				llqInfo->state = LLQ_GetZoneInfo;
+				startGetZoneData(&q->qname, m, mDNSfalse, mDNStrue, startLLQHandshakeCallback, llqInfo);
+				}
+			}
+		else { q->LastQTime = timenow; q->ThisQInterval = INIT_UCAST_POLL_INTERVAL; } // trigger poll in 1 second (to reduce packet rate when restarts come in rapid succession)
+		}
+	}
+
+mDNSexport void mDNS_UpdateLLQs(mDNS *m)
+	{
+	uDNS_GlobalInfo *u = &m->uDNS_info;
+
+	mDNS_Lock(m);
+	if (u->LLQNatInfo)
+		{
+		NATTraversalInfo *nat = u->LLQNatInfo;
+		u->LLQNatInfo = mDNSNULL;
+		DeleteNATPortMapping(m, nat, mDNSNULL);
+		}
+	SuspendLLQs(m, mDNStrue);
+	RestartQueries(m);
+	mDNS_Unlock(m);
+	}
+
+// simplest sleep logic - rather than having sleep states that must be dealt with explicitly in all parts of
+// the code, we simply send a deregistration, and put the service in Refresh state, with a timeout far enough
+// in the future that we'll sleep (or the sleep will be cancelled) before it is retransmitted.  Then to wake,
+// we just move up the timers.
+
+
+
+mDNSlocal void SleepRecordRegistrations(mDNS *m)
+	{
+	DNSMessage msg;
+	AuthRecord *rr = m->uDNS_info.RecordRegistrations;
+	mDNSs32 timenow = mDNSPlatformTimeNow(m);
+
+	while (rr)
+		{		
+		if (rr->uDNS_info.state == regState_Registered ||
+			rr->uDNS_info.state == regState_Refresh)
+			{
+			mDNSu8 *ptr = msg.data, *end = (mDNSu8 *)&msg + sizeof(DNSMessage);
+			InitializeDNSMessage(&msg.h, newMessageID(&m->uDNS_info), UpdateReqFlags);
+			
+			// construct deletion update
+			ptr = putZone(&msg, ptr, end, &rr->uDNS_info.zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass));
+			if (!ptr) { LogMsg("Error: SleepRecordRegistrations - could not put zone"); return; }			
+			ptr = putDeletionRecord(&msg, ptr, &rr->resrec);
+			if (!ptr) {  LogMsg("Error: SleepRecordRegistrations - could not put deletion record"); return; }
+
+			mDNSSendDNSMessage(m, &msg, ptr, mDNSInterface_Any, &rr->uDNS_info.ns, rr->uDNS_info.port, -1, GetAuthInfoForZone(&m->uDNS_info, &rr->uDNS_info.zone));
+			rr->uDNS_info.state = regState_Refresh;
+			rr->LastAPTime = timenow;
+			rr->ThisAPInterval = 300 * mDNSPlatformOneSecond;
+			}
+		rr = rr->next;
+		}
+	}
+
+mDNSlocal void WakeRecordRegistrations(mDNS *m)
+	{
+	mDNSs32 timenow = mDNSPlatformTimeNow(m);
+	AuthRecord *rr = m->uDNS_info.RecordRegistrations;
+
+	while (rr)
+		{
+		if (rr->uDNS_info.state == regState_Refresh)
+			{
+			// trigger slightly delayed refresh (we usually get this message before kernel is ready to send packets)
+			rr->LastAPTime = timenow;
+			rr->ThisAPInterval = INIT_UCAST_POLL_INTERVAL;
+			}
+		rr = rr->next;
+		}
+	}
+
+mDNSlocal void SleepServiceRegistrations(mDNS *m)
+	{
+	mDNSs32 timenow = mDNSPlatformTimeNow(m);
+	ServiceRecordSet *srs = m->uDNS_info.ServiceRegistrations;
+	while(srs)
+		{
+		if (srs->uDNS_info.state == regState_Registered ||
+			srs->uDNS_info.state == regState_Refresh)
+			{
+			mDNSOpaque16 origid  = srs->uDNS_info.id;
+			srs->uDNS_info.state = regState_DeregPending;  // state expected by SendDereg()
+			SendServiceDeregistration(m, srs);
+			srs->uDNS_info.id = origid;
+			srs->uDNS_info.state = regState_Refresh;			
+			srs->RR_SRV.LastAPTime = timenow;
+			srs->RR_SRV.ThisAPInterval = 300 * mDNSPlatformOneSecond;
+			}
+		srs = srs->next;
+		}
+	}
+
+mDNSlocal void WakeServiceRegistrations(mDNS *m)
+	{
+	mDNSs32 timenow = mDNSPlatformTimeNow(m);
+	ServiceRecordSet *srs = m->uDNS_info.ServiceRegistrations;
+	while(srs)
+		{
+		if (srs->uDNS_info.state == regState_Refresh)
+			{
+			// trigger slightly delayed refresh (we usually get this message before kernel is ready to send packets)
+			srs->RR_SRV.LastAPTime = timenow;
+			srs->RR_SRV.ThisAPInterval = INIT_UCAST_POLL_INTERVAL;
+			}
+		srs = srs->next;
 		}
 	}
 
 mDNSexport void uDNS_Init(mDNS *const m)
 	{
 	mDNSPlatformMemZero(&m->uDNS_info, sizeof(uDNS_GlobalInfo));
-	m->uDNS_info.nextevent = mDNSPlatformTimeNow() + 0x78000000;
+	m->uDNS_info.nextevent = m->timenow_last + 0x78000000;
+	}
+
+mDNSexport void uDNS_Sleep(mDNS *m)
+	{
+	SuspendLLQs(m, mDNStrue);
+	SleepServiceRegistrations(m);
+	SleepRecordRegistrations(m);
+	}
+
+mDNSexport void uDNS_Wake(mDNS *m)
+	{
+	RestartQueries(m);
+	WakeServiceRegistrations(m);
+	WakeRecordRegistrations(m);
 	}
diff --git a/mDNSCore/uDNS.h b/mDNSCore/uDNS.h
index 52fc878..20edb2d 100755
--- a/mDNSCore/uDNS.h
+++ b/mDNSCore/uDNS.h
@@ -3,8 +3,6 @@
  *
  * @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
@@ -25,6 +23,58 @@
     Change History (most recent first):
 
 $Log: uDNS.h,v $
+Revision 1.27  2004/11/23 04:06:50  cheshire
+Get rid of floating point constant -- in a small embedded device, bringing in all
+the floating point libraries just to halve an integer value is a bit too heavyweight.
+
+Revision 1.26  2004/11/22 17:49:15  ksekar
+Changed INIT_REFRESH from fraction to decimal
+
+Revision 1.25  2004/11/22 17:16:20  ksekar
+<rdar://problem/3854298> Unicast services don't disappear when you disable all networking
+
+Revision 1.24  2004/11/19 04:24:08  ksekar
+<rdar://problem/3682609> Security: Enforce a "window" on one-shot wide-area queries
+
+Revision 1.23  2004/11/18 18:04:21  ksekar
+Add INIT_REFRESH constant
+
+Revision 1.22  2004/11/15 20:09:24  ksekar
+<rdar://problem/3719050> Wide Area support for Add/Remove record
+
+Revision 1.21  2004/11/11 20:14:55  ksekar
+<rdar://problem/3719574> Wide-Area registrations not deregistered on sleep
+
+Revision 1.20  2004/10/16 00:16:59  cheshire
+<rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check
+
+Revision 1.19  2004/09/17 01:08:49  cheshire
+Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
+  The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
+  declared in that file are ONLY appropriate to single-address-space embedded applications.
+  For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
+
+Revision 1.18  2004/09/03 19:23:05  ksekar
+<rdar://problem/3788460>: Need retransmission mechanism for wide-area service registrations
+
+Revision 1.17  2004/09/01 03:59:29  ksekar
+<rdar://problem/3783453>: Conditionally compile out uDNS code on Windows
+
+Revision 1.16  2004/08/25 00:37:27  ksekar
+<rdar://problem/3774635>: Cleanup DynDNS hostname registration code
+
+Revision 1.15  2004/07/30 17:40:06  ksekar
+<rdar://problem/3739115>: TXT Record updates not available for wide-area services
+
+Revision 1.14  2004/07/29 19:27:15  ksekar
+NATPMP Support - minor fixes and cleanup
+
+Revision 1.13  2004/07/29 02:03:35  ksekar
+Delete unused #define and structure field
+
+Revision 1.12  2004/07/26 22:49:30  ksekar
+<rdar://problem/3651409>: Feature #9516: Need support for NATPMP in client
+
 Revision 1.11  2004/06/17 01:13:11  ksekar
 <rdar://problem/3696616>: polling interval too short
 
@@ -65,49 +115,58 @@ Revision 1.1  2003/12/13 03:05:27  ksekar
 #ifndef __UDNS_H_
 #define __UDNS_H_
 
-#include "mDNSClientAPI.h"
+#include "mDNSEmbeddedAPI.h"
 #include "DNSCommon.h"
 
 #ifdef	__cplusplus
 	extern "C" {
 #endif
 
-#define INIT_UCAST_POLL_INTERVAL (15 * mDNSPlatformOneSecond)
+#define RESTART_GOODBYE_DELAY (2 * mDNSPlatformOneSecond) // delay after restarting LLQ before nuking previous known answers (avoids flutter if we restart before we have networking up)
+#define MIN_UCAST_PERIODIC_EXEC (5 * mDNSPlatformOneSecond) 	
+#define INIT_UCAST_POLL_INTERVAL mDNSPlatformOneSecond      // this interval is used after send failures on network transitions
+	                                                        // which typically heal quickly, so we start agressively and exponentially back off
 #define MAX_UCAST_POLL_INTERVAL (15 * 60 * mDNSPlatformOneSecond)
-#define NO_GOODBYE                       // will we receive goodbye packets from the server?
+#define RESPONSE_WINDOW (60 * mDNSPlatformOneSecond)        // require server responses within one minute of request
 #define UPDATE_PORT_NAME "_dns-update._udp."
 #define LLQ_PORT_NAME "_dns-llq._udp"
 	
 // 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 mDNSBool uDNS_IsActiveQuery(DNSQuestion *const question, uDNS_GlobalInfo *u);  // returns true if OK to call StopQuery
 extern mStatus uDNS_StopQuery(mDNS *const m, DNSQuestion *const question);
-
-// 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 void uDNS_Init(mDNS *m);
+extern void uDNS_Sleep(mDNS *m);
+extern void uDNS_Wake(mDNS *m);
+#define uDNS_Close uDNS_Sleep
+	
+// uDNS_UpdateRecord
+// following fields must be set, and the update validated, upon entry.
+// rr->NewRData
+// rr->newrdlength
+// rr->UpdateCallback
+
+extern mStatus uDNS_AddRecordToService(mDNS *const m, ServiceRecordSet *sr, ExtraResourceRecord *extra);
+extern mStatus uDNS_UpdateRecord(mDNS *m, AuthRecord *rr);
 	
 extern mStatus uDNS_RegisterRecord(mDNS *const m, AuthRecord *const rr);
 extern 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);
+	const mDNSAddr *const srcaddr, const mDNSIPPort srcport, const mDNSAddr *const dstaddr, 
+	const mDNSIPPort dstport, const mDNSInterfaceID InterfaceID);
 
+extern void uDNS_ReceiveNATMap(mDNS *m, mDNSu8 *pkt, mDNSu16 len);
+	
 // returns time of next scheduled event
 extern void uDNS_Execute(mDNS *const m);
 
-extern void uDNS_Init(mDNS *const m);
 	
 #ifdef	__cplusplus
 	}
diff --git a/mDNSMacOS9/CarbonResource.r b/mDNSMacOS9/CarbonResource.r
index 853a4ac..105a398 100644
--- a/mDNSMacOS9/CarbonResource.r
+++ b/mDNSMacOS9/CarbonResource.r
@@ -3,8 +3,6 @@
  *
  * @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/mDNSMacOS9/Mac OS Test Responder.c b/mDNSMacOS9/Mac OS Test Responder.c
index 9ff78dc..cf03862 100644
--- a/mDNSMacOS9/Mac OS Test Responder.c	
+++ b/mDNSMacOS9/Mac OS Test Responder.c	
@@ -3,8 +3,6 @@
  *
  * @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
@@ -25,6 +23,16 @@
     Change History (most recent first):
 
 $Log: Mac\040OS\040Test\040Responder.c,v $
+Revision 1.23  2004/09/17 01:08:50  cheshire
+Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
+  The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
+  declared in that file are ONLY appropriate to single-address-space embedded applications.
+  For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
+
+Revision 1.22  2004/08/13 23:25:01  cheshire
+Now that we do both uDNS and mDNS, global replace "m->hostname" with
+"m->MulticastHostname" for clarity
+
 Revision 1.21  2004/03/12 21:30:25  cheshire
 Build a System-Context Shared Library from mDNSCore, for the benefit of developers
 like Muse Research who want to be able to use mDNS/DNS-SD from GPL-licensed code.
@@ -53,7 +61,7 @@ Update to APSL 2.0
 #include <Events.h>						// For WaitNextEvent()
 #include <SIOUX.h>						// For SIOUXHandleOneEvent()
 
-#include "mDNSClientAPI.h"				// Defines the interface to the client layer above
+#include "mDNSEmbeddedAPI.h"			// Defines the interface to the client layer above
 
 #include "mDNSMacOS9.h"					// Defines the specific types needed to run mDNS on this platform
 
@@ -164,7 +172,7 @@ mDNSlocal OSStatus mDNSResponderTestSetup(mDNS *m)
 	char buffer[MAX_ESCAPED_DOMAIN_NAME];
 	mDNSv4Addr ip = m->HostInterfaces->ip.ip.v4;
 	
-	ConvertDomainNameToCString(&m->hostname, buffer);
+	ConvertDomainNameToCString(&m->MulticastHostname, buffer);
 	printf("Name %s\n", buffer);
 	printf("IP   %d.%d.%d.%d\n", ip.b[0], ip.b[1], ip.b[2], ip.b[3]);
 
diff --git a/mDNSMacOS9/Mac OS Test Searcher.c b/mDNSMacOS9/Mac OS Test Searcher.c
index 6b5d90d..f2fb9ce 100644
--- a/mDNSMacOS9/Mac OS Test Searcher.c	
+++ b/mDNSMacOS9/Mac OS Test Searcher.c	
@@ -3,8 +3,6 @@
  *
  * @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
@@ -25,6 +23,20 @@
     Change History (most recent first):
 
 $Log: Mac\040OS\040Test\040Searcher.c,v $
+Revision 1.20  2004/10/19 21:33:18  cheshire
+<rdar://problem/3844991> Cannot resolve non-local registrations using the mach API
+Added flag 'kDNSServiceFlagsForceMulticast'. Passing through an interface id for a unicast name
+doesn't force multicast unless you set this flag to indicate explicitly that this is what you want
+
+Revision 1.19  2004/09/17 01:08:50  cheshire
+Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
+  The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
+  declared in that file are ONLY appropriate to single-address-space embedded applications.
+  For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
+
+Revision 1.18  2004/09/16 21:59:16  cheshire
+For consistency with zerov6Addr, rename zeroIPAddr to zerov4Addr
+
 Revision 1.17  2004/06/10 04:37:27  cheshire
 Add new parameter in mDNS_GetDomains()
 
@@ -51,7 +63,7 @@ Update to APSL 2.0
 #include <Events.h>						// For WaitNextEvent()
 #include <SIOUX.h>						// For SIOUXHandleOneEvent()
 
-#include "mDNSClientAPI.h"				// Defines the interface to the client layer above
+#include "mDNSEmbeddedAPI.h"			// Defines the interface to the client layer above
 #include "mDNSMacOS9.h"					// Defines the specific types needed to run mDNS on this platform
 
 typedef struct
@@ -155,7 +167,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      = zerov4Addr;
 	info->i.port          = zeroIPPort;
 	info->add             = AddRecord;
 	info->dom             = mDNSfalse;
@@ -188,7 +200,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      = zerov4Addr;
 	info->i.port          = zeroIPPort;
 	info->add             = AddRecord;
 	info->dom             = mDNStrue;
@@ -253,7 +265,7 @@ int main()
 			printf("\nSending mDNS service lookup queries and waiting for responses...\n\n");
 			MakeDomainNameFromDNSNameString(&srvtype, "_http._tcp.");
 			MakeDomainNameFromDNSNameString(&srvdom, "local.");
-			err = mDNS_StartBrowse(&mDNSStorage, &browsequestion, &srvtype, &srvdom, mDNSInterface_Any, FoundInstance, &services);
+			err = mDNS_StartBrowse(&mDNSStorage, &browsequestion, &srvtype, &srvdom, mDNSInterface_Any, mDNSfalse, FoundInstance, &services);
 			if (err) break;
 			err = mDNS_GetDomains(&mDNSStorage, &domainquestion, mDNS_DomainTypeBrowse, NULL, mDNSInterface_Any, FoundDomain, &services);
 			if (err) break;
diff --git a/mDNSMacOS9/Responder.c b/mDNSMacOS9/Responder.c
index d1612f8..2e7135e 100644
--- a/mDNSMacOS9/Responder.c
+++ b/mDNSMacOS9/Responder.c
@@ -3,8 +3,6 @@
  *
  * @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/mDNSMacOS9/Searcher.c b/mDNSMacOS9/Searcher.c
index 4d0d494..a0a562f 100644
--- a/mDNSMacOS9/Searcher.c
+++ b/mDNSMacOS9/Searcher.c
@@ -3,8 +3,6 @@
  *
  * @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/mDNSMacOS9/SubTypeTester.c b/mDNSMacOS9/SubTypeTester.c
new file mode 100644
index 0000000..7c153a3
--- /dev/null
+++ b/mDNSMacOS9/SubTypeTester.c
@@ -0,0 +1,248 @@
+/*
+ * 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: SubTypeTester.c,v $
+Revision 1.5  2004/09/17 01:08:50  cheshire
+Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
+  The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
+  declared in that file are ONLY appropriate to single-address-space embedded applications.
+  For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
+
+Revision 1.4  2004/09/16 00:24:49  cheshire
+<rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
+
+Revision 1.3  2004/08/13 23:25:01  cheshire
+Now that we do both uDNS and mDNS, global replace "m->hostname" with
+"m->MulticastHostname" for clarity
+
+Revision 1.2  2004/08/04 22:11:30  cheshire
+<rdar://problem/3588761> Current method of doing subtypes causes name collisions
+Change to use "._sub." instead of ".s." to mark subtypes.
+
+Revision 1.1  2004/06/11 00:03:28  cheshire
+Add code for testing avail/busy subtypes
+
+
+ */
+
+#include <stdio.h>						// For printf()
+#include <string.h>						// For strlen() etc.
+
+#include <Events.h>						// For WaitNextEvent()
+#include <SIOUX.h>						// For SIOUXHandleOneEvent()
+
+#include "mDNSEmbeddedAPI.h"			// Defines the interface to the client layer above
+
+#include "mDNSMacOS9.h"					// Defines the specific types needed to run mDNS on this platform
+
+// These don't have to be globals, but their memory does need to remain valid for as
+// long as the search is going on. They are declared as globals here for simplicity.
+static mDNS m;
+static mDNS_PlatformSupport p;
+static ServiceRecordSet p1, p2;
+static AuthRecord availRec1, availRec2;
+static Boolean availRec2Active;
+
+// 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.
+// For a device with a user interface, and a screen, and a keyboard, the appropriate
+// response may be to prompt the user and ask them to choose a new name for the service.
+mDNSlocal void Callback(mDNS *const m, ServiceRecordSet *const sr, mStatus result)
+	{
+	switch (result)
+		{
+		case mStatus_NoError:      debugf("Callback: %##s Name Registered",   sr->RR_SRV.resrec.name.c); break;
+		case mStatus_NameConflict: debugf("Callback: %##s Name Conflict",     sr->RR_SRV.resrec.name.c); break;
+		case mStatus_MemFree:      debugf("Callback: %##s Memory Free",       sr->RR_SRV.resrec.name.c); break;
+		default:                   debugf("Callback: %##s Unknown Result %d", sr->RR_SRV.resrec.name.c, result); break;
+		}
+
+	if (result == mStatus_NameConflict) mDNS_RenameAndReregisterService(m, sr, mDNSNULL);
+	}
+
+// RegisterService() is a simple wrapper function which takes C string
+// parameters, converts them to domainname parameters, and calls mDNS_RegisterService()
+mDNSlocal void RegisterService(mDNS *m, ServiceRecordSet *recordset,
+	UInt16 PortAsNumber, const char txtinfo[],
+	const domainlabel *const n, const char type[], const char domain[])
+	{
+	domainname t;
+	domainname d;
+	char buffer[MAX_ESCAPED_DOMAIN_NAME];
+	UInt8 txtbuffer[512];
+
+	MakeDomainNameFromDNSNameString(&t, type);
+	MakeDomainNameFromDNSNameString(&d, domain);
+	
+	if (txtinfo)
+		{
+		strncpy((char*)txtbuffer+1, txtinfo, sizeof(txtbuffer)-1);
+		txtbuffer[0] = (UInt8)strlen(txtinfo);
+		}
+	else
+		txtbuffer[0] = 0;
+
+	mDNS_RegisterService(m, recordset,
+		n, &t, &d,									// Name, type, domain
+		mDNSNULL, mDNSOpaque16fromIntVal(PortAsNumber),
+		txtbuffer, (mDNSu16)(1+txtbuffer[0]),		// TXT data, length
+		mDNSNULL, 0,								// Subtypes (none)
+		mDNSInterface_Any,							// Interface ID
+		Callback, mDNSNULL);						// Callback and context
+
+	ConvertDomainNameToCString(&recordset->RR_SRV.resrec.name, buffer);
+	printf("Made Service Records for %s\n", buffer);
+	}
+
+// 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.
+mDNSlocal void RegisterFakeServiceForTesting(mDNS *m, ServiceRecordSet *recordset, const char txtinfo[],
+	const char name[], const char type[], const char domain[])
+	{
+	static UInt16 NextPort = 0xF000;
+	domainlabel n;
+	MakeDomainLabelFromLiteralString(&n, name);
+	RegisterService(m, recordset, NextPort++, txtinfo, &n, type, domain);
+	}
+
+// Done once on startup, and then again every time our address changes
+mDNSlocal OSStatus mDNSResponderTestSetup(mDNS *m)
+	{
+	char buffer[MAX_ESCAPED_DOMAIN_NAME];
+	mDNSv4Addr ip = m->HostInterfaces->ip.ip.v4;
+	
+	ConvertDomainNameToCString(&m->MulticastHostname, buffer);
+	printf("Name %s\n", buffer);
+	printf("IP   %d.%d.%d.%d\n", ip.b[0], ip.b[1], ip.b[2], ip.b[3]);
+
+	printf("\n");
+	printf("Registering Service Records\n");
+	// Create example printer discovery records
+	//static ServiceRecordSet p1, p2;
+
+	RegisterFakeServiceForTesting(m, &p1, "", "One", "_raop._tcp.", "local.");
+	RegisterFakeServiceForTesting(m, &p2, "", "Two", "_raop._tcp.", "local.");
+
+	return(kOTNoError);
+	}
+
+mDNSlocal void AvailCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
+	{
+	Boolean *b = (Boolean *)rr->RecordContext;
+	(void)m; // Unused
+	// Signal that our record is now free for re-use
+	if (result == mStatus_MemFree) *b = false;
+	}
+
+mDNSlocal OSStatus mDNSResponderSetAvail(mDNS *m, AuthRecord *rr, ServiceRecordSet *sr)
+	{
+	// 1. Initialize required fields of AuthRecord
+	// 2. Set name of subtype PTR record to our special subtype name denoting "available" instances
+	// 3. Set target of subtype PTR record to point to our SRV record (exactly the same as the main service PTR record)
+	// 4. And register it
+	mDNS_SetupResourceRecord(rr, mDNSNULL, mDNSInterface_Any, kDNSType_PTR, 2*3600, kDNSRecordTypeShared, AvailCallback, &availRec2Active);
+	MakeDomainNameFromDNSNameString(&rr->resrec.name, "a._sub._raop._tcp.local.");
+	AssignDomainName(rr->resrec.rdata->u.name, sr->RR_SRV.resrec.name);
+	return(mDNS_Register(m, rr));
+	}
+
+// YieldSomeTime() just cooperatively yields some time to other processes running on classic Mac OS
+mDNSlocal Boolean YieldSomeTime(UInt32 milliseconds)
+	{
+	extern Boolean SIOUXQuitting;
+	EventRecord e;
+	WaitNextEvent(everyEvent, &e, milliseconds / 17, NULL);
+	SIOUXHandleOneEvent(&e);
+	return(SIOUXQuitting);
+	}
+
+int main()
+	{
+	mStatus err;
+	Boolean DoneSetup = false;
+	mDNSs32 nextAvail, nextBusy;
+
+	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");
+
+	err = InitOpenTransport();
+	if (err) { debugf("InitOpenTransport failed %d", err); return(err); }
+
+	err = mDNS_Init(&m, &p, mDNS_Init_NoCache, mDNS_Init_ZeroCacheSize,
+		mDNS_Init_AdvertiseLocalAddresses, mDNS_Init_NoInitCallback, mDNS_Init_NoInitCallbackContext);
+	if (err) return(err);
+
+	while (!YieldSomeTime(35))
+		{
+#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;
+			printf("\nListening for mDNS queries...\n");
+			mDNSResponderTestSetup(&m);
+			mDNSResponderSetAvail(&m, &availRec1, &p1);
+			availRec2Active = false;
+			nextAvail = mDNS_TimeNow(&m) + mDNSPlatformOneSecond * 10;
+			nextBusy  = mDNS_TimeNow(&m) + mDNSPlatformOneSecond * 15;
+			}
+
+		if (DoneSetup)
+			{
+			// We check availRec2.RecordType because we don't want to re-register this record
+			// if the previous mDNS_Deregister() has not yet completed
+			if (mDNS_TimeNow(&m) - nextAvail > 0 && !availRec2Active)
+				{
+				printf("Setting Two now available\n");
+				availRec2Active = true;
+				mDNSResponderSetAvail(&m, &availRec2, &p2);
+				nextAvail = nextBusy + mDNSPlatformOneSecond * 10;
+				}
+			else if (mDNS_TimeNow(&m) - nextBusy > 0)
+				{
+				printf("Setting Two now busy\n");
+				mDNS_Deregister(&m, &availRec2);
+				nextBusy = nextAvail + mDNSPlatformOneSecond * 5;
+				}
+			}
+		}
+	
+	if (p1.RR_SRV.resrec.RecordType) mDNS_DeregisterService(&m, &p1);
+	if (p2.RR_SRV.resrec.RecordType) mDNS_DeregisterService(&m, &p2);
+	if (availRec1.resrec.RecordType) mDNS_Deregister(&m, &availRec1);
+	if (availRec2Active)             mDNS_Deregister(&m, &availRec2);
+
+	mDNS_Close(&m);
+	
+	return(0);
+	}
diff --git a/mDNSMacOS9/mDNS.mcp b/mDNSMacOS9/mDNS.mcp
index fdf6c0ee07628c8364217bfda06a1fbd5bcedd03..24cdedd73790ef4fad01371fb5629adc20362d12 100644
GIT binary patch
delta 6153
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
D#Sh6Y

delta 1138
zcmZXUe`r-@7{{OY-1BSa$NjbG?(S8(?q1j2!aHX%>E65DwKAORc5y;dFoMMxwlSR(
zC9+vCt|8eyzQfo2C!@qbV%8yF&`~NOVJ@RoWL6ZkmVr40iP-G+ocV@94}8z(JkNRF
z^S<x%KIcpy%6>SOUe-G_GyniT08$VBU8vm!fX*!#s`+@CpN#510iZ};0)kJx`$Z$4
z-6yOSehgm`2dGW~L@-2R(EDun>XDa5(2<~d*9oL&I28m0t;y>@>?oJNKJ7jDuZ8|~
z=*yus?p%I~xW|33`RpLZ;|5+(Nw-;Z40<4wam%575xT!2N55-GIh_`7`&3dT8t+cx
z&>7-}QVX`?$58?H^Nf;XA1s(TdNBKih3j}6l}2UgwsTcs4WMQHhOVcOx%;I1S|{k$
z%sQ5sQ66#%57VaMCGN$x3oklPr`@lPUW%~9N7A=ASCkD^8@jvybi0zQ0El_Rkx{`K
z!8$>M&V3#aNuH;RNo{~Gy6SARH{2F!je-e}7FJR)Ku6EM*@cPqBB4oel}FrbkKjfT
z4+sVYLxNR;m2~sDrpo{CAK2?}X{|JFDl}WI(N`lTyY`LTNLKPM3uKSPCT4v)Plcp;
z;+8Jx^)go3&$s*~Z;-X?mnQ*QkMZrlsPlxsUzT_3Iv)78a{1s55sVqi0gH{kp#}Lp
zlhi%I_LNkOX4-0LZ(F=LkS8b!<>Lc+`S&r_lqV+ETIYiu{^6}W&}ei#=M<jgCwG#g
zg!PO`-iiN4*xYuX%)>{NTX!kVu3qAuJysX6fPmFr>_5wC&+^fdI)Bw$v%wxMsY%vT
zQfrE5`ZSb|s^Dk(j6>^`q}R{1bUV&-cgYK0XQ}+{K8r~F@Syx|f@e?pma6Rb4W+g?
zF=g<HDKl*I?kn<%2tRd8?yun2{*;FZ@A%u4&pU-6-}sK)6{IKE*!+=WR&*)5_^UOJ
zjT~DU#uKeXRiSE7QB(}I0+m2{tx-qAtt}O6v1cDcweZP1c7K}x*zQjgUjE*?>|?bz
ztxC4(j<uYnZdz(_eAeRQv-YKDyrd#=3cFkE`hxd45AGNl#?3!4`O5PETlZqz`zt&!
zbNW0kU@se9@V}?QABO>!Z|2c^en-|wz83R3`6nc>LeaFoSJ2DxX*GZy0NG88UV|Cv
GPyYi6B`rt*

diff --git a/mDNSMacOS9/mDNSLibrary.c b/mDNSMacOS9/mDNSLibrary.c
index a8ac4a9..13dc10a 100644
--- a/mDNSMacOS9/mDNSLibrary.c
+++ b/mDNSMacOS9/mDNSLibrary.c
@@ -3,8 +3,6 @@
  *
  * @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
@@ -25,6 +23,12 @@
     Change History (most recent first):
 
 $Log: mDNSLibrary.c,v $
+Revision 1.2  2004/09/17 01:08:50  cheshire
+Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
+  The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
+  declared in that file are ONLY appropriate to single-address-space embedded applications.
+  For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
+
 Revision 1.1  2004/03/12 21:30:26  cheshire
 Build a System-Context Shared Library from mDNSCore, for the benefit of developers
 like Muse Research who want to be able to use mDNS/DNS-SD from GPL-licensed code.
@@ -33,7 +37,7 @@ 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 "mDNSEmbeddedAPI.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;
diff --git a/mDNSMacOS9/mDNSLibraryLoader.c b/mDNSMacOS9/mDNSLibraryLoader.c
index c708eac..d671d77 100644
--- a/mDNSMacOS9/mDNSLibraryLoader.c
+++ b/mDNSMacOS9/mDNSLibraryLoader.c
@@ -3,8 +3,6 @@
  *
  * @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/mDNSMacOS9/mDNSLibraryResources.r b/mDNSMacOS9/mDNSLibraryResources.r
index c77311c..b699ed5 100644
--- a/mDNSMacOS9/mDNSLibraryResources.r
+++ b/mDNSMacOS9/mDNSLibraryResources.r
@@ -3,8 +3,6 @@
  *
  * @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
@@ -25,6 +23,45 @@
     Change History (most recent first):
 
 $Log: mDNSLibraryResources.r,v $
+Revision 1.17  2004/12/13 21:54:30  cheshire
+mDNSResponder-87
+
+Revision 1.16  2004/12/06 19:09:47  cheshire
+mDNSResponder-86
+
+Revision 1.15  2004/11/29 23:36:15  cheshire
+mDNSResponder-85
+
+Revision 1.14  2004/11/23 03:46:31  cheshire
+mDNSResponder-84
+
+Revision 1.13  2004/10/26 20:30:30  cheshire
+mDNSResponder-82
+
+Revision 1.12  2004/10/14 23:38:04  cheshire
+mDNSResponder-80
+
+Revision 1.11  2004/10/07 21:49:15  cheshire
+mDNSResponder-79
+
+Revision 1.10  2004/09/25 02:52:09  cheshire
+mDNSResponder-78
+
+Revision 1.9  2004/09/22 22:52:07  cheshire
+mDNSResponder-77
+
+Revision 1.8  2004/09/21 00:20:52  cheshire
+mDNSResponder-76
+
+Revision 1.7  2004/09/15 19:45:06  cheshire
+mDNSResponder-75
+
+Revision 1.6  2004/09/09 23:32:35  cheshire
+mDNSResponder-74
+
+Revision 1.5  2004/08/10 21:51:45  cheshire
+mDNSResponder-69
+
 Revision 1.4  2004/06/10 20:28:16  cheshire
 Update version string to 1.0a66
 
@@ -55,15 +92,15 @@ like Muse Research who want to be able to use mDNS/DNS-SD from GPL-licensed code
 
 resource 'vers' (1, purgeable)
 	{
-   0x01, 0x00, alpha, 66, verUS,
-   "1.0a66",
-   "Multicast DNS & DNS Service Discovery 1.0a66"
+   0x01, 0x00, alpha, 87, verUS,
+   "1.0a87",
+   "Multicast DNS & DNS Service Discovery 1.0a87"
 	};
 
 resource 'vers' (2, purgeable)
 	{
-   0x01, 0x00, alpha, 66, verUS,
-   "1.0a66",
+   0x01, 0x00, alpha, 87, verUS,
+   "1.0a87",
    "developer.apple.com/darwin/projects/rendezvous/"
 	};
 
diff --git a/mDNSMacOS9/mDNSMacOS9.c b/mDNSMacOS9/mDNSMacOS9.c
index 6563112..d38facc 100644
--- a/mDNSMacOS9/mDNSMacOS9.c
+++ b/mDNSMacOS9/mDNSMacOS9.c
@@ -3,8 +3,6 @@
  *
  * @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
@@ -25,6 +23,49 @@
     Change History (most recent first):
 
 $Log: mDNSMacOS9.c,v $
+Revision 1.41  2004/10/16 00:17:00  cheshire
+<rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check
+
+Revision 1.40  2004/09/27 23:56:27  cheshire
+Fix infinite loop where mDNSPlatformUnlock() called mDNS_TimeNow(),
+and then mDNS_TimeNow() called mDNSPlatformUnlock()
+
+Revision 1.39  2004/09/21 21:02:54  cheshire
+Set up ifname before calling mDNS_RegisterInterface()
+
+Revision 1.38  2004/09/17 01:08:50  cheshire
+Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
+  The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
+  declared in that file are ONLY appropriate to single-address-space embedded applications.
+  For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
+
+Revision 1.37  2004/09/17 00:19:10  cheshire
+For consistency with AllDNSLinkGroupv6, rename AllDNSLinkGroup to AllDNSLinkGroupv4
+
+Revision 1.36  2004/09/16 21:59:16  cheshire
+For consistency with zerov6Addr, rename zeroIPAddr to zerov4Addr
+
+Revision 1.35  2004/09/16 00:24:49  cheshire
+<rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
+
+Revision 1.34  2004/09/14 23:42:36  cheshire
+<rdar://problem/3801296> Need to seed random number generator from platform-layer data
+
+Revision 1.33  2004/09/14 23:16:31  cheshire
+Fix compile error: mDNS_SetFQDNs has been renamed to mDNS_SetFQDN
+
+Revision 1.32  2004/09/14 21:03:16  cheshire
+Fix spacing
+
+Revision 1.31  2004/08/14 03:22:42  cheshire
+<rdar://problem/3762579> Dynamic DNS UI <-> mDNSResponder glue
+Add GetUserSpecifiedDDNSName() routine
+Convert ServiceRegDomain to domainname instead of C string
+Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs
+
+Revision 1.30  2004/07/29 19:26:03  ksekar
+Plaform-level changes for NATPMP support
+
 Revision 1.29  2004/05/26 20:53:16  cheshire
 Remove unncecessary "return( -1 );" at the end of mDNSPlatformUTC()
 
@@ -55,10 +96,10 @@ 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.
+Best solution is just to combine mDNSEmbeddedAPI.h and mDNSPlatformFunctions.h into a single file.
 
 Revision 1.19  2003/08/18 23:09:20  cheshire
-<rdar://problem/3382647> mDNSResponder divide by zero in mDNSPlatformTimeNow()
+<rdar://problem/3382647> mDNSResponder divide by zero in mDNSPlatformRawTime()
 
 Revision 1.18  2003/08/12 19:56:24  cheshire
 Update to APSL 2.0
@@ -72,7 +113,7 @@ Update to APSL 2.0
 #include <TextUtils.h>					// For smSystemScript
 #include <UnicodeConverter.h>			// For ConvertFromPStringToUnicode()
 
-#include "mDNSClientAPI.h"				// Defines the interface provided to the client layer above
+#include "mDNSEmbeddedAPI.h"				// Defines the interface provided to the client layer above
 
 #include "mDNSMacOS9.h"					// Defines the specific types needed to run mDNS on this platform
 
@@ -165,7 +206,7 @@ mDNSexport void LogMsg(const char *format, ...)
 	}
 #endif
 
-mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end,
+mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const msg, const mDNSu8 *const end,
 	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
@@ -223,11 +264,11 @@ mDNSlocal OSStatus readpacket(mDNS *m)
 	senderport.NotAnInteger = sender.fPort;
 	
 	destaddr.type = mDNSAddrType_IPv4;
-	destaddr.ip.v4  = zeroIPAddr;
+	destaddr.ip.v4  = zerov4Addr;
 
 	#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;
+	destaddr.ip.v4  = AllDNSLinkGroupv4;
 	#endif
 
 	if (recvdata.opt.len)
@@ -246,8 +287,7 @@ mDNSlocal OSStatus readpacket(mDNS *m)
 
 	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);
-	else if (recvdata.udata.len < sizeof(DNSMessageHeader)) debugf("ERROR: recvdata.udata.len (%d) too short", recvdata.udata.len);
-	else mDNSCoreReceive(m, &packet, recvdata.udata.buf + recvdata.udata.len, &senderaddr, senderport, &destaddr, MulticastDNSPort, interface, 255);
+	else mDNSCoreReceive(m, &packet, recvdata.udata.buf + recvdata.udata.len, &senderaddr, senderport, &destaddr, MulticastDNSPort, interface);
 	
 	return(err);
 	}
@@ -324,11 +364,14 @@ mDNSlocal pascal void mDNSNotifier(void *contextPtr, OTEventCode code, OTResult
 			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.McastTxRx             = mDNStrue;
+			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.mask.type               = mDNSAddrType_IPv4;
+			m->p->interface.mask.ip.v4.NotAnInteger = interfaceinfo.fMask;
+			m->p->interface.ifname[0]               = 0;
+			m->p->interface.Advertise               = m->AdvertiseLocalAddresses;
+			m->p->interface.McastTxRx               = mDNStrue;
 			}
 			
 		case T_OPTMGMTCOMPLETE:
@@ -572,7 +615,7 @@ mDNSexport mStatus mDNSPlatformInit(mDNS *const m)
 	ConvertUTF8PstringToRFC1034HostLabel(m->nicelabel.c, &m->hostlabel);
 	if (m->hostlabel.c[0] == 0) MakeDomainLabelFromLiteralString(&m->hostlabel, "Macintosh");
 
-	mDNS_GenerateFQDN(m);
+	mDNS_SetFQDN(m);
 
 	// When it's finished mDNSOpenEndpoint asynchronously calls mDNSinitComplete() and then mDNS_RegisterInterface()
 	CallmDNSNotifierUPP = NewOTNotifyUPP(CallmDNSNotifier);
@@ -655,7 +698,7 @@ mDNSlocal void ScheduleNextTimerCallback(const mDNS *const m)
 	{
 	if (m->mDNSPlatformStatus == mStatus_NoError)
 		{
-		SInt32 interval = m->NextScheduledEvent - mDNSPlatformTimeNow();
+		SInt32 interval = m->NextScheduledEvent - (mDNSPlatformRawTime() + m->timenow_adjust);
 		if      (interval < 1)                 interval = 1;
 		else if (interval > 0x70000000 / 1000) interval = 0x70000000 / mDNSPlatformOneSecond;
 		else                                   interval = (interval * 1000 + mDNSPlatformOneSecond-1)/ mDNSPlatformOneSecond;
@@ -680,9 +723,10 @@ mDNSexport void     mDNSPlatformMemCopy(const void *src,       void *dst, UInt32
 mDNSexport mDNSBool mDNSPlatformMemSame(const void *src, const void *dst, UInt32 len) { return(OTMemcmp(dst, src, len)); }
 mDNSexport void     mDNSPlatformMemZero(                       void *dst, UInt32 len) { OTMemzero(dst, len); }
 mDNSexport void *   mDNSPlatformMemAllocate(mDNSu32 len)                              { return(OTAllocMem(len)); }
-mDNSexport void     mDNSPlatformMemFree    (void *mem)                                { OTFreeMem(mem); }
-mDNSexport mStatus  mDNSPlatformTimeInit(mDNSs32 *timenow) { *timenow = mDNSPlatformTimeNow(); return(mStatus_NoError); }
-mDNSexport SInt32   mDNSPlatformTimeNow()                                             { return((SInt32)TickCount()); }
+mDNSexport void     mDNSPlatformMemFree(void *mem)                                    { OTFreeMem(mem); }
+mDNSexport mDNSu32  mDNSPlatformRandomSeed(void)                                      { return(TickCount()); }
+mDNSexport mStatus  mDNSPlatformTimeInit(void)                                        { return(mStatus_NoError); }
+mDNSexport SInt32   mDNSPlatformRawTime()                                             { return((SInt32)TickCount()); }
 mDNSexport SInt32   mDNSPlatformOneSecond = 60;
 
 mDNSexport mDNSs32	mDNSPlatformUTC(void)
diff --git a/mDNSMacOS9/mDNSMacOS9.h b/mDNSMacOS9/mDNSMacOS9.h
index 03c7bd5..c4fa310 100755
--- a/mDNSMacOS9/mDNSMacOS9.h
+++ b/mDNSMacOS9/mDNSMacOS9.h
@@ -3,8 +3,6 @@
  *
  * @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/mDNSMacOS9/mDNSPrefix.h b/mDNSMacOS9/mDNSPrefix.h
index 3d1b0aa..80adab4 100644
--- a/mDNSMacOS9/mDNSPrefix.h
+++ b/mDNSMacOS9/mDNSPrefix.h
@@ -3,8 +3,6 @@
  *
  * @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
@@ -25,6 +23,9 @@
     Change History (most recent first):
 
 $Log: mDNSPrefix.h,v $
+Revision 1.3  2004/06/11 00:03:28  cheshire
+Add code for testing avail/busy subtypes
+
 Revision 1.2  2004/05/21 01:57:08  cheshire
 Add macros for malloc() and free() so that dnssd_clientlib.c can use them
 
@@ -46,26 +47,32 @@ like Muse Research who want to be able to use mDNS/DNS-SD from GPL-licensed code
 // 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")
+#if   __ide_target("Standalone TestResponder")           || __ide_target("Standalone TestSearcher")           || __ide_target("Standalone SubTypeTester")
 #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
diff --git a/mDNSMacOSX/DNSServiceDiscoveryDefines.h b/mDNSMacOSX/DNSServiceDiscoveryDefines.h
index bd5b11b..c2f50c1 100644
--- a/mDNSMacOSX/DNSServiceDiscoveryDefines.h
+++ b/mDNSMacOSX/DNSServiceDiscoveryDefines.h
@@ -3,8 +3,6 @@
  *
  * @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
@@ -25,6 +23,9 @@
     Change History (most recent first):
 
 $Log: DNSServiceDiscoveryDefines.h,v $
+Revision 1.6  2004/09/20 21:45:27  ksekar
+Mach IPC cleanup
+
 Revision 1.5  2003/08/12 19:56:25  cheshire
 Update to APSL 2.0
 
@@ -41,5 +42,6 @@ typedef char    DNSCString[1024];
 typedef char    sockaddr_t[128];
 
 typedef const char * record_data_t;
+typedef struct { char bytes[4]; } IPPort;
 
 #endif	/* __DNS_SERVICE_DISCOVERY_DEFINES_H */
diff --git a/mDNSMacOSX/DNSServiceDiscoveryReply.defs b/mDNSMacOSX/DNSServiceDiscoveryReply.defs
index 6ae6004..942fb6b 100644
--- a/mDNSMacOSX/DNSServiceDiscoveryReply.defs
+++ b/mDNSMacOSX/DNSServiceDiscoveryReply.defs
@@ -3,8 +3,6 @@
  *
  * @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/DNSServiceDiscoveryRequest.defs b/mDNSMacOSX/DNSServiceDiscoveryRequest.defs
index a4596af..b6d9cf8 100644
--- a/mDNSMacOSX/DNSServiceDiscoveryRequest.defs
+++ b/mDNSMacOSX/DNSServiceDiscoveryRequest.defs
@@ -3,8 +3,6 @@
  *
  * @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
@@ -36,6 +34,7 @@ import "DNSServiceDiscoveryDefines.h";
 type DNSCString = c_string[*:1024];
 type record_data = ^ array [] of MACH_MSG_TYPE_BYTE
 				ctype: record_data_t;
+type IPPort = struct[4] of char ctype:IPPort;				
 
 simpleroutine DNSServiceBrowserCreate_rpc(
 				server: mach_port_t;
@@ -55,7 +54,7 @@ simpleroutine DNSServiceRegistrationCreate_rpc(
                         in	name: DNSCString;
                         in	regtype: DNSCString;
                         in	domain: DNSCString;
-                        in	port: int;
+                        in	port: IPPort;
                         in	txtRecord: DNSCString);
 
                         
diff --git a/mDNSMacOSX/LegacyNATTraversal.c b/mDNSMacOSX/LegacyNATTraversal.c
new file mode 100644
index 0000000..d8f0480
--- /dev/null
+++ b/mDNSMacOSX/LegacyNATTraversal.c
@@ -0,0 +1,3010 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+
+$Log: LegacyNATTraversal.c,v $
+Revision 1.11  2004/12/03 03:34:20  ksekar
+<rdar://problem/3882674> LegacyNATTraversal.c leaks threads
+
+Revision 1.10  2004/12/01 02:43:49  cheshire
+Update copyright message
+
+Revision 1.9  2004/10/27 02:25:05  cheshire
+<rdar://problem/3816029> Random memory smashing bug
+
+Revision 1.8  2004/10/27 02:17:21  cheshire
+Turn off "safe_close: ERROR" error messages -- there are too many of them
+
+Revision 1.7  2004/10/26 21:15:40  cheshire
+<rdar://problem/3854314> Legacy NAT traversal code closes file descriptor 0
+Additional fixes: Code should set fds to -1 after closing sockets.
+
+Revision 1.6  2004/10/26 20:59:20  cheshire
+<rdar://problem/3854314> Legacy NAT traversal code closes file descriptor 0
+
+Revision 1.5  2004/10/26 01:01:35  cheshire
+Use "#if 0" instead of commenting out code
+
+Revision 1.4  2004/10/10 06:51:36  cheshire
+Declared some strings "const" as appropriate
+
+Revision 1.3  2004/09/21 23:40:12  ksekar
+<rdar://problem/3810349> mDNSResponder to return errors on NAT traversal failure
+
+Revision 1.2  2004/09/17 01:08:52  cheshire
+Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
+  The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
+  declared in that file are ONLY appropriate to single-address-space embedded applications.
+  For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
+
+Revision 1.1  2004/08/18 17:35:41  ksekar
+<rdar://problem/3651443>: Feature #9586: Need support for Legacy NAT gateways
+
+
+*/
+
+#include "mDNSEmbeddedAPI.h"
+#include "mDNSMacOSX.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <netdb.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <sched.h>
+#include <time.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <errno.h>
+
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/sysctl.h>
+#include <net/route.h>
+#include "memory.h"
+#include <ctype.h>
+#include <arpa/inet.h>
+
+//#include "IPAddr.h"
+//#include "upnp.h"
+//#include "debug.h"
+
+// use error codes
+//#include "netaddr.h"
+
+// TODO: remove later and do variable length
+#define MAX_SOAPMSGSIZE		65536
+
+static int safe_close(int fd)
+	{
+	if (fd < 3) { /* LogMsg("safe_close: ERROR sd %d < 3", fd); */ return(-1); }
+	return(close(fd));
+	}
+
+#define close safe_close
+
+////////////////////////////////////////////////////////////////////////
+// NetAddr Functions
+////////////////////////////////////////////////////////////////////////
+
+// Return codes
+#define NA_E_SUCCESS				(0)
+#define NA_E_INTERNAL_ERROR			(-1)	/* somewhere something wrong */
+#define NA_E_INVALID_PARAMETER		(-2)	/* bad params */
+#define NA_E_OPERATION_FAILED		(-3)	/* can't fulfill request */
+#define NA_E_TIMEOUT				(-4)	/* operation timed out */
+#define NA_E_THREAD_ERROR			(-5)	/* some error related to threads */
+#define NA_E_PARSE_ERROR			(-6)	/* a parsing error occured */
+#define NA_E_NOT_READY				(-7)	/* this op can't proceed yet */
+#define NA_E_NOT_FOUND				(-8)	/* resource/prereq not found */
+#define NA_E_NOT_AVAILABLE			(-9)	/* service not available */
+#define NA_E_EXISTS					(-10)	/* can't modify existing item */
+#define NA_E_AGAIN					(-11)	/* something wrong - try again */
+#define NA_E_NOT_SUPPORTED			(-12)	/* wait until next version */
+#define NA_E_ABORT					(-14)	/* operation aborted */
+#define NA_E_NET					(-15)	/* network layer problem */
+
+// Logging flags - log types (increasing degree of detail)
+#define NALOG_ERROR					(1UL)		/* error messages */
+#define NALOG_ALERT					(2UL)		/* useful warning/alerts */
+#define NALOG_INFO0					(4UL)		/* info - potential problem */
+#define NALOG_INFO1					(8UL)		/* extra info */
+#define NALOG_DUMP					(16UL)		/* data dumps */
+
+#define NALOG_RSRV1					(32UL)		/* reserved */
+#define NALOG_RSRV2					(64UL)		/* reserved */
+#define NALOG_RSRV3					(128UL)		/* reserved */
+
+// Logging flags - component (not used for now)
+#define NALOG_UPNP					(256)		/* UPnP */
+
+// Default Logging levels
+#define NALOG_LEVEL0				(0)
+#define NALOG_LEVEL1				(NALOG_UPNP | NALOG_ERROR)
+#define NALOG_LEVEL2				(NALOG_LEVEL1 | NALOG_ALERT)
+#define NALOG_LEVEL3				(NALOG_LEVEL2 | NALOG_INFO0)
+#define NALOG_LEVEL4				(NALOG_LEVEL3 | NALOG_INFO1)
+#define NALOG_LEVEL5				(NALOG_LEVEL4 | NALOG_DUMP)
+#define NALOG_DEFAULT_LEVEL			(NALOG_LEVEL2)
+
+// Default timeout values (in m-seconds (milli))
+// 50 milliseconds for function timeout
+#define NA_DEFAULT_FUNCTION_TIMEOUT	(50)
+
+////////////////////////////////////////////////////////////////////////
+// GLOBAL Defines
+////////////////////////////////////////////////////////////////////////
+#define SSDP_IP "239.255.255.250"
+#define SSDP_PORT 1900
+#define SSDP_TTL 4
+
+#define CRLF "\r\n"
+#define H_CRLF "\r\n"
+// SOAP message's CRLF:
+//#define S_CRLF "\r\n"
+#define S_CRLF
+
+// standard 200 ok msg
+#define HTTP200OK		"HTTP/1.1 200 OK\r\n\r\n"
+#define HTTP200OKLEN	(sizeof(HTTP200OK) - 1)
+
+// maximum time to wait for an event (in microseconds)
+#define MAX_EXPECTEVENTTIME		(10000)
+
+////////////////////////////////////////////////////////////////////////
+// GLOBAL Data Types
+////////////////////////////////////////////////////////////////////////
+typedef struct tagProperty {
+	char		*pszName;
+	char		*pszValue;
+	char		*pszType;
+} Property, *PProperty;
+
+typedef struct tagHTTPResponse {
+	char		*pszStatus;
+	char		*pszReason;
+	int			iNumHeaders;
+	Property	aHeaders[30];  // assume at most this many headers
+	char		*pszBody;
+
+	// for admin use
+	int			fFree;
+	char		*buf;
+} HTTPResponse, *PHTTPResponse, **PPHTTPResponse;
+
+////////////////////////////////////////////////////////////////////////
+// GLOBAL Constants
+////////////////////////////////////////////////////////////////////////
+static const char szSSDPMsgDiscoverRoot[] =
+	"M-SEARCH * HTTP/1.1\r\n"
+	"Host:239.255.255.250:1900\r\n"
+	"ST:upnp:rootdevice\r\n"
+	"Man:\"ssdp:discover\"\r\n"
+	"MX:3\r\n"
+	"\r\n";
+
+static const char szSSDPMsgDiscoverIGD[] =
+	"M-SEARCH * HTTP/1.1\r\n"
+	"Host:239.255.255.250:1900\r\n"
+	"ST:urn:schemas-upnp-org:device:InternetGatewayDevice:1\r\n"
+	"Man:\"ssdp:discover\"\r\n"
+	"MX:3\r\n"
+	"\r\n";
+
+static const char szSSDPMsgDiscoverNAT[] =
+	"M-SEARCH * HTTP/1.1\r\n"
+	"Host:239.255.255.250:1900\r\n"
+	"ST:urn:schemas-upnp-org:service:WANIPConnection:1\r\n"
+	"Man:\"ssdp:discover\"\r\n"
+	"MX:3\r\n"
+	"\r\n";
+
+//// Subscribe message
+// 1$s: control URL
+// 2$s: local's host/port ("host:port")
+// 3$s: router's host/port ("host:port")
+// 4$d: subscription timeout in seconds
+static const char szEventMsgSubscribeFMT[] =
+	"SUBSCRIBE %1$s HTTP/1.1\r\n"
+	"NT: upnp:event\r\n"
+	"Callback: <http://%2$s/notify>\r\n"
+	"Timeout: Second-%4$d\r\n"
+	"User-Agent: Mozilla/4.0 (compatible; UPnP/1.0; Windows NT/5.1)\r\n"
+	"Host: %3$s\r\n"
+	"Content-Length: 0\r\n"
+	"Pragma: no-cache\r\n"
+	"\r\n";
+
+//// Unsubscribe message
+// 1$s: control URL
+// 2$s: SID (some uuid passed back during subscribe)
+// 3$s: router's host ("host")
+#if 0
+static const char szEventMsgUnsubscribeFMT[] =
+	"UNSUBSCRIBE %1$s HTTP/1.1\r\n"
+	"SID: %2$s\r\n"
+	"User-Agent: Mozilla/4.0 (compatible; UPnP/1.0; Windows NT/5.1)\r\n"
+	"Host: %3$s\r\n"
+	"Content-Length: 0\r\n"
+	"Pragma: no-cache\r\n"
+	"\r\n";
+#endif
+
+//// Generic SOAP Control:Action request messages
+// 1$s: control URL
+// 2$s: router's host/port ("host:port")
+// 3$s: action (string)
+// 4$d: content-length
+static const char szSOAPMsgControlAHeaderFMT[] =
+	//"M-POST %1$s HTTP/1.1\r\n"
+	"POST %1$s HTTP/1.1\r\n"
+	"Content-Type: text/xml; charset=\"utf-8\"\r\n"
+	//"TEST: \"http://schemas.xmlsoap.org/soap/envelope/\"; ns=01\r\n"
+	//"Man: \"http://schemas.xmlsoap.org/soap/envelope/\"; ns=01\r\n"
+	//"01-SOAPAction: \"urn:schemas-upnp-org:service:WANIPConnection:1#%3$s\"\r\n"
+	"SOAPAction: \"urn:schemas-upnp-org:service:WANIPConnection:1#%3$s\"\r\n"
+	"User-Agent: Mozilla/4.0 (compatible; UPnP/1.0; Windows 9x)\r\n"
+	"Host: %2$s\r\n"
+	"Content-Length: %4$d\r\n"
+	"Connection: close\r\n"
+//	"Connection: Keep-Alive\r\n"
+	"Pragma: no-cache\r\n"
+	"\r\n";
+
+// 1$: action (string)
+// 2$: argument list
+static const char szSOAPMsgControlABodyFMT[] =
+	"<?xml version=\"1.0\"?>" CRLF
+	"<SOAP-ENV:Envelope" S_CRLF
+	" xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\"" S_CRLF
+	" SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" S_CRLF
+	"<SOAP-ENV:Body>" S_CRLF
+	"<m:%1$s" S_CRLF
+	" xmlns:m=\"urn:schemas-upnp-org:service:WANIPConnection:1\">" S_CRLF
+	"%2$s" 
+	"</m:%1$s>" S_CRLF
+	"</SOAP-ENV:Body>" S_CRLF
+	"</SOAP-ENV:Envelope>" S_CRLF
+//	CRLF
+//	"0"
+//	CRLF
+	CRLF;
+
+// 1$: argument name
+// 2$: argument value
+static const char szSOAPMsgControlAArgumentFMT[] =
+	"<%1$s>%2$s</%1$s>" S_CRLF;
+
+// 1$: argument name
+// 2$: argument value
+// 3$: argument type
+static const char szSOAPMsgControlAArgumentFMT_t[] =
+	"<%1$s"
+	" xmlns:dt=\"urn:schemas-microsoft-com:datatypes\""
+	" dt:dt=\"%3$s\">%2$s</%1$s>" S_CRLF;
+
+#if 0
+//// Generic SOAP Control:Query request messages
+// 1$s: control URL
+// 2$s: router's host/port ("host:port")
+// 3$d: content-length
+static const char szSOAPMsgControlQHeaderFMT[] =
+	"M-POST %1$s HTTP/1.1\r\n"
+	//"POST %1$s HTTP/1.1\r\n"
+	"Host: %2$s\r\n"
+	"Content-Length: %3$d\r\n"
+	"Content-Type: text/xml; charset-\"utf-8\"\r\n"
+	//"Man: \"http://schemas.xmlsoap.org/soap/envelope/\"; ns=01\r\n"
+	//"SOAPAction: \"urn:schemas-upnp-org:control-1-0#QueryStateVariable\"\r\n"
+	"01-SOAPAction: \"urn:schemas-upnp-org:control-1-0#QueryStateVariable\"\r\n"
+	"\r\n";
+
+// 1$: variable name
+static const char szSOAPMsgControlQBodyFMT[] =
+	"<s:Envelope" S_CRLF
+	" xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\"" S_CRLF
+	" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" S_CRLF
+	"<s:Body>" S_CRLF
+	"<u:QueryStateVariable xmlns:u=\"urn:schemas-upnp-org:control-1-0\"" S_CRLF
+	"<u:varName>%s</u:varName>" S_CRLF
+	"</u:QueryStateVariable>" S_CRLF
+	"</s:Body>" S_CRLF
+	"</s:Envelope>" S_CRLF
+	"" S_CRLF;
+#endif
+// 1$: device description URL
+// 2$: host/port
+static const char szSSDPMsgDescribeDeviceFMT[] =
+	"GET %s HTTP/1.1\r\n"
+	"Accept: text/xml, application/xml\r\n"
+	"User-Agent: Mozilla/4.0 (compatible; UPnP/1.0; Windows NT/5.1)\r\n"
+	"Host: %s\r\n"
+	"Connection: close\r\n"
+//	"Connection: Keep-Alive\r\n"
+	"\r\n";
+
+////////////////////////////////////////////////////////////////////////
+// GLOBAL Variables
+////////////////////////////////////////////////////////////////////////
+
+static int					g_fFirstInit = TRUE;
+static int					g_fQuit = FALSE;
+static FILE					*g_log;
+static int					g_fLogging;
+
+// Globally-accessible UDP socket
+static int					g_sUDP       = -1;
+static int					g_sUDPCancel = -1;
+
+// Globally-accessible TCP socket
+static int					g_sTCP       = -1;
+static int					g_sTCPCancel = -1;
+
+// Event Vars
+static int					g_fEventEnabled = FALSE;
+static unsigned short		g_wEventPort;
+static struct sockaddr_in	g_saddrRouterEvent;
+static char 				g_szRouterHostPortEvent[1024];
+static char 				g_szEventURL[1024];
+
+// UPnP Router info
+static char 				g_szFriendlyName[1024];
+static char 				g_szManufacturer[1024];
+static char 				g_szModelName[1024];
+static char 				g_szModelDescription[1024];
+
+// URL base
+static struct sockaddr_in	g_saddrRouterBase;
+static char 				g_szRouterHostPortBase[1024];
+
+// the threads
+static pthread_t			g_UDPthread = NULL;
+static pthread_t			g_TCPthread = NULL;
+
+// Local IP
+static unsigned long		g_dwLocalIP = 0;
+
+// Globally accessible info about the router/UPnP
+static int					g_fUPnPEnabled = FALSE;
+static char 				g_szUSN[1024];
+
+static struct sockaddr_in	g_saddrRouterDesc;
+static char 				g_szRouterHostPortDesc[1024];
+static char 				g_szNATDevDescURL[1024];
+
+static struct sockaddr_in	g_saddrRouterSOAP;
+static char 				g_szRouterHostPortSOAP[1024];
+static char 				g_szControlURL[1024];
+static int					g_fControlURLSet = FALSE;
+
+// Lock/condvar for synchronous upnp calls
+static pthread_mutex_t				g_xUPnP;
+static pthread_mutex_t				g_xUPnPMsg;
+static pthread_cond_t				g_condUPnP;
+static pthread_cond_t				g_condUPnPControlURL;
+static struct timeval				g_tvUPnPInitTime;
+static struct timeval				g_tvLastUpdateTime;
+
+// timeout values in seconds
+static int      					g_iFunctionTimeout = NA_DEFAULT_FUNCTION_TIMEOUT;
+
+static void GetDeviceDescription(void);
+static void SetLocalIP(void);
+
+////////////////////////////////////////////////////////////////////////
+// IPAddr Functions
+////////////////////////////////////////////////////////////////////////
+
+
+#define ISIPV6          0x01
+#define ISPPP           0x02
+#define IFNAMELEN       16      /* Interface Name Length                */
+#define IPLEN           16      /* 16 bytes(128 bits) for IPv6  */
+
+typedef struct tagIPINFO
+{
+        int                             iFlags;
+        char                    szIfName[IFNAMELEN];    /* Interface name                       */
+        unsigned char   abIP[IPLEN];                    /* IP in host byte order        */
+        unsigned short  wPort;
+} IPINFO, *PIPINFO, **PPIPINFO;
+
+typedef struct hostent	HOSTENT, *PHOSTENT;
+
+static unsigned long GetNATIPNetmask(unsigned long dwIP)
+{
+	if ((dwIP & 0xFF000000) == 0x0A000000)  return 0xFF000000;
+	if ((dwIP & 0xFFF00000) == 0xAC100000)  return 0xFFF00000;
+	if ((dwIP & 0xFFFF0000) == 0xC0a80000)  return 0xFFFF0000;
+
+	return 0;	/* No NAT IP */
+}
+
+static int GetIPInfo(PPIPINFO ppIPInfo)
+{
+	int				fd;
+	int				iLastLen, iLen, iNum = 0, iMax = 0;
+	unsigned long	dwIP;
+	char			*pcBuf, *pcTemp;
+	PIPINFO			pIPInfo = NULL;
+	struct ifconf	ifc;
+	struct ifreq	*ifr, ifrcopy;
+
+	if (ppIPInfo == NULL) return 0;
+
+	fd = socket(AF_INET, SOCK_DGRAM, 0);
+
+	iLastLen = -1;
+	iLen = 100 * sizeof(struct ifreq);
+
+	for (;;)
+	{
+		pcBuf = (char *)malloc(iLen);
+		ifc.ifc_len = iLen;
+		ifc.ifc_buf = pcBuf;
+
+		if (ioctl(fd, SIOCGIFCONF, &ifc) < 0)
+		{
+			if (errno != EINVAL || iLastLen != -1)
+			{
+//				DbgPrint(ELL_ERROR, "ioctl failed(%d)\n", errno);
+				free(pcBuf);
+				close(fd);
+				return 0;
+			}
+		}
+		else
+		{
+			if (ifc.ifc_len == iLastLen) break;
+			iLastLen = ifc.ifc_len;
+		}
+
+		iLen += 10 * sizeof(struct ifreq);
+		free(pcBuf);
+	}
+
+	for (pcTemp = pcBuf; pcTemp < pcBuf + ifc.ifc_len; )
+	{
+		if (iNum >= iMax)
+		{
+			PIPINFO	pIPInfoNew;
+
+			iMax += 10;
+			pIPInfoNew = (PIPINFO)realloc(pIPInfo, sizeof(IPINFO) * iMax);
+			if (pIPInfoNew == NULL)
+			{
+				free(pIPInfo);
+				free(pcBuf);
+				close(fd);
+				return 0;
+			}
+			else pIPInfo = pIPInfoNew;
+
+			memset(pIPInfo + (iMax - 10), 0, sizeof(IPINFO) * 10);
+		}
+
+		ifr = (struct ifreq *)pcTemp;
+
+		pcTemp += sizeof(ifr->ifr_name) + ifr->ifr_addr.sa_len;
+
+		/* discard invalid address families & loopback */
+		if ((ifr->ifr_addr.sa_family != AF_INET &&
+			ifr->ifr_addr.sa_family != AF_INET6) ||
+			strncmp(ifr->ifr_name, "lo", 2) == 0) continue;
+
+		ifrcopy = *ifr;
+		ioctl(fd, SIOCGIFFLAGS, &ifrcopy);
+		if ((ifrcopy.ifr_flags & IFF_UP) == 0) continue;
+
+		switch (ifr->ifr_addr.sa_family)
+		{
+		case AF_INET:
+			memcpy(pIPInfo[iNum].szIfName, ifr->ifr_name, IFNAMELEN);
+			dwIP =
+				ntohl(((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr.s_addr);
+			memcpy(pIPInfo[iNum].abIP, &dwIP, sizeof(unsigned long));
+			if (ifrcopy.ifr_flags & IFF_POINTOPOINT)
+				pIPInfo[iNum].iFlags |= ISPPP;
+			iNum++;
+			break;
+
+		case AF_INET6:
+			memcpy(pIPInfo[iNum].szIfName, ifr->ifr_name, IFNAMELEN);
+			memcpy(pIPInfo[iNum].abIP,
+				((struct sockaddr_in6 *)&(ifr->ifr_addr))-> sin6_addr.s6_addr,
+				16);
+			pIPInfo[iNum].iFlags |= ISIPV6;
+			if (ifrcopy.ifr_flags & IFF_POINTOPOINT)
+				pIPInfo[iNum].iFlags |= ISPPP;
+			iNum++;
+			break;
+
+		default:
+			break;
+		}
+	}
+
+	free(pcBuf);
+	close(fd);
+
+	*ppIPInfo = pIPInfo;
+
+	return iNum;
+}
+
+static void FreeIPInfo(PIPINFO pIPInfo)
+{
+	if (pIPInfo != NULL) free(pIPInfo);
+}
+
+
+////////////////////////////////////////////////////////////////////////
+// Function Definitions
+////////////////////////////////////////////////////////////////////////
+
+static void SendDiscoveryMsg();
+
+// SSDPListen
+//   Creates a UDP multicast socket and listens to the SSDP IP/PORT
+// Returns
+//   -1 on error, or the socket descriptor if success
+static int SSDPListen()
+{
+	char				fLoop;
+	int					iTTL;
+	struct ip_mreq		mreq;
+	struct sockaddr_in	saddr;
+	int					sd;
+
+    // IPPROTO_IP == 0; IPPROTO_TCP == 6; IPPROTO_UDP == 17; etc.
+	sd = socket(AF_INET, SOCK_DGRAM, 0);
+	if (sd == -1) {
+		if (g_fLogging & NALOG_ERROR)
+			fprintf(g_log, "Can't create socket! SSDPListen exiting\n");
+		return NA_E_NET;
+	}
+
+	// sock options values
+	fLoop = 0; // false - don't send copy to self
+	iTTL = SSDP_TTL;
+
+	// bind to listen to ssdp multicast address
+	bzero(&saddr, sizeof(saddr));
+	saddr.sin_len = sizeof(saddr);
+	saddr.sin_family = AF_INET;
+	//saddr.sin_addr.s_addr = inet_addr(SSDP_IP);
+	//saddr.sin_port = htons(SSDP_PORT);
+	saddr.sin_addr.s_addr = htonl(g_dwLocalIP);
+	saddr.sin_port = 0;
+
+	// and set the multicast add_member structure
+	// (TODO: need to find interfaces later - ioctl, with:
+	//  SIOCFIFCONF to find if's, SIOCGIFADDR to get addr, and SIOCFIFFLAGS
+	//  to check for IFF_MULTICAST flag for multicast support on an if)
+	bzero(&mreq, sizeof(mreq));
+	mreq.imr_interface.s_addr = g_dwLocalIP;
+	mreq.imr_multiaddr.s_addr = inet_addr(SSDP_IP);
+
+	if (
+		bind(sd, (struct sockaddr *)&saddr, sizeof(saddr)) //||
+		//setsockopt(sd, IPPROTO_IP, IP_MULTICAST_LOOP, &fLoop, sizeof(fLoop)) ||
+		//setsockopt(sd, IPPROTO_IP, IP_MULTICAST_TTL, &iTTL, sizeof(iTTL)) ||
+		//setsockopt(sd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq))
+		) {
+		if (g_fLogging & NALOG_ERROR)
+			fprintf(g_log,
+				"bind/setsockopt for multicast failed... errno = %d\n", errno);
+		close(sd);
+		return NA_E_NET;
+	}
+
+	return sd;
+}
+
+static int EventListen()
+{
+	struct sockaddr_in	saddr;
+	int					sd;
+
+	// try 5 ports before failing completely
+	for (g_wEventPort = 5000; g_wEventPort < 5005; g_wEventPort++)
+	{
+		sd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+		if (sd == -1) {
+			if (g_fLogging & NALOG_ERROR)
+				fprintf(g_log, "Can't create socket! EventListen exiting\n");
+			return NA_E_NET;
+		}
+
+		bzero(&saddr, sizeof(saddr));
+		saddr.sin_len = sizeof(saddr);
+		saddr.sin_family = AF_INET;
+		saddr.sin_addr.s_addr = htonl(g_dwLocalIP);
+		saddr.sin_port = htons(g_wEventPort);
+
+		// return if okay
+		if (bind(sd, (struct sockaddr *)&saddr, sizeof(saddr)) == 0)
+		{
+			listen(sd, 128);
+			////TracePrint(ELL_TRACE, "UPnP: EventListen @%u\n", g_wEventPort);
+			return sd;
+		}
+
+		// unsuccessful - close sd and try again
+		if (g_fLogging & NALOG_ERROR)
+			fprintf(g_log,
+				"bind TCP port %u failed: errno = %d\n", g_wEventPort, errno);
+		close(sd);
+	}
+
+	return NA_E_NET;
+}
+
+static void *TCPProc(void *in);
+
+static int EventInit()
+{
+	int				iRet;
+	pthread_attr_t	attr;
+
+	if (g_fEventEnabled == FALSE)
+	{
+		// initialize TCP socket for Eventing
+		g_sTCP = EventListen();
+		if (g_sTCP < 0) {
+			if (g_fLogging & NALOG_ERROR)
+				fprintf(g_log, "EventInit - Failed to init tcp socket.\n");
+			return NA_E_INTERNAL_ERROR;
+		}
+
+		// make TCP thread
+		pthread_attr_init(&attr);
+		iRet = pthread_create(&g_TCPthread, &attr, TCPProc, 0);
+		if (iRet != 0) {
+			close(g_sTCP);
+			g_sTCP = -1;
+			if (g_fLogging & NALOG_ERROR)
+				fprintf(g_log, "EventInit: TCPProc create failed(%d)\n", iRet);
+			return NA_E_THREAD_ERROR;
+		}
+	}
+
+	g_fEventEnabled = TRUE;
+
+	return NA_E_SUCCESS;
+}
+
+static void DumpHex(char *buf, int len)
+{
+	int		i;
+	int		nexti;
+	int		j;
+	int		endj;
+
+	if (g_fLogging & NALOG_DUMP) {
+		if (buf == NULL) return;
+		if (len <= 0) return;
+
+		for (i = 0; i < len; i = nexti) {
+			fprintf(g_log, "%04x:  ", i);
+			nexti = i + 16;
+			endj = (nexti > len) ? len : nexti;
+			for (j = i; j < endj; j++)
+				fprintf(g_log, "%02x ", buf[j] & 0xff);
+			if (j == len) {
+				if ((j % 16) != 0) {
+					char pad[3 * 16 + 1];  // don't need the last 3 bytes anyway
+					j = (16 - (j % 16)) * 3;
+					memset(pad, ' ', j);
+					pad[j] = '\0';
+					fputs(pad, g_log);
+				}
+			}
+			for (j = i; j < endj; j++)
+				isprint(buf[j]) ? fputc(buf[j], g_log) : fputc('.', g_log);
+			fputc('\n', g_log);
+		}
+
+	}
+}
+
+// FindHTTPHeaderNewLine
+//   Returns a pointer to the beginning of a CRLF, that is not a
+//   part of LWS.  (LWS is CRLF followed by a space or tab, and in
+//   HTTP, considered as equivalent to a single space) (LWS stands
+//   for "linear white space")
+// Returns a pointer the beginning of CRLF, and sets the EOH flag to
+//   whether this is the last header in the HTTP header section.
+//   Also, if pbuf is NULL, or if there isn't any CRLF found in the
+//   string, or if the HTTP syntax is wrong, NULL is returned, and
+//   the EOH flag is not touched.
+static char *FindHTTPHeaderNewLine(char *pbuf, int iBufSize, int *pfEOH)
+{
+	char *result;
+	int i = 0;
+
+	if (pbuf == NULL) return NULL;
+
+	for (;;) {
+		result = memchr(pbuf, '\r', iBufSize);
+		if (result == NULL) {
+			if (g_fLogging & NALOG_INFO0) {
+				fprintf(g_log, "FindHTTPHeaderNewLine: er @(%d)\n", i);
+				fflush(g_log);
+			}
+			return NULL;
+		}
+		i++; // count chars
+
+		// decrement iBufSize, and move pbuf forward
+		iBufSize -= (result - pbuf);
+		pbuf = result;
+
+		++pbuf;  // now pointing right after "\r"
+		--iBufSize;
+		if (*pbuf == '\0') break;
+		if (*pbuf != '\n') continue;
+
+		++pbuf;  // now pointing after "\r\n"
+		--iBufSize;
+		if (*pbuf == '\0') break;
+		if ((*pbuf == ' ') || (*pbuf == '\t')) continue;
+
+		// at this point we know we're at the end of a header field,
+		// and there's more stuff coming...
+
+		// just need to check if this is the last header
+		if ((pbuf[0] == '\r') && (pbuf[1] == '\n'))
+			*pfEOH = TRUE;
+		else
+			*pfEOH = FALSE;
+
+		return result;
+	}
+
+	return NULL;
+}
+
+// NewHTTPResponse_sz
+//   Creates an HTTPResponse structure from a string (sz).  Set
+//   fDestroyOriginal to TRUE if the buffer passed in can be overwritten.
+//   Otherwise, NewHTTPResponse_sz will duplicate the buffer.
+// Returns the created HTTPResponse structure if successful, or if an
+//   error occured (out of memory, or bad http syntax), returns NULL.
+// NOTE: ALWAYS call DeleteHTTPResponse after using the HTTPResponse structure.
+// NOTE: The input is assumed to be correct.  If there're HTTP syntax errors,
+//   and the pszHTTPResponse is not null-terminated, result may be undefined.
+//   (to be fixed next version)
+static PHTTPResponse NewHTTPResponse_sz(
+	char *pszHTTPResponse,
+	int iBufferSize,
+	int fDestroyOriginal)
+{
+	PHTTPResponse	pResponse;
+	int				fEOH;
+	char			*pszEOL;
+	int				iNumHeaders;
+	char			*pBuf;
+
+	if ((pResponse = (PHTTPResponse)malloc(sizeof(HTTPResponse))) == NULL) {
+		if (g_fLogging & NALOG_INFO0) {
+			fprintf(g_log, "NewHTTPResponse_sz: er 1\n");
+			fflush(g_log);
+		}
+		return NULL;
+	}
+
+	// make copy of buffer now
+	if (fDestroyOriginal) {
+		pResponse->buf = NULL;
+		pBuf = pszHTTPResponse;
+	}
+	else {
+		int len = strlen(pszHTTPResponse);
+		if ((len+1) > iBufferSize) {
+			if (g_fLogging & NALOG_INFO0)
+				fprintf(g_log, "Length: %d > %d\n", len+1, iBufferSize);
+			iBufferSize = len+1;
+		}
+		if ((pResponse->buf = (char *)malloc(iBufferSize)) == NULL) {
+			free(pResponse);
+			if (g_fLogging & NALOG_INFO0) {
+				fprintf(g_log, "NewHTTPResponse_sz: er 2\n");
+				fflush(g_log);
+			}
+			return NULL;
+		}
+		memcpy(pResponse->buf, pszHTTPResponse, iBufferSize);
+		pBuf = pResponse->buf;
+	}
+
+	// get the first line
+	pszEOL = FindHTTPHeaderNewLine(pBuf, iBufferSize, &fEOH);
+	if (pszEOL == NULL) {
+		if (g_fLogging & NALOG_INFO0) {
+			fprintf(g_log, "NewHTTPResponse_sz: er 3\n");
+			fflush(g_log);
+		}
+		goto cleanup;
+	}
+
+	*pszEOL = '\0';    // terminate the status line
+	pszEOL += 2;       // point to the rest of the buffer
+
+	// set the status string first
+	pResponse->pszStatus = strchr(pBuf, ' ');
+	if (pResponse->pszStatus == NULL) {
+		if (g_fLogging & NALOG_INFO0) {
+			fprintf(g_log, "NewHTTPResponse_sz: er 4\n");
+			fflush(g_log);
+		}
+		goto cleanup;  // syntax error
+	}
+
+	pResponse->pszStatus++;  // point to the actual status
+
+	pResponse->pszReason = strchr(pResponse->pszStatus, ' ');
+	if (pResponse->pszReason == NULL) {
+		if (g_fLogging & NALOG_INFO0) {
+			fprintf(g_log, "NewHTTPResponse_sz: er 5\n");
+			fflush(g_log);
+		}
+		goto cleanup;  // syntax error
+	}
+
+	pResponse->pszReason[0] = '\0';  // terminate status string
+	pResponse->pszReason++;          // point to the reason string
+
+	iNumHeaders = 0;  // initialize to 0 headers
+
+	// parse header fields line by line (while not end of headers)
+	while (!fEOH) {
+		PProperty	pHeader = &(pResponse->aHeaders[iNumHeaders]);
+		// point header field name to the first char of the line
+		pHeader->pszName = pszEOL;
+
+		// search for the end of line
+		pszEOL = FindHTTPHeaderNewLine(pszEOL,
+			iBufferSize - (pszEOL - pBuf),  // remainder size
+			&fEOH);
+		if (pszEOL == NULL) goto cleanup;  // syntax error
+
+		*pszEOL = '\0';  // terminate this string
+		pszEOL += 2;  // point to beginning of next line
+
+		pHeader->pszValue = strchr(pHeader->pszName, ':');
+		if (pHeader->pszValue == NULL) {
+			if (g_fLogging & NALOG_INFO0) {
+				fprintf(g_log, "NewHTTPResponse_sz: er 6\n");
+				fflush(g_log);
+			}
+			goto cleanup;  // syntax error (header field has no ":")
+		}
+
+		pHeader->pszValue[0] = '\0';  // terminate the header name string
+		pHeader->pszValue++;  // point after the ":"
+		// get rid of leading spaces for the value part
+		while (
+			(pHeader->pszValue[0] == ' ') ||
+			(pHeader->pszValue[0] == '\t') ||
+			(pHeader->pszValue[0] == '\r') ||
+			(pHeader->pszValue[0] == '\n')
+			) {
+			pHeader->pszValue++;  // skip the space
+		}
+
+		iNumHeaders++;  // added one more header
+		pHeader++;      // point to the next header in pResponse->aHeaders
+	}
+
+	pResponse->iNumHeaders = iNumHeaders;  // remember to set it in pResponse
+
+	pResponse->pszBody = pszEOL + 2;  // point after the empty line
+
+	return pResponse;
+
+cleanup:
+	if (pResponse->buf != NULL) free(pResponse->buf);
+	free(pResponse);
+	return NULL;
+}
+
+// DeleteHTTPResponse
+//   Deallocates stuff in the HTTPResponse structure, effectively returning
+//   memory to the system and destroying the structure.
+// NOTE: The pointer pResponse WILL BE FREED, and will be unusable after
+//   the call to DeleteHTTPResponse.
+static void DeleteHTTPResponse(PHTTPResponse pResponse)
+{
+//	int i;
+
+	if (pResponse == NULL) return;
+
+	// Current impl is just simple array - no need to free()
+	//for (i = 0; i < pResponse->iNumHeaders; i++) {
+	//	free(pResponse->aHeaders[i]);
+	//}
+
+	if (pResponse->buf != NULL)
+		free(pResponse->buf);
+	free(pResponse);
+}
+
+//typedef struct tagHTTPResponse {
+//	char		*pszStatus;
+//	char		*pszReason;
+//	int			iNumHeaders;
+//	Property	aHeaders[30];  // assume at most this many headers
+//	char		*pszBody;
+//
+//	// for admin use
+//	int			fFree;
+//	char		*buf;
+//} HTTPResponse, *PHTTPResponse, **PPHTTPResponse;
+
+static void PrintHTTPResponse(PHTTPResponse pResponse)
+{
+	int		i;
+
+	if (g_fLogging & (NALOG_INFO1)) {
+		if (pResponse == NULL) return;
+		fprintf(g_log, " *** HTTP response begin *** \n");
+		fprintf(g_log, " * status = [%s], reason = [%s] *\n",
+			pResponse->pszStatus, pResponse->pszReason);
+		for (i = 0; i < pResponse->iNumHeaders; i++) {
+			fprintf(g_log, " * Header \"%s\" = [%s]\n",
+				pResponse->aHeaders[i].pszName,
+				pResponse->aHeaders[i].pszValue);
+		}
+		if (g_fLogging & NALOG_DUMP)
+			fprintf(g_log, " * body = [%s] *\n", pResponse->pszBody);
+		fprintf(g_log, " *** HTTP response end *** \n");
+	}
+}
+
+static int DiscoverRouter(PHTTPResponse pResponse)
+{
+	int			i;
+	int			fLocation = FALSE;
+	int			fUSN = FALSE;
+	int			fIsNATDevice = FALSE;
+
+#if 0
+	if (strcmp(pResponse->pszStatus, "200") != 0)
+		return -1;
+#endif
+
+	if (pResponse == NULL) {
+		if (g_fLogging & NALOG_INFO0)
+			fprintf(g_log, "DiscoverRouter: pResponse == NULL\n");
+		return -1;
+	}
+
+	// check to see if this is a relevant packet
+	for (i = 0; i < pResponse->iNumHeaders; i++) {
+		PProperty pHeader = &(pResponse->aHeaders[i]);
+
+		if ((strcasecmp(pHeader->pszName, "ST") == 0) ||
+			(strcasecmp(pHeader->pszName, "NT") == 0)) {
+			if ((strcmp(pHeader->pszValue,
+				"urn:schemas-upnp-org:service:WANIPConnection:1") == 0) ||
+				(strcmp(pHeader->pszValue,
+				"urn:schemas-upnp-org:device:InternetGatewayDevice:1") == 0)) {
+				fIsNATDevice = TRUE;
+			}
+		}
+	}
+
+	// leave the message alone if we don't need it
+	if (!fIsNATDevice)
+		return -1;
+
+	// Now that we know we're looking at the message about the NAT device:
+	pthread_mutex_lock(&g_xUPnP);
+
+	// set upnp to be unconfigured for now
+	g_fUPnPEnabled = FALSE;
+
+	// loop through the headers
+	for (i = 0; i < pResponse->iNumHeaders; i++) {
+		PProperty pHeader = &(pResponse->aHeaders[i]);
+
+		if (strcasecmp(pHeader->pszName, "Location") == 0) {
+			char *p;
+			char *q;
+
+			if (g_fLogging & NALOG_INFO1)
+				fprintf(g_log, "Checking Location...\n");
+			p = pHeader->pszValue;
+			if (strncmp(p, "http://", 7) != 0)
+				continue;  // hope for another Location header to correct it
+			p += 7;  // skip over "http://"
+			q = strchr(p, '/');
+
+			// set the control URL first
+			if (q == NULL) {
+				g_szNATDevDescURL[0] = '/';
+				g_szNATDevDescURL[1] = '\0';
+			}
+			else {
+				strncpy(g_szNATDevDescURL, q, sizeof(g_szNATDevDescURL) - 1);
+				g_szNATDevDescURL[sizeof(g_szNATDevDescURL) - 1] = '\0';
+				// terminate the host/port string
+				*q = '\0';
+			}
+
+			if (g_fLogging & NALOG_INFO1)
+				fprintf(g_log, "  Device Description URL set to[%s]...\n",
+					g_szNATDevDescURL);
+
+			// see if port is specified
+			q = strchr(p, ':');
+			if (q == NULL) {
+				sprintf(g_szRouterHostPortDesc, "%s", p);
+
+				g_saddrRouterDesc.sin_addr.s_addr = inet_addr(p);
+				g_saddrRouterDesc.sin_port = htons(80);
+			}
+			else {
+				// don't include the ":80" - HTTP is by default port 80
+				if (atoi(q+1) == 80) *q = '\0';
+
+				strcpy(g_szRouterHostPortDesc, p);
+
+				// terminate the host part and point to it
+				*q = '\0';
+				q++;
+
+				g_saddrRouterDesc.sin_addr.s_addr = inet_addr(p);
+				g_saddrRouterDesc.sin_port = htons(atoi(q));
+			}
+
+			g_saddrRouterDesc.sin_family = AF_INET;
+
+			if (g_fLogging & NALOG_INFO1)
+				fprintf(g_log, "  Router Address set to[%s]...\n",
+					g_szRouterHostPortDesc);
+			fLocation = TRUE;
+		}
+		else if (strcasecmp(pHeader->pszName, "USN") == 0) {
+			if (g_fLogging & NALOG_INFO1)
+				fprintf(g_log, "Checking USN...\n");
+			strncpy(g_szUSN, pHeader->pszValue, sizeof(g_szUSN) - 1);
+			g_szUSN[sizeof(g_szUSN) - 1] = '\0';
+			fUSN = TRUE;
+		}
+		else {
+			;  // do nothing for other headers for now
+		}
+	}
+
+	// now check flags and set enabled if all set
+	if (fLocation && fUSN) {
+		if (g_fLogging & NALOG_INFO1) {
+			fprintf(g_log,
+				"Description Host/port string: [%s]\n"
+				"NATDevDescURL: [%s], USN: [%s]\n",
+				g_szRouterHostPortDesc,
+				g_szNATDevDescURL, g_szUSN);
+			if (g_fLogging & NALOG_INFO1)
+				fprintf(g_log, "Got router information\n");
+		}
+
+		g_fUPnPEnabled = TRUE;
+		pthread_cond_broadcast(&g_condUPnP);
+	}
+
+	// remember to unlock before return
+	pthread_mutex_unlock(&g_xUPnP);
+
+	return 0;
+}
+
+// granularity is specified as: granularity = 1/nth seconds
+#define UPNP_TIMEOUT_GRANULARITY	(1000)
+#define U_TOGRAN					UPNP_TIMEOUT_GRANULARITY
+
+// result = a - b
+static void TimevalSubtract(
+	struct timeval *result,
+	const struct timeval *a,
+	const struct timeval *b)
+{
+	result->tv_sec = a->tv_sec - b->tv_sec;
+
+	if (b->tv_usec > a->tv_usec) {
+		result->tv_sec--;
+		result->tv_usec = 1000000 + a->tv_usec - b->tv_usec;
+	}
+	else
+		result->tv_usec = a->tv_usec - b->tv_usec;
+}
+
+// elapsed = end - start
+static void GetTimeElapsed(
+	const struct timeval *tv_start,
+	const struct timeval *tv_end,
+	struct timeval *tv_elapsed)
+{
+	TimevalSubtract(tv_elapsed, tv_end, tv_start);
+#if 0
+	tv_elapsed->tv_sec = tv_end->tv_sec - tv_start->tv_sec;
+
+	if (tv_start->tv_usec > tv_end->tv_usec) {
+		tv_elapsed->tv_sec--;
+		tv_elapsed->tv_usec = 1000000 + tv_end->tv_usec - tv_start->tv_usec;
+	}
+	else
+		tv_elapsed->tv_usec = tv_end->tv_usec - tv_start->tv_usec;
+#endif
+}
+
+// returns +1, 0, or -1, if a>b, a==b, a<b, respectively
+static int CompareTime(
+	const struct timeval *a,
+	const struct timeval *b
+	)
+{
+	if ((a->tv_sec == b->tv_sec) &&
+		(a->tv_usec == b->tv_usec)) return 0;
+
+	if (a->tv_sec > b->tv_sec) return 1;
+	else if (a->tv_sec < b->tv_sec) return -1;
+
+	// if seconds are equal...
+	if (a->tv_usec > b->tv_usec) return 1;
+	else return -1;
+}
+
+static int WaitControlURLSet(double timeout)
+{
+	struct timespec		ts;
+	struct timeval		tv;
+	struct timeval		tv_start;
+	int					iRet;
+	long				to_sec = (int) (timeout / U_TOGRAN);
+	long				to_usec =
+		(int) (((timeout / U_TOGRAN) - to_sec) * 1000000.0);
+	//long				to_sec = (int) timeout;
+	//long				to_usec = (int) ((timeout - to_sec) * 1000000.0);
+	struct timeval		elapsed;
+
+	// get function start time
+	gettimeofday(&tv_start, NULL);
+
+	pthread_mutex_lock(&g_xUPnP);
+
+#if 0
+	// if last update is too long ago then wait for it
+	GetTimeElapsed(&g_tvLastUpdateTime, &tv_start, &elapsed);
+	if ((elapsed.tv_sec + (elapsed.tv_usec / 1000000.0)) >
+		(((double) g_iUPnPTimeout) / U_TOGRAN))
+		g_fControlURLSet = 0;
+#endif
+
+	while (!g_fControlURLSet) {
+		// get current time
+		gettimeofday(&tv, NULL);
+
+#if 0
+for now ignore device timeout
+		// see if we've past the device's timeout first
+		GetTimeElapsed(&g_tvUPnPInitTime, &tv, &elapsed);
+		if ((elapsed.tv_sec > g_timeout_sec) ||
+			(	(elapsed.tv_sec == g_timeout_sec) &&
+				(elapsed.tv_usec > g_timeout_usec)
+			))
+		{
+			pthread_mutex_unlock(&g_xUPnP);
+			return FALSE;
+		}
+#endif
+
+		// calculate ts to sleep till
+		ts.tv_sec = tv.tv_sec + to_sec;
+		ts.tv_nsec = (tv.tv_usec + to_usec) * 1000;
+		if (ts.tv_nsec > 1000000000) {
+			ts.tv_nsec -= 1000000000;
+			ts.tv_sec += 1;
+		}
+
+		// now get how long we've been in this function already and deduct
+		GetTimeElapsed(&tv_start, &tv, &elapsed);
+		ts.tv_sec -= elapsed.tv_sec;
+		if (ts.tv_nsec < (elapsed.tv_usec * 1000)) {
+			ts.tv_sec--;
+			ts.tv_nsec = 1000000000 + ts.tv_nsec - (elapsed.tv_usec * 1000);
+		}
+		else {
+			ts.tv_nsec -= (elapsed.tv_usec * 1000);
+		}
+
+		iRet = pthread_cond_timedwait(&g_condUPnPControlURL, &g_xUPnP, &ts);
+
+		// if timeout then return false
+		if (iRet != 0)
+		{
+			pthread_mutex_unlock(&g_xUPnP);
+			return FALSE;
+		}
+	}
+	pthread_mutex_unlock(&g_xUPnP);
+
+	return TRUE;
+}
+
+static int WaitUPnPFunction()
+{
+	struct timeval	start;
+//	struct timeval	end;
+	double			wait2;
+//	struct timeval	elapsed;
+
+	gettimeofday(&start, NULL);
+
+	wait2 = (double)g_iFunctionTimeout;
+
+	WaitControlURLSet(wait2);
+
+//gettimeofday(&end, NULL);
+//GetTimeElapsed(&start, &end, &elapsed);
+//fprintf(stderr, "== wait2: (%f) %d.%06d\n",
+//	wait2/U_TOGRAN, elapsed.tv_sec, elapsed.tv_usec);
+
+	return g_fControlURLSet;
+}
+
+static void SetLocalIP();
+
+static int SendTCPMsg_saddr_parse(
+	char *msg, int iLen,
+	char *result, int resultSize,
+	struct sockaddr_in *saHost);
+
+static void *TCPProc(void *in)
+{
+	int				iRet;
+	unsigned char	buf[MAX_SOAPMSGSIZE];
+	int				iBufLen;
+	
+	(void)in; // unused
+	WaitUPnPFunction();
+	//TracePrint(ELL_TRACE, "UPnP: Begin TCPProc\n");
+	
+	// do the subscription
+	{
+		char callback[100];
+		char response[2000];
+		PHTTPResponse resp;
+		int n;
+		sprintf(callback, "%lu.%lu.%lu.%lu:%u", 
+			(g_dwLocalIP >> 24) & 0xFF,
+			(g_dwLocalIP >> 16) & 0xFF,
+			(g_dwLocalIP >> 8) & 0xFF,
+			(g_dwLocalIP >> 0) & 0xFF,
+			g_wEventPort);
+
+		n = sprintf(buf,
+			szEventMsgSubscribeFMT,
+			g_szEventURL,
+			callback, g_szRouterHostPortEvent, 1800);
+
+		memset(response, 0, 2000);
+		n = SendTCPMsg_saddr_parse(
+			buf, n,
+			response, 2000,
+			&g_saddrRouterEvent);
+		if (n > 0)
+		{
+			response[n] = '\0';
+			resp = NewHTTPResponse_sz(buf, n, TRUE);
+			if (NULL != resp)
+			{
+////TracePrint(ELL_TRACE, "UPnP Subscribe returns %s/%d\n", resp->pszStatus, n);
+			}
+			else
+			{
+////TracePrint(ELL_TRACE, "UPnP Subscribe not enough response (%d) \n[%s]\n",
+//	n, response);
+			}
+			DeleteHTTPResponse(resp);
+		}
+		else
+		{
+////TracePrint(ELL_TRACE, "UPnP Subscribe failed (%d)\n", n);
+			return NULL;
+		}
+	}
+
+	//TracePrint(ELL_TRACE, "UPnP: TCPProc begin loop\n");
+
+	g_sTCPCancel = -1;
+
+	for (;;)
+	{
+//		ssize_t				n;
+		struct sockaddr_in	recvaddr;
+		int					recvaddrlen;
+		fd_set				readfds;
+		struct timeval		timeout;
+		int					sEvent;
+		int					fFirstRecv;
+		int					sMax;
+
+		// for after responding to long(?) TCP event
+		if (g_fQuit)
+			goto cleanup;
+
+		if (g_sTCPCancel != -1) close(g_sTCPCancel);
+		sMax = g_sTCPCancel = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+		if (sMax < g_sTCP) sMax = g_sTCP;
+
+		FD_ZERO(&readfds);
+		FD_SET(g_sTCP, &readfds);
+		FD_SET(g_sTCPCancel, &readfds);
+		iRet = select(sMax+1, &readfds, NULL, NULL, NULL);
+		if (iRet <= 0) {
+			if (EBADF == errno)
+				continue;
+			//TracePrint(ELL_TRACE, "UPnP Event select failed (%d)\n", errno);
+			continue;
+		}
+
+		recvaddrlen = sizeof(recvaddr);
+		sEvent = accept(g_sTCP, (struct sockaddr *)&recvaddr, &recvaddrlen);
+		// not likely - (system's descriptor/file table full)
+		if (sEvent <= 0) continue;
+
+		////TracePrint(ELL_TRACE, "UPnP receiving event..\n");
+
+		// read all we could from this event
+		fFirstRecv = 1;
+		iBufLen = 0;
+		for (;;)
+		{
+			FD_ZERO(&readfds);
+			FD_SET(sEvent, &readfds);
+			timeout.tv_sec = 0;
+			timeout.tv_usec = 400000;	// long cause we're dealing with input
+			iRet = select(sEvent+1, &readfds, NULL, NULL, &timeout);
+			if (iRet <= 0) {
+				if (g_fQuit)
+				{
+					close(sEvent);
+					goto cleanup;
+				}
+				break;
+			}
+
+			// recv
+			iRet = recv(sEvent, buf + iBufLen, MAX_SOAPMSGSIZE - iBufLen, 0);
+			if (iRet < 0)
+			{
+				// something is wrong
+				break;
+			}
+			else if (iRet == 0)
+			{
+				break;
+			}
+
+			iBufLen += iRet;
+
+			if (fFirstRecv)
+			{
+				int iTemp;
+				iTemp = send(sEvent, HTTP200OK, HTTP200OKLEN, 0);
+				shutdown(sEvent, 1);
+				fFirstRecv = 0;
+			}
+		}
+
+		// now send 200 OK and be done
+		close(sEvent);
+
+		////TracePrint(ELL_TRACE, "UPnP event (%d) received (%d)\n", g_fExpectEvent, iBufLen);
+
+		// and parse the XML here.
+		if (iBufLen < MAX_SOAPMSGSIZE)
+		{
+			buf[iBufLen] = '\0';
+			// for now do nothing
+		}
+		else
+		{
+			buf[MAX_SOAPMSGSIZE - 1] = '\0';
+		}
+	}
+
+cleanup:
+	//TracePrint(ELL_TRACE, "UPnP: TCPProc end\n");
+	close(g_sTCP);
+	g_sTCP = -1;
+	g_fEventEnabled = FALSE;
+	if (g_sTCPCancel != -1) close(g_sTCPCancel);
+	g_sTCPCancel = -1;
+	return NULL;
+}
+
+static void *UDPProc(void *in)
+{
+//	char			fLoop = 0; // false - don't send copy to self
+//	int				iTTL = SSDP_TTL;
+	int				iRet;
+//	struct ip_mreq	mreq;
+//	struct sockaddr_in	saddr;
+	unsigned char	buf[65536];
+//	FILE			*log = g_log;
+	static time_t	last_getdevicedesc_t = 0;
+	
+	(void)in;  // unused
+	pthread_mutex_lock(&g_xUPnP);
+	gettimeofday(&g_tvUPnPInitTime, NULL);
+	pthread_mutex_unlock(&g_xUPnP);
+
+	for (;;) {
+		ssize_t				n;
+		struct sockaddr_in	recvaddr;
+		int					recvaddrlen;
+		fd_set				readfds;
+		//struct timeval		timeout;
+		//int					i;
+		int					sMax;
+
+		if (g_sUDPCancel < g_sUDP) sMax = g_sUDP;
+		else                       sMax = g_sUDPCancel;
+
+		FD_ZERO(&readfds);
+		FD_SET(g_sUDP, &readfds);
+		FD_SET(g_sUDPCancel, &readfds);
+		iRet = select(sMax+1, &readfds, NULL, NULL, NULL);
+
+		if (iRet <= 0) {
+			if (g_fQuit)
+			{
+				close(g_sUDP);
+				close(g_sUDPCancel);
+				g_sUDP = -1;
+				g_sUDPCancel = -1;
+				return NULL;
+			}
+			continue;
+		}
+
+		if (!FD_ISSET(g_sUDP, &readfds)) continue;
+		recvaddrlen = sizeof(recvaddr);
+		n = recvfrom(g_sUDP, buf, sizeof(buf), 0,
+			(struct sockaddr *)&recvaddr, &recvaddrlen);
+		if (n < 0) {
+			if (g_fLogging & NALOG_ERROR)
+				fprintf(g_log, "recv failed (%d)\n", errno);
+			close(g_sUDP);
+			close(g_sUDPCancel);
+			g_sUDP = -1;
+			g_sUDPCancel = -1;
+			return NULL;
+		}
+		buf[n] = '\0';
+		if (strncmp(buf, "HTTP/1.1", 8) == 0) {
+			PHTTPResponse pResponse = NewHTTPResponse_sz(buf, n, TRUE);
+			PrintHTTPResponse(pResponse);
+			if (DiscoverRouter(pResponse) == 0)
+			{
+				time_t	now = time(NULL);
+				if (!g_fControlURLSet ||
+					((now - last_getdevicedesc_t) > 5))
+				{
+					GetDeviceDescription();
+					SetLocalIP();
+					last_getdevicedesc_t = now;
+				}
+			}
+			DeleteHTTPResponse(pResponse);
+		}
+		else if (strncmp(buf, "NOTIFY * HTTP/1.1", 7) == 0) {
+			// temporarily use this to fudge - will have the exact same
+			// parsing, only status/reason set to "*" and "HTTP/1.1".
+			// TODO: add support for HTTP requests
+			PHTTPResponse pResponse = NewHTTPResponse_sz(buf, n, TRUE);
+			if (DiscoverRouter(pResponse) == 0)
+			{
+				time_t	now = time(NULL);
+				if (!g_fControlURLSet ||
+					((now - last_getdevicedesc_t) > 5))
+				{
+					GetDeviceDescription();
+					SetLocalIP();
+					last_getdevicedesc_t = now;
+				}
+			}
+			DeleteHTTPResponse(pResponse);
+		}
+		else {
+			if (g_fLogging & NALOG_DUMP)
+				fprintf(g_log, "(%ld) Buffer: \n[%s]\n", time(NULL), buf);
+			fflush(g_log);
+		}
+	}
+
+	close(g_sUDP);
+	g_sUDP = -1;
+}
+
+static void SendUDPMsg(const char *msg) {
+	struct sockaddr_in	saSendTo;
+	int					iRet;
+	int					iLen;
+
+	bzero(&saSendTo, sizeof(saSendTo));
+	saSendTo.sin_family = AF_INET;
+	saSendTo.sin_addr.s_addr = inet_addr(SSDP_IP);
+	saSendTo.sin_port = htons(SSDP_PORT);
+
+	iLen = strlen(msg);
+
+	if (g_fLogging & NALOG_DUMP)
+		fprintf(g_log, "SendUDP: [%s]\n", msg);
+
+	iRet = sendto(g_sUDP, msg, iLen, 0,
+		(struct sockaddr *)&saSendTo, sizeof(saSendTo));
+
+	// sanity check
+	if (iRet != iLen)
+		if (g_fLogging & NALOG_ALERT)
+			fprintf(g_log,
+				"SendUDPMsg: iRet(%d) != strlen(msg)(%d)! (errno %d)\n",
+				iRet, iLen, errno);
+}
+
+// strstr, case insensitive, and is limited by len
+static char *strcasestr_n(const char *big, const char *little, int len)
+{
+	int bigLen;
+	int littleLen;
+	int i;
+	int end;
+
+	if (little == NULL) return (char *)big;
+	if (big == NULL) return NULL;
+
+	//bigLen = strlen(big);
+	bigLen = len;
+	littleLen = strlen(little);
+
+	if (bigLen < littleLen) return NULL;
+
+	end = bigLen - littleLen;
+	for (i = 0; i <= end; (i++), (big++)) {
+		if (strncasecmp(big, little, littleLen) == 0)
+			return (char *)big;
+	}
+
+	return NULL;
+}
+
+// this is strnstr, only portable
+static char *strstr_n(const char *big, const char *little, int len)
+{
+	int		iBigLen;
+	int		iLittleLen;
+
+	(void)len;  // unused
+
+	if ((big == NULL) || (little == NULL)) return NULL;
+
+	iBigLen = strlen(big);
+	iLittleLen = strlen(little);
+
+	// this part is basically strnstr, except this is portable
+	for (;;) {
+		if (iBigLen < iLittleLen)
+			return NULL;
+		if (strncmp(big, little, iLittleLen) == 0)
+			return (char *)big;
+		++big;
+		--iBigLen;
+	}
+}
+
+// returns -1 for "not found"
+static int FindContentLength(char *pbuf, int iLen)
+{
+	// non reusable HTTP header parsing code:
+	// ----------------------------------------------
+	char			*p;
+	int				iResult;
+
+	// find content length header
+	p = strcasestr_n(pbuf, "\r\nContent-Length:", iLen);
+	if (p == NULL) return -1;
+
+	p += sizeof("\r\nContent-Length:") - 1;	// minus '\0'
+
+	iResult = atoi(p);
+
+	return iResult;
+	// ----------------------------------------------
+}
+
+// returns -1 for "not found"
+static int FindBody(char *pbuf, int iLen)
+{
+	// non reusable HTTP header parsing code:
+	// ----------------------------------------------
+	char			*p;
+//	int				iResult;
+
+	// find the empty line
+	p = strstr_n(pbuf, "\r\n\r\n", iLen);
+	if (p == NULL) return -1;
+
+	p += sizeof("\r\n\r\n") - 1;	// minus '\0'
+
+	return (p - pbuf);
+	// ----------------------------------------------
+}
+
+static int SendTCPMsg_saddr_2part(
+	char *msg, int iLen,
+	char *msg2, int iLen2,
+	char *result, int resultSize,
+	struct sockaddr_in *saHost)
+{
+	int					s;
+	struct sockaddr_in	saSendTo;
+	int					iRet;
+	int					iBufLen;
+	int					fND;
+	int					fcntl_flags;
+	int					iRetcode;
+	struct timeval		tv;
+	fd_set				writefds;
+
+	struct timeval		tv_start;
+	struct timeval		tv_end;
+	struct timeval		tv_elapsed;
+
+	int					iContentLength = -1;
+	int					iBodyOffset = -1;
+
+	gettimeofday(&tv_start, NULL);
+
+	if (g_fUPnPEnabled != TRUE) {
+//TracePrint(ELL_TRACE, "UPnP not enabled\n");
+		if (g_fLogging & NALOG_ERROR)
+			fprintf(g_log, "UPnP not enabled (no UPnP device found yet)\n");
+		return NA_E_NOT_AVAILABLE;
+	}
+
+	s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+	if (s == -1) {
+		if (g_fLogging & NALOG_ERROR)
+			fprintf(g_log, "Can't get TCP socket (%d)\n", errno);
+		return NA_E_NET;
+	}
+
+	fND = 1;
+	if (setsockopt(s, IPPROTO_IP, TCP_NODELAY, &fND, sizeof(fND)) != 0) {
+		if (g_fLogging & NALOG_ERROR)
+			fprintf(g_log, "SendTCPMsg/2part: Can't set TCP_NODELAY option!\n");
+		iRetcode = NA_E_NET;
+		goto cleanup;
+	}
+
+	fcntl_flags = 0;
+	fcntl_flags = fcntl(s, F_GETFL, 0);
+	fcntl_flags |= O_NONBLOCK;
+	if (fcntl(s, F_SETFL, fcntl_flags) != 0) {
+		if (g_fLogging & NALOG_ERROR)
+			fprintf(g_log, "SendTCPMsg/2part: Can't set O_NONBLOCK option!\n");
+		iRetcode = NA_E_NET;
+		goto cleanup;
+	}
+
+	if (saHost == NULL)
+		memcpy(&saSendTo, &g_saddrRouterDesc, sizeof(saSendTo));
+	else
+		memcpy(&saSendTo, saHost, sizeof(saSendTo));
+
+	iRet = connect(s, (struct sockaddr *) &saSendTo, sizeof(saSendTo));
+	if ((iRet < 0) && (errno != EINPROGRESS)) {
+//TracePrint(ELL_TRACE, "UPnP connect failed\n");
+		if (g_fLogging & NALOG_ERROR)
+			fprintf(g_log, "SendTCPMsg/2part: connect failed (%d)\n", errno);
+		iRetcode = NA_E_NET;
+		goto cleanup;
+	}
+
+	if (g_fLogging & NALOG_INFO1)
+		fprintf(g_log,
+			"- Before Sending TCP Msg1: %d == %lu?\n", iLen, strlen(msg));
+	if (g_fLogging & NALOG_DUMP)
+		fprintf(g_log, "Sending TCP msg part 1:\n[%s]\n", msg);
+
+	tv.tv_sec = g_iFunctionTimeout / UPNP_TIMEOUT_GRANULARITY;
+	tv.tv_usec = (g_iFunctionTimeout % U_TOGRAN) * 1000000 / U_TOGRAN;
+	FD_ZERO(&writefds);
+	FD_SET(s, &writefds);
+	iRet = select(s+1, 0, &writefds, 0, &tv);
+	if (iRet < 0) {
+		if (g_fLogging & NALOG_ERROR)
+			fprintf(g_log, "SendTCPMsg/2part: select failed (%d)\n", errno);
+		iRetcode = NA_E_NET;
+		goto cleanup;
+	}
+	if (iRet == 0) {
+		if (g_fLogging & NALOG_ERROR)
+			fprintf(g_log, "SendTCPMsg/2part: select timed out\n");
+		iRetcode = NA_E_TIMEOUT;
+gettimeofday(&tv_end, NULL);
+GetTimeElapsed(&tv_start, &tv_end, &tv_elapsed);
+//TracePrint(ELL_TRACE, "UPnP 2part: timeout @1st after %lu.%06lu secs\n",
+//	tv_elapsed.tv_sec, tv_elapsed.tv_usec);
+		goto cleanup;
+	}
+
+	iRet = send(s, msg, iLen, 0);
+	// sanity check
+	if (iRet != iLen)
+		if (g_fLogging & NALOG_ALERT)
+			fprintf(g_log, "SendTCPMsg/2part: iRet(%d) != strlen(msg)(%d)!\n",
+				iRet, iLen);
+
+//TracePrint(ELL_TRACE, "UPnP 2part: 1st %d == %d (%d) (%d)?\n", iRet, iLen, strlen(msg), errno);
+
+	tv.tv_sec = g_iFunctionTimeout / UPNP_TIMEOUT_GRANULARITY;
+	tv.tv_usec = (g_iFunctionTimeout % U_TOGRAN) * 1000000 / U_TOGRAN;
+	FD_ZERO(&writefds);
+	FD_SET(s, &writefds);
+	// calculate how much time elapsed
+	gettimeofday(&tv_end, NULL);
+	GetTimeElapsed(&tv_start, &tv_end, &tv_elapsed);
+	if (CompareTime(&tv_elapsed, &tv) > 0) {
+		close(s);
+		return NA_E_TIMEOUT;
+		//tv.tv_sec = 0;
+		//tv.tv_usec = 0;
+	}
+	else {
+		// subtract that from timeout accordingly
+		tv.tv_sec -= tv_elapsed.tv_sec;
+		if (tv.tv_usec < tv_elapsed.tv_usec) {
+			tv.tv_sec--;
+			tv.tv_usec = 1000000 + tv.tv_usec - tv_elapsed.tv_usec;
+		}
+		else
+			tv.tv_usec = tv.tv_usec - tv_elapsed.tv_usec;
+	}
+	iRet = select(s+1, 0, &writefds, 0, &tv);
+	if (iRet < 0) {
+		if (g_fLogging & NALOG_ERROR)
+			fprintf(g_log, "SendTCPMsg/2part: select2 failed (%d)\n", errno);
+		iRetcode = NA_E_NET;
+		goto cleanup;
+	}
+	if (iRet == 0) {
+		if (g_fLogging & NALOG_ERROR)
+			fprintf(g_log, "SendTCPMsg/2part: select2 timed out\n");
+		iRetcode = NA_E_TIMEOUT;
+gettimeofday(&tv_end, NULL);
+GetTimeElapsed(&tv_start, &tv_end, &tv_elapsed);
+//TracePrint(ELL_TRACE, "UPnP 2part: timeout @2nd after %lu.%06lu secs\n",
+//	tv_elapsed.tv_sec, tv_elapsed.tv_usec);
+		goto cleanup;
+	}
+
+	iRet = send(s, msg2, iLen2, 0);
+	if (g_fLogging & NALOG_INFO1)
+		fprintf(g_log,
+			"SendTCPMsg/parse: Before Sending TCP Msg2: %d == %lu?\n",
+			iLen2, strlen(msg2));
+	if (g_fLogging & NALOG_DUMP)
+		fprintf(g_log, "Sending TCP msg part 2:\n[%s]\n", msg2);
+
+//TracePrint(ELL_TRACE, "UPnP 2part: 2nd %d == %d (%d) (%d)?\n", iRet, iLen2, strlen(msg2), errno);
+
+	// sanity check
+	if (iRet != iLen2)
+		if (g_fLogging & NALOG_ALERT)
+			fprintf(g_log, "SendTCPMsg/2part: iRet(%d) != strlen(msg2)(%d)!\n",
+				iRet, iLen2);
+
+	if (result == NULL) {    // if caller just want to send/display msgs
+		if (g_fLogging & NALOG_DUMP)
+			fprintf(g_log, "TCP Buffer: [");
+	}
+
+	if (g_fLogging & NALOG_INFO1)
+		fprintf(g_log, "start recv @%lu\n", time(NULL));
+
+	iBufLen = 0;
+	iContentLength = -1;
+	iBodyOffset = -1;
+	for (;;) {
+		fd_set			readfds;
+		struct timeval	timeout;
+		int				i;
+
+		FD_ZERO(&readfds);
+		FD_SET(s, &readfds);
+		//timeout.tv_sec = g_iFunctionTimeout / U_TOGRAN;
+		//timeout.tv_usec = (g_iFunctionTimeout % U_TOGRAN) * 1000000 / U_TOGRAN;
+		// just do flat 2 sec now, since connection already established
+		timeout.tv_sec = 1;
+		timeout.tv_usec = 0;
+
+
+		iRet = select(s+1, &readfds, NULL, NULL, &timeout);
+		if (iRet <= 0)
+		{
+//TracePrint(ELL_TRACE, "UPnP 2part: select timeout? (%d, %d)\n",
+//	iRet, errno);
+			break;
+		}
+
+//gettimeofday(&tv_end, NULL);
+//GetTimeElapsed(&tv_start, &tv_end, &tv_elapsed);
+//fprintf(stderr, "2 == loop: %d.%06d\n", tv_elapsed.tv_sec, tv_elapsed.tv_usec);
+
+		// if only sending messages
+		if (result == NULL) {
+			char	t[1000];
+			i = recv(s, t, 1000-1, 0);	// leave room for '\0' for dump
+			if (i== 0) break;
+			if (g_fLogging & NALOG_DUMP) {
+				t[i] = '\0';
+				fprintf(g_log, "%s", t);
+			}
+			continue;
+		}
+
+		// EO result buf: discard extra bytes
+		if (resultSize <= iBufLen) {
+			char	t[1000];
+			i = recv(s, &t, 1000, 0);
+			if (i== 0) break;
+			// Note that there's no dump here - prevents DoS attack from
+			// flooding the logs/diskspace
+			continue;
+		}
+
+		i = recv(s, result + iBufLen, resultSize - iBufLen, 0);
+		if (i <= 0) {
+//TracePrint(ELL_TRACE, "UPnP 2part: recv done %d (%d, %d)\n",
+//	iBufLen, i, errno);
+			break;
+		}
+
+		iBufLen += i;
+
+		// parse and see if we can find content-length to quit early
+		iContentLength = FindContentLength(result, iBufLen);
+
+		// now if we're still in header, see if we can find body
+		iBodyOffset = FindBody(result, iBufLen);
+
+		// now check if we can leave early.  conditions are:
+		// past headers, and we've already recv'ed content-length of body
+		if ((iBodyOffset >= 0) &&
+			(iContentLength >= 0) &&
+			((iBufLen - iBodyOffset) >= iContentLength))
+		{
+//TracePrint(ELL_TRACE, "UPnP 2part: read all specified %d (%d, %d) (%d, %d)\n",
+//	iBufLen, i, errno, iBodyOffset, iContentLength);
+			break;
+		}
+	}
+
+//fprintf(stderr, "2 -- \n");
+
+	if (g_fLogging & NALOG_INFO1)
+		fprintf(g_log, "done recv @%lu\n", time(NULL));
+
+	if (result == NULL) {    // if caller just want to send/display msgs
+		if (g_fLogging & NALOG_DUMP)
+			fprintf(g_log, "]\n");
+	}
+
+	close(s);
+	return iBufLen;
+
+cleanup:
+	close(s);
+	return iRetcode;
+}
+
+static int SendTCPMsg_saddr_parse(
+	char *msg, int iLen,
+	char *result, int resultSize,
+	struct sockaddr_in *saHost)
+{
+	int					s;
+	struct sockaddr_in	saSendTo;
+	int					iRet;
+	int					iBufLen;
+	int					fcntl_flags;
+	fd_set				writefds;
+	struct timeval		tv;
+
+	struct timeval		tv_start;
+//	struct timeval		tv_end;
+//	struct timeval		tv_elapsed;
+
+	// HTTP parsing vars
+	char				*pszCurHdr;
+	int					iContentLength;
+	int					iBodyOffset;
+//	char				prevChar;
+
+	tv.tv_sec = 0;
+	tv.tv_usec = 25000;
+	select(0, NULL, NULL, NULL, &tv);
+
+	pthread_mutex_lock(&g_xUPnPMsg);
+
+	gettimeofday(&tv_start, NULL);
+
+	if (g_fUPnPEnabled != TRUE) {
+//TracePrint(ELL_TRACE, "UPnP not enabled\n");
+		if (g_fLogging & NALOG_ERROR)
+			fprintf(g_log, "UPnP not enabled (no UPnP device found yet)\n");
+		pthread_mutex_unlock(&g_xUPnPMsg);
+		return NA_E_NOT_AVAILABLE;
+	}
+
+	s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+	if (s == -1) {
+		if (g_fLogging & NALOG_ERROR)
+			fprintf(g_log, "Can't get TCP socket (%d)\n", errno);
+		pthread_mutex_unlock(&g_xUPnPMsg);
+		return NA_E_NET;
+	}
+
+	fcntl_flags = 0;
+	fcntl_flags = fcntl(s, F_GETFL, 0);
+	fcntl_flags |= O_NONBLOCK;
+	if (fcntl(s, F_SETFL, fcntl_flags) != 0) {
+		if (g_fLogging & NALOG_ERROR)
+			fprintf(g_log, "SendTCPMsg/parse: Can't set O_NONBLOCK option!\n");
+		close(s);
+		pthread_mutex_unlock(&g_xUPnPMsg);
+		return NA_E_NET;
+	}
+
+	if (saHost == NULL)
+		memcpy(&saSendTo, &g_saddrRouterDesc, sizeof(saSendTo));
+	else
+		memcpy(&saSendTo, saHost, sizeof(saSendTo));
+
+	iRet = connect(s, (struct sockaddr *) &saSendTo, sizeof(saSendTo));
+	if ((iRet < 0) && (errno != EINPROGRESS)) {
+//TracePrint(ELL_TRACE, "UPnP connect failed\n");
+		if (g_fLogging & NALOG_ERROR)
+			fprintf(g_log, "SendTCPMsg/parse: connect failed (%d)\n", errno);
+		close(s);
+		pthread_mutex_unlock(&g_xUPnPMsg);
+		return NA_E_NET;
+	}
+
+	if (g_fLogging & NALOG_INFO1)
+		fprintf(g_log, "SendTCPMsg/parse: Before Sending TCP Msg: %d == %lu?\n",
+			iLen, strlen(msg));
+	if (g_fLogging & NALOG_DUMP)
+		fprintf(g_log,"Sending TCP msg:\n[%s]\n", msg);
+
+	tv.tv_sec = g_iFunctionTimeout / UPNP_TIMEOUT_GRANULARITY;
+	tv.tv_usec = (g_iFunctionTimeout % U_TOGRAN) * 1000000 / U_TOGRAN;
+	FD_ZERO(&writefds);
+	FD_SET(s, &writefds);
+	iRet = select(s+1, 0, &writefds, 0, &tv);
+	if (iRet < 0) {
+		if (g_fLogging & NALOG_ERROR)
+			fprintf(g_log, "SendTCPMsg/parse: select failed (%d)\n", errno);
+		close(s);
+		pthread_mutex_unlock(&g_xUPnPMsg);
+		return NA_E_NET;
+	}
+	if (iRet == 0) {
+		if (g_fLogging & NALOG_ERROR)
+			fprintf(g_log, "SendTCPMsg/parse: select timed out\n");
+		close(s);
+		pthread_mutex_unlock(&g_xUPnPMsg);
+		return NA_E_TIMEOUT;
+	}
+
+	iRet = send(s, msg, iLen, 0);
+
+	// sanity check
+	if (iRet != iLen)
+		if (g_fLogging & NALOG_ALERT)
+			fprintf(g_log, "SendTCPMsg: iRet (%d) != strlen(msg) (%d)!\n",
+				iRet, iLen);
+
+	if (result == NULL) {    // if caller just want to send/display msgs
+		if (g_fLogging & NALOG_DUMP)
+			fprintf(g_log, "TCP Buffer: [");
+	}
+
+	if (g_fLogging & NALOG_INFO1)
+		fprintf(g_log, "start recv @%lu\n", time(NULL));
+
+	iBufLen = 0;
+	pszCurHdr = result;
+	iContentLength = -1;
+	iBodyOffset = -1;
+	for (;;) {
+		fd_set			readfds;
+		struct timeval	timeout;
+		int				i;
+
+		FD_ZERO(&readfds);
+		FD_SET(s, &readfds);
+		//timeout.tv_sec = g_iFunctionTimeout / U_TOGRAN;
+		//timeout.tv_usec = (g_iFunctionTimeout % U_TOGRAN) * 1000000 / U_TOGRAN;
+		// just do flat 2 sec now, since connection already established
+		timeout.tv_sec = 1;
+		timeout.tv_usec = 0;
+
+		iRet = select(s+1, &readfds, NULL, NULL, &timeout);
+		if (iRet <= 0) {
+//fprintf(stderr, "**********: select failed (%d/%d)\n", iRet, errno);
+			break;
+		}
+
+//gettimeofday(&tv_end, NULL);
+//GetTimeElapsed(&tv_start, &tv_end, &tv_elapsed);
+//fprintf(stderr, "p == loop: %d.%06d\n", tv_elapsed.tv_sec, tv_elapsed.tv_usec);
+
+		// if only sending messages
+		if (result == NULL) {
+			char	t[1000];
+			i = recv(s, t, 1000-1, 0);	// leave room for '\0' for dump
+			if (i== 0) break;
+			if (g_fLogging & NALOG_DUMP) {
+				t[i] = '\0';
+				fprintf(g_log, "%s", t);
+			}
+			continue;
+		}
+
+		// EO result buf: discard extra bytes
+		if (resultSize <= iBufLen) {
+			char	t[1000];
+			i = recv(s, &t, 1000, 0);
+			if (i== 0) break;
+			// Note that there's no dump here - prevents DoS attack from
+			// flooding the logs/diskspace
+			continue;
+		}
+
+		i = recv(s, result + iBufLen, resultSize - iBufLen, 0);
+		if (0 == i) {
+
+			break;
+		}
+		else if (i < 0) {
+			if (EAGAIN == errno) continue;
+			break;
+		}
+
+		iBufLen += i;
+
+		// parse and see if we can find content-length to quit early
+		iContentLength = FindContentLength(result, iBufLen);
+
+		// now if we're still in header, see if we can find body
+		iBodyOffset = FindBody(result, iBufLen);
+
+	}
+
+//fprintf(stderr, "p -- \n");
+
+	if (g_fLogging & NALOG_INFO1)
+		fprintf(g_log, "done recv @%lu\n", time(NULL));
+
+	if (result == NULL) {    // if caller just want to send/display msgs
+		if (g_fLogging & NALOG_DUMP)
+			fprintf(g_log, "]\n");
+	}
+
+	close(s);
+	pthread_mutex_unlock(&g_xUPnPMsg);
+	return iBufLen;
+}
+
+
+
+// szSOAPMsgControlAHeaderFMT   - 4 args (ctrl_url, host/port, action, length)
+// szSOAPMsgControlABodyFMT     - 2 args (action, args string)
+// szSOAPMsgControlAArgumentFMT - 2 args (name/value)
+static PHTTPResponse SendSOAPMsgControlAction(
+	char *action,
+	int argc,
+	PProperty args,
+	int f2Part)
+{
+	//char	outBuffer[65536];
+	//char	outBufferBody[65536];
+	//char	outBufferArgs[65536];
+	char	*outBuffer = NULL;
+	char	*outBufferBody = NULL;
+	char	*outBufferArgs = NULL;
+	char	*inBuffer = NULL;
+	int		iLen;
+	int		iHeaderLen;
+	int		iBodyLen;
+	int		iArgsLen;
+	int		iResultLen;
+	int		i;
+	int		n;
+	PHTTPResponse pResponse = NULL;
+
+
+	if (!WaitUPnPFunction())
+		return NULL;
+
+	if ((outBuffer = (char *) malloc(MAX_SOAPMSGSIZE)) == NULL) {
+		if (g_fLogging & NALOG_ERROR)
+			fprintf(g_log, "can't malloc for outBuffer\n");
+		goto cleanup;
+	}
+	if ((outBufferBody = (char *) malloc(MAX_SOAPMSGSIZE)) == NULL) {
+		if (g_fLogging & NALOG_ERROR)
+			fprintf(g_log, "can't malloc for outBufferBody\n");
+		goto cleanup;
+	}
+	if ((outBufferArgs = (char *) malloc(MAX_SOAPMSGSIZE)) == NULL) {
+		if (g_fLogging & NALOG_ERROR)
+			fprintf(g_log, "can't malloc for outBufferArgs\n");
+		goto cleanup;
+	}
+	if ((inBuffer = (char *) malloc(MAX_SOAPMSGSIZE)) == NULL) {
+		if (g_fLogging & NALOG_ERROR)
+			fprintf(g_log, "can't malloc for inBuffer\n");
+		goto cleanup;
+	}
+
+	iArgsLen = 0;
+	if (args != NULL)
+		for (i=0; i<argc; i++) {
+			n = 0;
+			if (args[i].pszType == NULL) {
+				n = sprintf(outBufferArgs + iArgsLen,
+					szSOAPMsgControlAArgumentFMT,
+					args[i].pszName, args[i].pszValue);
+			}
+			else {
+				n = sprintf(outBufferArgs + iArgsLen,
+					szSOAPMsgControlAArgumentFMT_t,
+					args[i].pszName, args[i].pszValue, args[i].pszType);
+			}
+			iArgsLen += n;
+		}
+	outBufferArgs[iArgsLen] = '\0';
+
+	iBodyLen = sprintf(outBufferBody, szSOAPMsgControlABodyFMT,
+		action, outBufferArgs);
+
+	iHeaderLen = sprintf(outBuffer, szSOAPMsgControlAHeaderFMT,
+		g_szControlURL, g_szRouterHostPortSOAP, action, iBodyLen);
+
+	if (f2Part) {
+		DumpHex(outBuffer, iHeaderLen+1);
+		DumpHex(outBufferBody, iBodyLen+1);
+		iResultLen = SendTCPMsg_saddr_2part(
+			outBuffer, iHeaderLen,
+			outBufferBody, iBodyLen,
+			inBuffer, MAX_SOAPMSGSIZE,
+			&g_saddrRouterSOAP);
+	}
+	else {
+		strcpy(outBuffer + iHeaderLen, outBufferBody);
+		iLen = iHeaderLen + iBodyLen;
+
+		DumpHex(outBuffer, iLen+1);
+
+//strcat(outBuffer, CRLF "0" CRLF CRLF);
+//iLen += 7;
+
+		iResultLen = SendTCPMsg_saddr_parse(
+			outBuffer, iLen,
+			inBuffer, MAX_SOAPMSGSIZE,
+			&g_saddrRouterSOAP);
+	}
+
+	if (iResultLen > 0) {
+		if (iResultLen > MAX_SOAPMSGSIZE) {
+			if (g_fLogging & NALOG_ALERT)
+				fprintf(g_log, "result truncated..\n");
+			iResultLen = MAX_SOAPMSGSIZE;
+		}
+		pResponse = NewHTTPResponse_sz(inBuffer, iResultLen, FALSE);
+		if (pResponse != NULL) {
+			PrintHTTPResponse(pResponse);
+			//DeleteHTTPResponse(pResponse);
+			// - return response to caller
+		}
+	}
+	else {
+		if (g_fLogging & NALOG_ERROR)
+			fprintf(g_log, "No TCP Response\n");
+		//TracePrint(ELL_TRACE, "UPnP SendSOAPMsg got no TCP response (%d)\n",
+//			iResultLen);
+	}
+
+cleanup:
+	if (outBuffer != NULL) free(outBuffer);
+	if (outBufferBody != NULL) free(outBufferBody);
+	if (outBufferArgs != NULL) free(outBufferArgs);
+	if (inBuffer != NULL) free(inBuffer);
+
+	return pResponse;
+}
+
+static int FindURLBase(char *pbuf, int iLen, char *szURLBase)
+{
+	// non reusable XML parsing code:
+	// ----------------------------------------------
+	char			*p;
+	int				i = 0;
+
+	// now skip after end of this tag, then skip until controlURL tag
+	p = strstr_n(pbuf, "<URLBase>", iLen);
+	if (p == NULL) return -1;
+
+	// skip to the actual stuff
+	p += sizeof("<URLBase>") - 1;  // minus '\0'
+
+	// skip white spaces (just in case)
+	while (isspace(*p))
+		p++;
+
+	// copy into szURLBase
+	while ((*p != '\0') && (*p != '<') && !isspace(*p)) {
+		if (i++ > 1000) break;
+		*szURLBase = *p;
+		szURLBase++;
+		p++;
+	}
+	*szURLBase = '\0';
+
+	return 0;
+	// ----------------------------------------------
+}
+
+
+static int FindDescInfo(
+	char *pbuf,
+	int iLen,
+	const char *szParentName,
+	const char *szName,
+	char *szValue)
+{
+	char			*p;
+	char			szSearch[100];
+	int				iSearchLen;
+	int				i = 0;
+
+	// find the device within pbuf
+	p = strstr_n(
+		pbuf,
+		szParentName,
+		iLen);
+	if (p == NULL)
+		return -1;
+
+	// adjust strlen
+	iLen -= (p - pbuf);
+	pbuf = p;
+
+	// now skip after end of this tag, then skip until manufacturer tag
+	iSearchLen = sprintf(szSearch, "<%s>", szName);
+	p = strstr_n(pbuf, szSearch, iLen);
+	if (p == NULL) return -1;
+	p += iSearchLen;
+
+	// skip white spaces (just in case)
+	while (isspace(*p))
+		p++;
+
+	// copy into szValue
+	while ((*p != '\0') && (*p != '<')) {
+		if (i++ > 1000) break;
+		*szValue = *p;
+		szValue++;
+		p++;
+	}
+	*szValue = '\0';
+
+	return 0;
+}
+
+static int FindIGDInfo(char *pbuf, int iLen, const char *szName, char *szValue)
+{
+	return FindDescInfo(
+		pbuf, iLen,
+		"urn:schemas-upnp-org:device:InternetGatewayDevice:1",
+		szName, szValue);
+}
+
+static int FindManufacturer(char *pbuf, int iLen, char *szManuf)
+{
+	return FindIGDInfo(pbuf, iLen, "manufacturer", szManuf);
+}
+
+static int FindFriendlyName(char *pbuf, int iLen, char *szValue)
+{
+	return FindIGDInfo(pbuf, iLen, "friendlyName", szValue);
+}
+
+static int FindModelName(char *pbuf, int iLen, char *szValue)
+{
+	return FindIGDInfo(pbuf, iLen, "modelName", szValue);
+}
+
+static int FindModelDescription(char *pbuf, int iLen, char *szValue)
+{
+	return FindIGDInfo(pbuf, iLen, "modelDescription", szValue);
+}
+
+static int FindWANIPInfo(char *pbuf, int iLen, const char *szName, char *szValue)
+{
+	return FindDescInfo(
+		pbuf, iLen,
+		"urn:schemas-upnp-org:service:WANIPConnection:1",
+		szName, szValue);
+}
+
+static int FindControlURL(char *pbuf, int iLen, char *szControlURL)
+{
+	return FindWANIPInfo(pbuf, iLen, "controlURL", szControlURL);
+}
+
+static int FindEventURL(char *pbuf, int iLen, char *szEventURL)
+{
+	return FindWANIPInfo(pbuf, iLen, "eventSubURL", szEventURL);
+}
+
+static int FindRouterInfo(char *inBuffer, int iLen)
+{
+	if (FindManufacturer(inBuffer, iLen, g_szManufacturer) != 0)
+		g_szManufacturer[0] = '\0';
+
+	if (FindFriendlyName(inBuffer, iLen, g_szFriendlyName) != 0)
+		g_szFriendlyName[0] = '\0';
+
+	if (FindModelName(inBuffer, iLen, g_szModelName) != 0)
+		g_szModelName[0] = '\0';
+
+	if (FindModelDescription(inBuffer, iLen, g_szModelDescription) != 0)
+		g_szModelDescription[0] = '\0';
+
+//TracePrint(ELL_TRACE,
+//	"UPnP Router Info:\n"
+//	" - manufacturer   [%s]\n"
+//	" - friendly name  [%s]\n"
+//	" - model name     [%s]\n"
+//	" - model desc     [%s]\n",
+//	g_szManufacturer, g_szFriendlyName, g_szModelName, g_szModelDescription);
+
+	return 0;
+}
+
+static void ParseURL(
+	const char *szBuf, char *pszHostPort,
+	struct sockaddr_in *psaddr, char *pszPath)
+{
+	char			buf[1024];
+	char			*p;
+	char			*q;
+	unsigned short	port;
+
+	strcpy(buf, szBuf);
+
+	p = buf;
+	if (0 == strncmp(p, "http://", 7))
+		p += 7;
+
+	q = strchr(p, '/');
+
+	if (pszPath) {
+		if (NULL == q) {
+			pszPath[0] = '/';
+			pszPath[1] = '\0';
+		}
+		else  {
+			strcpy(pszPath, q);
+			*q = '\0';
+		}
+	}
+
+	// find the port separetor
+	q = strchr(p, ':');
+	if (NULL == q)
+		port = 80;
+	else {
+		port = atoi(q + 1);
+		// HTTP's by default port 80, so don't have it in the "Host:" header
+		if (80 == port) *q = '\0';
+	}
+
+	if (pszHostPort) strcpy(pszHostPort, p);
+
+	if (NULL != q) *q = '\0';
+
+	if (NULL != psaddr) {
+		psaddr->sin_family = AF_INET;
+		psaddr->sin_addr.s_addr = inet_addr(p);
+		psaddr->sin_port = htons(port);
+	}
+#if 0
+//TracePrint(ELL_TRACE, "ParseURL [%s] -> [%s][%s] %lu.%lu.%lu.%lu:%u\n",
+	szBuf,
+	pszHostPort?pszHostPort:"",
+	pszPath?pszPath:"",
+	(psaddr->sin_addr.s_addr >> 24) & 0xff,
+	(psaddr->sin_addr.s_addr >> 16) & 0xff,
+	(psaddr->sin_addr.s_addr >> 8) & 0xff,
+	(psaddr->sin_addr.s_addr >> 0) & 0xff,
+	psaddr->sin_port);
+#endif
+}
+
+static void GetDeviceDescription(void)
+{
+	char		*outBuffer = NULL;
+	char		*inBuffer = NULL;
+	int			iBufLen;
+	int			iLen;
+	char		szURLBase[1024];
+	char		szControlURL[1024];
+	char		szEventURL[1024];
+
+	if (!g_fUPnPEnabled) {
+		if (g_fLogging & NALOG_ERROR)
+			fprintf(g_log, "GetDeviceDescription: upnp not enabled\n");
+		return;
+	}
+
+	if ((outBuffer = (char *) malloc(MAX_SOAPMSGSIZE)) == NULL) {
+		if (g_fLogging & NALOG_ERROR)
+			fprintf(g_log, "can't malloc for outBuffer\n");
+		goto cleanup;
+	}
+	if ((inBuffer = (char *) malloc(MAX_SOAPMSGSIZE)) == NULL) {
+		if (g_fLogging & NALOG_ERROR)
+			fprintf(g_log, "can't malloc for inBuffer\n");
+		goto cleanup;
+	}
+
+	iBufLen = sprintf(outBuffer, szSSDPMsgDescribeDeviceFMT, g_szNATDevDescURL,
+		g_szRouterHostPortDesc);
+
+	if (g_fLogging & NALOG_INFO1)
+		fprintf(g_log, "Describe Device: [%s]\n", outBuffer);
+	iLen = SendTCPMsg_saddr_parse(outBuffer, iBufLen, inBuffer, MAX_SOAPMSGSIZE,
+		&g_saddrRouterDesc);
+
+	g_fControlURLSet = FALSE;
+
+	if (FindControlURL(inBuffer, iLen, szControlURL) != 0) {
+		if (g_fLogging & NALOG_ERROR)
+			fprintf(g_log, "GetDeviceDesc: can't find control URL\n");
+		goto cleanup;
+	}
+
+	// start modifying global
+	pthread_mutex_lock(&g_xUPnP);
+
+	{
+		// now see if there's the URLBase
+		if (FindURLBase(inBuffer, iLen, szURLBase) != 0) {
+			// not there?  try default numbers from device description
+			memcpy(&g_saddrRouterBase, &g_saddrRouterDesc,
+				sizeof(g_saddrRouterBase));
+			strcpy(g_szRouterHostPortBase, g_szRouterHostPortDesc);
+		}
+		else {
+			ParseURL(szURLBase,
+				g_szRouterHostPortBase, &g_saddrRouterBase, NULL);
+
+			if ((strlen(g_szRouterHostPortBase) == 0) ||
+				(g_saddrRouterBase.sin_addr.s_addr == INADDR_NONE)) {
+				memcpy(&g_saddrRouterBase, &g_saddrRouterDesc,
+					sizeof(g_saddrRouterBase));
+				strcpy(g_szRouterHostPortBase, g_szRouterHostPortDesc);
+			}
+		}
+	}
+
+	ParseURL(szControlURL,
+		g_szRouterHostPortSOAP, &g_saddrRouterSOAP, g_szControlURL);
+	if ((strlen(g_szRouterHostPortSOAP) == 0) ||
+		(g_saddrRouterSOAP.sin_addr.s_addr == INADDR_NONE)) {
+		memcpy(&g_saddrRouterSOAP, &g_saddrRouterBase,
+			sizeof(g_saddrRouterSOAP));
+		strcpy(g_szRouterHostPortSOAP, g_szRouterHostPortBase);
+	}
+
+
+////TracePrint(ELL_TRACE, "UPnP Control URL set to[%s][%s]...\n",
+//	g_szRouterHostPortSOAP, g_szControlURL);
+
+	g_fControlURLSet = TRUE;
+	gettimeofday(&g_tvLastUpdateTime, NULL);
+	pthread_cond_broadcast(&g_condUPnPControlURL);
+
+	if (g_fLogging & NALOG_INFO1)
+		fprintf(g_log, "Got Device Description\n");
+
+	// find router info
+	FindRouterInfo(inBuffer, iLen);
+
+	if (FindEventURL(inBuffer, iLen, szEventURL) != 0) {
+		szEventURL[0] = '\0';
+	}
+	else {
+		ParseURL(szEventURL,
+			g_szRouterHostPortEvent, &g_saddrRouterEvent, g_szEventURL);
+		if ((strlen(g_szRouterHostPortEvent) == 0) ||
+			(g_saddrRouterEvent.sin_addr.s_addr == INADDR_NONE)) {
+			memcpy(&g_saddrRouterEvent, &g_saddrRouterBase,
+				sizeof(g_saddrRouterEvent));
+			strcpy(g_szRouterHostPortEvent, g_szRouterHostPortBase);
+		}
+
+		EventInit();
+	}
+
+cleanup:
+	if (outBuffer != NULL) free(outBuffer);
+	if (inBuffer != NULL) free(inBuffer);
+
+	pthread_mutex_unlock(&g_xUPnP);
+}
+
+
+static void GetIPByName(char *hostname, unsigned long *ip_ret)
+{
+	unsigned long ip;
+
+	ip = inet_addr(hostname);
+	if (ip == INADDR_NONE) {
+		struct hostent *pHEnt;
+		pHEnt = gethostbyname(hostname);
+		if (pHEnt == NULL) {
+			if (g_fLogging & NALOG_ALERT)
+				fprintf(g_log, "Can't translate [%s] to IP...\n", hostname);
+			g_dwLocalIP = htonl(INADDR_ANY);
+			return;
+		}
+		ip = ntohl(*(unsigned long *)(pHEnt->h_addr));
+		if (g_fLogging & NALOG_INFO1)
+			fprintf(g_log, "hostname [%s] to ip: %ld.%ld.%ld.%ld\n",
+				hostname,
+				(ip >> 24) & 0xff,
+				(ip >> 16) & 0xff,
+				(ip >> 8) & 0xff,
+				(ip >> 0) & 0xff);
+	}
+	*ip_ret = ip;
+}
+
+static void SetLocalIP()
+{
+	PIPINFO pIPInfo = NULL;
+	int count = GetIPInfo(&pIPInfo);
+	if (NULL != pIPInfo)
+	{
+		// choose first non IPV6 address
+		// iterate through array and set port information
+		int				i;
+		unsigned long	dwFirst = 0;
+		for(i = 0; i < count; i++)
+		{
+			if (!(pIPInfo[i].iFlags & ISIPV6) &&
+				(strncmp(pIPInfo[i].szIfName, "ppp", 3) != 0))
+			{
+				unsigned long	dwTemp;
+
+				memcpy(&dwTemp, pIPInfo[i].abIP, sizeof(unsigned long));
+
+				if (0 != GetNATIPNetmask(dwTemp)) {
+					g_dwLocalIP = dwTemp;
+					break;
+				}
+
+				if (0 == dwFirst)
+					dwFirst = dwTemp;
+			}
+		}
+		if (i == count)
+			g_dwLocalIP = dwFirst;
+		FreeIPInfo(pIPInfo);
+	}
+
+}
+
+static int FindTagContent(const char *text, const char *tagname, char *buf)
+{
+	char	*p;
+	// parse the xml
+	p = strstr(text, tagname);
+	if (p == NULL) {
+		if (g_fLogging & NALOG_INFO0)
+			fprintf(g_log, "FindTagContent: can't find %s\n", tagname);
+		return NA_E_PARSE_ERROR;
+	}
+
+	if (sscanf(p, "%*[^>]> %[^ <] <", buf) < 1) {
+		if (g_fLogging & NALOG_INFO0)
+			fprintf(g_log, "FindTagContent: Can't parse tag %s\n", tagname);
+		return NA_E_PARSE_ERROR;
+	}
+
+	return NA_E_SUCCESS;
+}
+
+mStatus LNT_UnmapPort(mDNSIPPort PubPort, mDNSBool tcp)
+{
+	//int				iLen;
+	char			szEPort[10];
+	//char			szRemoteHost[1024];
+	//unsigned		long dwIP;
+	Property		propArgs[3];
+	PHTTPResponse	resp;
+    unsigned short port = PubPort.NotAnInteger;
+    int protocol = tcp ? IPPROTO_TCP : IPPROTO_UDP;
+	sprintf(szEPort, "%u", port);
+
+	bzero(propArgs, sizeof(propArgs));
+	propArgs[0].pszName = "NewRemoteHost";
+	propArgs[0].pszValue = "";
+	propArgs[0].pszType = "string";
+	propArgs[1].pszName = "NewExternalPort";
+	propArgs[1].pszValue = szEPort;
+	propArgs[1].pszType = "ui2";
+	propArgs[2].pszName = "NewProtocol";
+	if (protocol == IPPROTO_TCP) {
+		propArgs[2].pszValue = "TCP";
+	}
+	else if (protocol == IPPROTO_UDP) {
+		propArgs[2].pszValue = "UDP";
+	}
+	else {
+		return -1;
+	}
+	propArgs[2].pszType = "string";
+
+	resp = SendSOAPMsgControlAction(
+		"DeletePortMapping", 3, propArgs, FALSE);
+	if (resp == NULL) {
+		return mStatus_NATTraversal;
+	}
+
+	if (strcmp(resp->pszStatus, "200") != 0) {
+		DeleteHTTPResponse(resp);
+		return mStatus_NATTraversal;
+	}
+
+	DeleteHTTPResponse(resp);
+	return mStatus_NoError;
+}
+
+
+static int GetMappingUnused(unsigned short eport, int protocol);
+
+extern mStatus LNT_MapPort(mDNSIPPort priv, mDNSIPPort pub, mDNSBool tcp)
+{
+	char			szEPort[6];
+	char			szIPort[6];
+	unsigned		long dwIP;
+	char			szLocalIP[30];
+	char			descr[40];
+	Property		propArgs[8];
+	PHTTPResponse	resp;
+    unsigned short iport = priv.NotAnInteger;
+    unsigned short eport = pub.NotAnInteger;
+    int protocol = tcp ? IPPROTO_TCP : IPPROTO_UDP;
+
+
+	if (NA_E_EXISTS == GetMappingUnused(eport, protocol))
+		return mStatus_AlreadyRegistered;
+
+	//DeletePortMapping(eport, protocol);
+
+	sprintf(szEPort, "%u", eport);
+
+	sprintf(szIPort, "%u", iport);
+
+	dwIP = g_dwLocalIP;
+	sprintf(szLocalIP, "%u.%u.%u.%u",
+		(unsigned int)((dwIP >> 24) & 0xff),
+		(unsigned int)((dwIP >> 16) & 0xff),
+		(unsigned int)((dwIP >> 8) & 0xff),
+		(unsigned int)((dwIP >> 0) & 0xff));
+
+	bzero(propArgs, sizeof(propArgs));
+	propArgs[0].pszName = "NewRemoteHost";
+	propArgs[0].pszValue = "";
+	propArgs[0].pszType = "string";
+	propArgs[1].pszName = "NewExternalPort";
+	propArgs[1].pszValue = szEPort;
+	propArgs[1].pszType = "ui2";
+	propArgs[2].pszName = "NewProtocol";
+	if (protocol == IPPROTO_TCP) {
+		propArgs[2].pszValue = "TCP";
+	}
+	else if (protocol == IPPROTO_UDP) {
+		propArgs[2].pszValue = "UDP";
+	}
+	else {
+		return mStatus_BadParamErr;
+	}
+	propArgs[2].pszType = "string";
+	propArgs[3].pszName = "NewInternalPort";
+	propArgs[3].pszValue = szIPort;
+	propArgs[3].pszType = "ui2";
+	propArgs[4].pszName = "NewInternalClient";
+	propArgs[4].pszValue = szLocalIP;
+	propArgs[4].pszType = "string";
+	propArgs[5].pszName = "NewEnabled";
+	propArgs[5].pszValue = "1";
+	propArgs[5].pszType = "boolean";
+	propArgs[6].pszName = "NewPortMappingDescription";
+	sprintf(descr, "iC%u", eport);
+	//propArgs[6].pszValue = "V";
+	propArgs[6].pszValue = descr;
+	propArgs[6].pszType = "string";
+	propArgs[7].pszName = "NewLeaseDuration";
+	propArgs[7].pszValue = "0";
+	propArgs[7].pszType = "ui4";
+
+	resp = SendSOAPMsgControlAction(
+		"AddPortMapping", 8, propArgs, FALSE);
+
+	if (resp == NULL) {
+		return mStatus_NATTraversal;
+	}
+
+	if (strcmp(resp->pszStatus, "200") != 0) {
+		DeleteHTTPResponse(resp);
+		return mStatus_NATTraversal;
+	}
+
+	DeleteHTTPResponse(resp);
+	return mStatus_NoError;
+}
+
+static int GetMappingUnused(unsigned short eport, int protocol)
+{
+	char			buf[1024];
+	char			szPort[10];
+	Property		propArgs[3];
+	PHTTPResponse	resp;
+	unsigned long	ip;
+
+	sprintf( szPort, "%u", eport);
+
+	bzero(&propArgs, sizeof(propArgs));
+	propArgs[0].pszName = "NewRemoteHost";
+	propArgs[0].pszValue = "";
+	propArgs[0].pszType = "string";
+	propArgs[1].pszName = "NewExternalPort";
+	propArgs[1].pszValue = szPort;
+	propArgs[1].pszType = "ui2";
+	propArgs[2].pszName = "NewProtocol";
+	if (protocol == IPPROTO_TCP) {
+		propArgs[2].pszValue = "TCP";
+	}
+	else if (protocol == IPPROTO_UDP) {
+		propArgs[2].pszValue = "UDP";
+	}
+	else {
+		return NA_E_INVALID_PARAMETER;
+	}
+	propArgs[2].pszType = "string";
+
+	resp = SendSOAPMsgControlAction(
+		"GetSpecificPortMappingEntry", 3, propArgs, FALSE);
+	if (resp != NULL) {
+		if ((strcmp(resp->pszStatus, "200") == 0) &&
+			(FindTagContent(resp->pszBody, "NewInternalClient", buf) == 0))
+		{
+			GetIPByName(buf, &ip);
+			if (ip == g_dwLocalIP) {
+				// (perhaps we let it go?)
+				DeleteHTTPResponse(resp);
+				return NA_E_SUCCESS;
+			}
+			else {
+				DeleteHTTPResponse(resp);
+				return NA_E_EXISTS;
+			}
+		}
+		DeleteHTTPResponse(resp);
+	}
+
+	return NA_E_SUCCESS;
+}
+
+mStatus LNT_GetPublicIP(mDNSOpaque32 *IpPtr)
+{
+	char			buf[1024];
+	PHTTPResponse	resp;
+	static struct timeval	tvLastGoodIP = {0,0};
+	static unsigned long	dwLastGoodIP;
+	struct timeval			tv;
+	unsigned long *ip       = (unsigned long *)IpPtr;
+	if (ip == NULL) return mStatus_BadParamErr;
+
+	gettimeofday(&tv, NULL);
+	GetTimeElapsed(&tvLastGoodIP, &tv, &tv);
+	if (tv.tv_sec < 4)
+	{
+		return dwLastGoodIP;
+	}
+
+	resp = SendSOAPMsgControlAction(
+		"GetExternalIPAddress", 0, NULL, FALSE);
+
+	if (resp == NULL)
+		return mStatus_NATTraversal;
+
+	if (FindTagContent(resp->pszBody, "NewExternalIPAddress", buf) == 0) {
+		if (g_fLogging & NALOG_INFO1)
+			fprintf(g_log, "Mapped remote host = %s\n", buf);
+		*ip = inet_addr(buf);
+		DeleteHTTPResponse(resp);
+
+		gettimeofday(&tvLastGoodIP, NULL);
+		dwLastGoodIP = *ip;
+
+		return mStatus_NoError;
+	}
+
+	DeleteHTTPResponse(resp);
+	return mStatus_NATTraversal;
+}
+
+static void SendDiscoveryMsg()
+{
+	// do it twice to avoid lost packet
+	//SendUDPMsg(szSSDPMsgDiscoverNAT);
+	SendUDPMsg(szSSDPMsgDiscoverRoot);
+	SendUDPMsg(szSSDPMsgDiscoverIGD);
+	SendUDPMsg(szSSDPMsgDiscoverNAT);
+}
+
+// Set up threads for upnp responses, etc.
+int LegacyNATInit(void)
+{
+	//pthread_t		UDPthread;
+	pthread_attr_t	attr;
+	int				iRet;
+	//struct timeval	tv;
+
+	static int		fFirstInitLocks = TRUE;
+	FILE *log = NULL;	
+	
+	g_fLogging = 0;
+	g_log = stderr;
+
+	SetLocalIP();
+
+	g_fQuit = FALSE;
+
+	if (fFirstInitLocks)
+	{
+		// init locks
+		if (pthread_mutex_init(&g_xUPnP, NULL)) {
+			if (g_fLogging & NALOG_ERROR)
+				fprintf(log, "UpnpInit - mutex init failed\n");
+			return NA_E_INTERNAL_ERROR;
+		}
+		if (pthread_cond_init(&g_condUPnP, NULL)) {
+			pthread_mutex_destroy(&g_xUPnP);
+			if (g_fLogging & NALOG_ERROR)
+				fprintf(log, "UpnpInit - cond init failed\n");
+			return NA_E_INTERNAL_ERROR;
+		}
+		if (pthread_cond_init(&g_condUPnPControlURL, NULL)) {
+			pthread_mutex_destroy(&g_xUPnP);
+			pthread_cond_destroy(&g_condUPnP);
+			if (g_fLogging & NALOG_ERROR)
+				fprintf(log, "UpnpInit - cond init failed\n");
+			return NA_E_INTERNAL_ERROR;
+		}
+		if (pthread_mutex_init(&g_xUPnPMsg, NULL)) {
+			pthread_mutex_destroy(&g_xUPnP);
+			pthread_cond_destroy(&g_condUPnP);
+			pthread_cond_destroy(&g_condUPnPControlURL);
+			if (g_fLogging & NALOG_ERROR)
+				fprintf(log, "UpnpInit - mutex init failed\n");
+			return NA_E_INTERNAL_ERROR;
+		}
+
+		fFirstInitLocks = FALSE;
+	}
+
+	if (g_fFirstInit)
+	{
+		// initialize UDP socket for SSDP
+		g_sUDP = SSDPListen();
+		g_sUDPCancel = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); // sock to signal canccelation to UDP thread
+		if (g_sUDP < 0 || g_sUDPCancel < 0) {
+			if (g_fLogging & NALOG_ERROR)
+				fprintf(log, "UpnpInit - Failed to init multicast socket.\n");
+			return NA_E_INTERNAL_ERROR;
+		}
+
+		// make UDP thread
+		pthread_attr_init(&attr);
+		iRet = pthread_create(&g_UDPthread, &attr, UDPProc, log);
+		if (iRet != 0) {
+			g_fFirstInit = TRUE;		// so we'll redo this part next time
+			close(g_sUDP);
+			g_sUDP = -1;
+			if (g_fLogging & NALOG_ERROR)
+				fprintf(log, "UpnpInit - pthread create failed (%d)\n", iRet);
+			return NA_E_THREAD_ERROR;
+		}
+
+		// set this to FALSE only if first call succeeded
+		g_fFirstInit = FALSE;
+
+		//TracePrint(ELL_TRACE, "UPnP init passed\n");
+
+		//tv.tv_sec = 0;
+		//tv.tv_usec = 20000;   // wait 20ms for thread/udp/multicast init
+		//select(0, 0, 0, 0, &tv);
+	}
+
+	// send discovery message
+	SendDiscoveryMsg();
+
+	return NA_E_SUCCESS;
+}
+
+int LegacyNATDestroy()
+{
+    void *UDPThreadRetVal; 
+	g_fQuit = TRUE;
+	if (g_sTCPCancel >= 0) close(g_sTCPCancel);
+	if (g_sUDPCancel >= 0) close(g_sUDPCancel);
+	pthread_join(g_UDPthread, &UDPThreadRetVal);
+	g_sTCPCancel = -1;
+	g_sUDPCancel = -1;
+	g_fFirstInit = TRUE;
+	g_fUPnPEnabled = FALSE;
+	g_fControlURLSet = FALSE;
+	return NA_E_SUCCESS;
+}
diff --git a/mDNSMacOSX/SamplemDNSClient.c b/mDNSMacOSX/SamplemDNSClient.c
index 430d0e6..a387269 100644
--- a/mDNSMacOSX/SamplemDNSClient.c
+++ b/mDNSMacOSX/SamplemDNSClient.c
@@ -3,8 +3,6 @@
  *
  * @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
@@ -38,6 +36,12 @@
     Change History (most recent first):
 
 $Log: SamplemDNSClient.c,v $
+Revision 1.46  2004/11/02 01:32:34  cheshire
+<rdar://problem/3861705> Update code so it still compiles when DNSServiceDiscovery.h is deprecated
+
+Revision 1.45  2004/06/15 02:39:47  cheshire
+When displaying error message, only show command name, not entire path
+
 Revision 1.44  2004/05/28 02:20:06  cheshire
 If we allow dot or empty string for domain when resolving a service,
 it should be a synonym for "local"
@@ -80,6 +84,12 @@ Add checkin history header
 #include <arpa/inet.h>
 #include <net/if.h>
 #include <CoreFoundation/CoreFoundation.h>
+
+// We already know this tool is using the old deprecated API (that's its purpose)
+// Since we compile with all warnings treated as errors, we have to turn off the warnings here or the project won't compile
+#include <AvailabilityMacros.h>
+#undef AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED
+#define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED
 #include <DNSServiceDiscovery/DNSServiceDiscovery.h>
 
 //*************************************************************************************************************
@@ -322,6 +332,7 @@ static void reg_reply(DNSServiceRegistrationReplyErrorType errorCode, void *cont
 
 int main(int argc, char **argv)
 	{
+	const char *progname = strrchr(argv[0], '/') ? strrchr(argv[0], '/') + 1 : argv[0];
 	char *dom;
 	setlinebuf(stdout);				// Want to see lines as they appear, not block buffered
 
@@ -443,16 +454,16 @@ Exit:
 	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 -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]);
+	fprintf(stderr, "%s -E                  (Enumerate recommended registration domains)\n", progname);
+	fprintf(stderr, "%s -F                      (Enumerate recommended browsing domains)\n", progname);
+	fprintf(stderr, "%s -B        <Type> <Domain>        (Browse for services instances)\n", progname);
+	fprintf(stderr, "%s -L <Name> <Type> <Domain>           (Look up a service instance)\n", progname);
+	fprintf(stderr, "%s -R <Name> <Type> <Domain> <Port> [<TXT>...] (Register a service)\n", progname);
+	fprintf(stderr, "%s -A                      (Test Adding/Updating/Deleting a record)\n", progname);
+	fprintf(stderr, "%s -U                                  (Test updating a TXT record)\n", progname);
+	fprintf(stderr, "%s -N                             (Test adding a large NULL record)\n", progname);
+	fprintf(stderr, "%s -T                            (Test creating a large TXT record)\n", progname);
+	fprintf(stderr, "%s -M      (Test creating a registration with multiple TXT records)\n", progname);
+	fprintf(stderr, "%s -I   (Test registering and then immediately updating TXT record)\n", progname);
 	return 0;
 	}
diff --git a/mDNSMacOSX/daemon.c b/mDNSMacOSX/daemon.c
index 9cb6a47..e82657e 100644
--- a/mDNSMacOSX/daemon.c
+++ b/mDNSMacOSX/daemon.c
@@ -3,8 +3,6 @@
  *
  * @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
@@ -38,6 +36,177 @@
     Change History (most recent first):
 
 $Log: daemon.c,v $
+Revision 1.227  2004/12/10 13:52:57  cheshire
+<rdar://problem/3909995> Turn off SIGPIPE signals
+
+Revision 1.226  2004/12/10 05:27:26  cheshire
+<rdar://problem/3909147> Guard against multiple autoname services of the same type on the same machine
+
+Revision 1.225  2004/12/10 04:28:29  cheshire
+<rdar://problem/3914406> User not notified of name changes for services using new UDS API
+
+Revision 1.224  2004/12/10 00:41:05  cheshire
+Adjust alignment of log messages
+
+Revision 1.223  2004/12/07 20:42:34  cheshire
+Add explicit context parameter to mDNS_RemoveRecordFromService()
+
+Revision 1.222  2004/12/06 21:15:23  ksekar
+<rdar://problem/3884386> mDNSResponder crashed in CheckServiceRegistrations
+
+Revision 1.221  2004/11/30 03:24:04  cheshire
+<rdar://problem/3854544> Defer processing network configuration changes until configuration has stabilized
+
+Revision 1.220  2004/11/29 23:34:31  cheshire
+On platforms with coarse time resolutions, ORing time values with one to ensure they are non-zero
+is crude, and effectively halves the time resolution. The more selective NonZeroTime() function
+only nudges the time value to 1 if the interval calculation happens to result in the value zero.
+
+Revision 1.219  2004/11/25 01:00:56  cheshire
+Checkin 1.217 not necessary
+
+Revision 1.218  2004/11/24 20:27:19  cheshire
+Add missing "err" parameter in LogMsg() call
+
+Revision 1.217  2004/11/24 17:55:01  ksekar
+Added log message clarifying <rdar://problem/3869241> For unicast operations, verify that service types are legal
+
+Revision 1.216  2004/11/24 00:10:44  cheshire
+<rdar://problem/3869241> For unicast operations, verify that service types are legal
+
+Revision 1.215  2004/11/23 22:33:01  cheshire
+<rdar://problem/3654910> Remove temporary workaround code for iChat
+
+Revision 1.214  2004/11/23 22:13:59  cheshire
+<rdar://problem/3886293> Subtype advertising broken for Mach API
+
+Revision 1.213  2004/11/23 06:12:55  cheshire
+<rdar://problem/3871405> Update wording for name conflict dialogs
+
+Revision 1.212  2004/11/23 05:15:37  cheshire
+<rdar://problem/3875830> Computer Name in use message garbled
+
+Revision 1.211  2004/11/23 05:00:41  cheshire
+<rdar://problem/3874629> Name conflict log message should not have ".local" appended
+
+Revision 1.210  2004/11/03 03:45:17  cheshire
+<rdar://problem/3863627> mDNSResponder does not inform user of Computer Name collisions
+
+Revision 1.209  2004/11/03 02:25:50  cheshire
+<rdar://problem/3324137> Conflict for Computer Name should update *all* empty string services, not just the one with the conflict
+
+Revision 1.208  2004/11/03 01:54:14  cheshire
+Update debugging messages
+
+Revision 1.207  2004/11/02 23:58:19  cheshire
+<rdar://problem/2974905> mDNSResponder does not inform user of name collisions
+
+Revision 1.206  2004/10/28 02:40:47  cheshire
+Add log message to confirm receipt of SIGUSR1 (simulate network configuration change event)
+
+Revision 1.205  2004/10/28 02:21:01  cheshire
+<rdar://problem/3856500> Improve mDNSResponder signal handling
+Added SIGHUP as a way to do a forced restart of the daemon (better than kill -9)
+Added SIGUSR1 to simulate a network change notification from System Configuration Framework
+
+Revision 1.204  2004/10/27 01:57:21  cheshire
+Add check of  m->p->InterfaceList
+
+Revision 1.203  2004/10/26 04:31:44  cheshire
+Rename CountSubTypes() as ChopSubTypes()
+
+Revision 1.202  2004/10/26 01:29:18  cheshire
+Use "#if 0" instead of commenting out code
+
+Revision 1.201  2004/10/25 21:41:39  ksekar
+<rdar://problem/3852958> wide-area name conflicts can cause crash
+
+Revision 1.200  2004/10/22 01:03:55  cheshire
+<rdar://problem/3375328> select() says data is waiting; recvfrom() says there is no data
+Log error message if attempt to remap stdin/stdout/stderr to /dev/null fails
+
+Revision 1.199  2004/10/19 21:33:19  cheshire
+<rdar://problem/3844991> Cannot resolve non-local registrations using the mach API
+Added flag 'kDNSServiceFlagsForceMulticast'. Passing through an interface id for a unicast name
+doesn't force multicast unless you set this flag to indicate explicitly that this is what you want
+
+Revision 1.198  2004/10/15 23:00:18  ksekar
+<rdar://problem/3799242> Need to update LLQs on location changes
+
+Revision 1.197  2004/10/12 23:38:59  ksekar
+<rdar://problem/3837065> remove unnecessary log message
+
+Revision 1.196  2004/10/04 05:56:04  cheshire
+<rdar://problem/3824730> mDNSResponder doesn't respond to certain AirPort changes
+
+Revision 1.195  2004/09/30 00:24:59  ksekar
+<rdar://problem/3695802> Dynamically update default registration domains on config change
+
+Revision 1.194  2004/09/26 23:20:35  ksekar
+<rdar://problem/3813108> Allow default registrations in multiple wide-area domains
+
+Revision 1.193  2004/09/23 23:35:27  cheshire
+Update error message
+
+Revision 1.192  2004/09/21 23:40:12  ksekar
+<rdar://problem/3810349> mDNSResponder to return errors on NAT traversal failure
+
+Revision 1.191  2004/09/21 21:05:12  cheshire
+Move duplicate code out of mDNSMacOSX/daemon.c and mDNSPosix/PosixDaemon.c,
+into mDNSShared/uds_daemon.c
+
+Revision 1.190  2004/09/21 19:51:15  cheshire
+Move "Starting time value" message from mDNS.c to mDNSMacOSX/daemon.c
+
+Revision 1.189  2004/09/21 18:17:23  cheshire
+<rdar://problem/3785400> Add version info to mDNSResponder
+
+Revision 1.188  2004/09/20 21:45:27  ksekar
+Mach IPC cleanup
+
+Revision 1.187  2004/09/17 01:08:52  cheshire
+Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
+  The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
+  declared in that file are ONLY appropriate to single-address-space embedded applications.
+  For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
+
+Revision 1.186  2004/09/16 00:24:49  cheshire
+<rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
+
+Revision 1.185  2004/08/25 02:01:45  cheshire
+<rdar://problem/3774777> Need to be able to get status of Dynamic DNS Host Name Update
+
+Revision 1.184  2004/08/19 19:04:12  ksekar
+<rdar://problem/3767546>: mDNSResponder crashes when adding a record to a service
+
+Revision 1.183  2004/08/14 03:22:42  cheshire
+<rdar://problem/3762579> Dynamic DNS UI <-> mDNSResponder glue
+Add GetUserSpecifiedDDNSName() routine
+Convert ServiceRegDomain to domainname instead of C string
+Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs
+
+Revision 1.182  2004/08/13 23:57:59  cheshire
+Get rid of non-portable "_UNUSED"
+
+Revision 1.181  2004/08/11 02:02:26  cheshire
+Remove "mDNS *globalInstance" parameter from udsserver_init();
+Move CheckForDuplicateRegistrations to uds_daemon.c
+
+Revision 1.180  2004/07/13 21:24:25  rpantos
+Fix for <rdar://problem/3701120>.
+
+Revision 1.179  2004/06/19 00:02:54  cheshire
+Restore fix for <rdar://problem/3548256> Should not allow empty string for resolve domain
+
+Revision 1.178  2004/06/18 19:10:00  cheshire
+<rdar://problem/3588761> Current method of doing subtypes causes name collisions
+
+Revision 1.177  2004/06/16 23:14:46  ksekar
+<rdar://problem/3693816> Remove fix for <rdar://problem/3548256> Should not allow empty string for resolve domain
+
+Revision 1.176  2004/06/11 20:27:42  cheshire
+Rename "SocketRef" as "cfs" to avoid conflict with other plaforms
+
 Revision 1.175  2004/06/10 20:23:21  cheshire
 Also list interfaces in SIGINFO output
 
@@ -77,7 +246,7 @@ Unified list copy/free code.  Added symetric list for
 
 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"
+from mDNSMacOSX.h to mDNSEmbeddedAPI.h), impelemted to return "local"
 only on non-OSX platforms.  Changed call to return a copy of the list
 to avoid shared memory issues.  Added a routine to free the list.
 
@@ -251,10 +420,10 @@ standard error file descriptors to /dev/null just like any other
 well behaved daemon
 
 Revision 1.112  2003/06/25 23:42:19  ksekar
-<rdar://problem/3249292>: Feature: New Rendezvous APIs (#7875)
+<rdar://problem/3249292>: Feature: New DNS-SD 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.
+DNS-SD APIs, and integrated with existing Mach-port based daemon.
 
 Revision 1.111  2003/06/11 01:02:43  cheshire
 <rdar://problem/3287858> mDNSResponder binary compatibility
@@ -336,11 +505,12 @@ Add $Log header
 #include <paths.h>
 #include <fcntl.h>
 #include <pwd.h>
+#include <SystemConfiguration/SCPreferencesSetSpecific.h>
 
 #include "DNSServiceDiscoveryRequestServer.h"
 #include "DNSServiceDiscoveryReply.h"
 
-#include "mDNSClientAPI.h"			// Defines the interface to the client layer above
+#include "mDNSEmbeddedAPI.h"			// Defines the interface to the client layer above
 #include "mDNSMacOSX.h"				// Defines the specific types needed to run mDNS on this platform
 
 #include "uds_daemon.h"				// Interface to the server side implementation of dns_sd.h
@@ -355,26 +525,21 @@ Add $Log header
 // Note: The C preprocessor stringify operator ('#') makes a string from its argument, without macro expansion
 // e.g. If "version" is #define'd to be "4", then STRINGIFY_AWE(version) will return the string "version", not "4"
 // To expand "version" to its value before making the string, use STRINGIFY(version) instead
-#define STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s) #s 
+#define STRINGIFY_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 kmDNSBootstrapName[] = "com.apple.mDNSResponderRestart";
 static mach_port_t client_death_port = MACH_PORT_NULL;
-static mach_port_t exit_m_port       = MACH_PORT_NULL;
-static mach_port_t info_m_port       = MACH_PORT_NULL;
+static mach_port_t signal_port       = MACH_PORT_NULL;
 static mach_port_t server_priv_port  = MACH_PORT_NULL;
 
 // mDNS Mach Message Timeout, in milliseconds.
@@ -411,17 +576,20 @@ typedef struct DNSServiceBrowser_struct DNSServiceBrowser;
 
 typedef struct DNSServiceBrowserQuestion
 	{
-    struct DNSServiceBrowserQuestion *next;
-    DNSQuestion q;
+	struct DNSServiceBrowserQuestion *next;
+	DNSQuestion q;
+    domainname domain;
 	} DNSServiceBrowserQuestion;
 
 struct DNSServiceBrowser_struct
 	{
 	DNSServiceBrowser *next;
 	mach_port_t ClientMachPort;
-    DNSServiceBrowserQuestion *qlist;
+	DNSServiceBrowserQuestion *qlist;
 	DNSServiceBrowserResult *results;
 	mDNSs32 lastsuccess;
+    mDNSBool DefaultDomain;                // was the browse started on an explicit domain?
+    domainname type;                       //  registration type 
 	};
 
 typedef struct DNSServiceResolver_struct DNSServiceResolver;
@@ -434,33 +602,41 @@ struct DNSServiceResolver_struct
 	mDNSs32          ReportTime;
 	};
 
-
-typedef struct ExtraRecordRef
+// A single registered service: ServiceRecordSet + bookkeeping
+// Note that we duplicate some fields from parent DNSServiceRegistration object
+// to facilitate cleanup, when instances and parent may be deallocated at different times.
+typedef struct ServiceInstance
 	{
-    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;
+    struct ServiceInstance *next;
 	mach_port_t ClientMachPort;
-	mDNSBool autoname;
-	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;
-    ExtraRecordRef   *ExtraRefList;
-    ServiceRecordSet *gs; // default "global" (wide area) service (may be NULL)
-    ServiceRecordSet ls;  // .local service (also used if client passes an explicit domain)
+    mDNSBool autoname;			// Set if this name is tied to the Computer Name
+    mDNSBool autorename;		// Set if we just got a name conflict and now need to automatically pick a new name
+    domainlabel name;
+    domainname domain;
+    ServiceRecordSet srs;
 	// Don't add any fields after ServiceRecordSet.
 	// This is where the implicit extra space goes if we allocate an oversized ServiceRecordSet object
-	};
+	} ServiceInstance;
+
+// A client-created service.  May reference several ServiceInstance objects if default
+// settings cause registration in multiple domains.
+typedef struct DNSServiceRegistration
+	{
+    struct DNSServiceRegistration *next;
+	mach_port_t ClientMachPort;
+    mDNSBool DefaultDomain;
+    mDNSBool autoname;
+    size_t rdsize;
+    int NumSubTypes;
+    char regtype[MAX_ESCAPED_DOMAIN_NAME]; // for use in AllocateSubtypes
+    domainlabel name;  // used only if autoname is false 
+    domainname type;
+    mDNSIPPort port;
+    unsigned char txtinfo[1024];
+    size_t txt_len;
+    uint32_t NextRef;
+    ServiceInstance *regs;
+	} DNSServiceRegistration;
 
 static DNSServiceDomainEnumeration *DNSServiceDomainEnumerationList = NULL;
 static DNSServiceBrowser           *DNSServiceBrowserList           = NULL;
@@ -484,7 +660,8 @@ static void validatelists(mDNS *const m)
 	CacheRecord                 *cr;
 	DNSQuestion                 *q;
 	mDNSu32 slot;
-	
+	NetworkInterfaceInfoOSX     *i;
+
 	for (e = DNSServiceDomainEnumerationList; e; e=e->next)
 		if (e->ClientMachPort == 0 || e->ClientMachPort == (mach_port_t)~0)
 			LogMsg("!!!! DNSServiceDomainEnumerationList: %p is garbage (%X) !!!!", e, e->ClientMachPort);
@@ -514,9 +691,13 @@ static void validatelists(mDNS *const m)
 			LogMsg("!!!! Questions list: %p is garbage (%lX) !!!!", q, q->ThisQInterval);
 
 	for (slot = 0; slot < CACHE_HASH_SLOTS; slot++)
-		for (cr = mDNSStorage.rrcache_hash[slot]; cr; cr=cr->next)
+		for (cr = m->rrcache_hash[slot]; cr; cr=cr->next)
 			if (cr->resrec.RecordType == 0 || cr->resrec.RecordType == 0xFF)
 				LogMsg("!!!! Cache slot %lu: %p is garbage (%X) !!!!", slot, rr, rr->resrec.RecordType);
+
+	for (i = m->p->InterfaceList; i; i = i->next)
+		if (!i->ifa_name)
+			LogMsg("!!!! InterfaceList: %p is garbage !!!!", i);
 	}
 
 void *mallocL(char *msg, unsigned int size)
@@ -525,7 +706,7 @@ void *mallocL(char *msg, unsigned int size)
 	if (!mem)
 		{
 		LogMsg("malloc( %s : %d ) failed", msg, size);
-		return(NULL); 
+		return(NULL);
 		}
 	else
 		{
@@ -563,46 +744,26 @@ void freeL(char *msg, void *x)
 //*************************************************************************************************************
 // Client Death Detection
 
-mDNSlocal void FreeSRS(ServiceRecordSet *s)
+mDNSlocal void FreeServiceInstance(ServiceInstance *x)
 	{
-	while (s->Extras)
+	ServiceRecordSet *s = &x->srs;
+	ExtraResourceRecord *e = x->srs.Extras, *tmp;
+	
+	while(e)
 		{
-		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);
+		e->r.RecordContext = e;
+		tmp = e;
+		e = e->next;
+		FreeExtraRR(&mDNSStorage, &tmp->r, mStatus_MemFree);
 		}
-
+	
 	if (s->RR_TXT.resrec.rdata != &s->RR_TXT.rdatastorage)
 			freeL("TXT RData", s->RR_TXT.resrec.rdata);
 
-	if (s->SubTypes) freeL("ServiceSubTypes", s->SubTypes);	
+	if (s->SubTypes) freeL("ServiceSubTypes", s->SubTypes);
+	freeL("ServiceInstance", x);
 	}
 
-mDNSlocal void FreeDNSServiceRegistration(ServiceRecordSet *srs)
-	{
-	DNSServiceRegistration *x = srs->ServiceContext;
-	ExtraRecordRef *ref, *fptr;
-	
-	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
@@ -631,7 +792,7 @@ 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;
 		while (qptr)
@@ -641,7 +802,7 @@ mDNSlocal void AbortClient(mach_port_t ClientMachPort, void *m)
 			else LogOperation("%5d: DNSServiceBrowser(%##s) STOP", ClientMachPort, qptr->q.qname.c);
 			mDNS_StopBrowse(&mDNSStorage, &qptr->q);
 			freePtr = qptr;
-			qptr = qptr->next;			
+			qptr = qptr->next;
 			freeL("DNSServiceBrowserQuestion", freePtr);
 			}
 		while (x->results)
@@ -670,32 +831,27 @@ mDNSlocal void AbortClient(mach_port_t ClientMachPort, void *m)
 	while (*r && (*r)->ClientMachPort != ClientMachPort) r = &(*r)->next;
 	if (*r)
 		{
+		ServiceInstance *si = NULL;
 		DNSServiceRegistration *x = *r;
 		*r = (*r)->next;
-		x->autorenameLS = mDNSfalse;
-		x->autorenameGS = mDNSfalse;
-		if (m && m != x)
-			{
-			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 (x->gs && mDNS_DeregisterService(&mDNSStorage, x->gs))
+
+		si = x->regs;
+		while (si)
 			{
-			// Deregister returned an error, so we free immediately
-			FreeSRS(x->gs);
-			x->gs = NULL;
+			ServiceInstance *instance = si;
+			si = si->next;                 
+			instance->autorename = mDNSfalse;
+			if (m && m != x) LogMsg("%5d: DNSServiceRegistration(%##s, %u) STOP; WARNING m %p != x %p", ClientMachPort, instance->srs.RR_SRV.resrec.name.c, SRS_PORT(&instance->srs), m, x);			
+			else LogOperation("%5d: DNSServiceRegistration(%##s, %u) STOP", ClientMachPort, instance->srs.RR_SRV.resrec.name.c, SRS_PORT(&instance->srs));
+
+			// If mDNS_DeregisterService() returns mStatus_NoError, that means that the service was found in the list,
+			// 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, &instance->srs)) FreeServiceInstance(instance); // FreeServiceInstance invalidates pointer
 			}
-		if (mDNS_DeregisterService(&mDNSStorage, &x->ls))
-			FreeDNSServiceRegistration(&x->ls);
+		x->regs = NULL;		
+		freeL("DNSServiceRegistration", x);
 		return;
 		}
 
@@ -725,8 +881,8 @@ mDNSlocal void AbortClientWithLogMessage(mach_port_t c, char *reason, char *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);
+		ServiceInstance *si;
+		for (si = r->regs; si; si = si->next) LogMsg("%5d: Registration(%##s) %s%s", c, si->srs.RR_SRV.resrec.name.c, reason, msg);
 		}
 	else            LogMsg("%5d: (%s) %s, but no record of client can be found!", c,                            reason, msg);
 
@@ -740,7 +896,7 @@ mDNSlocal mDNSBool CheckForExistingClient(mach_port_t c)
 	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;
@@ -752,7 +908,7 @@ mDNSlocal mDNSBool CheckForExistingClient(mach_port_t c)
 			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->ls.RR_SRV.resrec.name.c);
+	if (r) LogMsg("%5d: Registration(%##s) already exists!",      c, r->regs ? r->regs->srs.RR_SRV.resrec.name.c : NULL);
 	return(e || b || l || r);
 	}
 
@@ -841,7 +997,7 @@ mDNSexport kern_return_t provide_DNSServiceDomainEnumerationCreate_rpc(mach_port
 	x->ClientMachPort = client;
 	x->next = DNSServiceDomainEnumerationList;
 	DNSServiceDomainEnumerationList = x;
-	
+
 	// Generate initial response
 	verbosedebugf("%5d: Enumerate %s Domains", client, regDom ? "Registration" : "Browsing");
 	// We always give local. as the initial default browse domain, and then look for more
@@ -853,7 +1009,7 @@ mDNSexport kern_return_t provide_DNSServiceDomainEnumerationCreate_rpc(mach_port
 	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
 	LogOperation("%5d: DNSServiceDomainEnumeration(%##s) START", client, x->dom.qname.c);
 	EnableDeathNotificationForClient(client, x);
@@ -870,10 +1026,10 @@ fail:
 mDNSlocal void FoundInstance(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
 	{
 	(void)m;		// Unused
-	
+
 	if (answer->rrtype != kDNSType_PTR)
 		{ LogMsg("FoundInstance: Should not be called with rrtype %d (not a PTR record)", answer->rrtype); return; }
-	
+
 	domainlabel name;
 	domainname type, domain;
 	if (!DeconstructServiceName(&answer->rdata->u.name, &name, &type, &domain))
@@ -885,7 +1041,7 @@ mDNSlocal void FoundInstance(mDNS *const m, DNSQuestion *question, const Resourc
 
 	DNSServiceBrowserResult *x = mallocL("DNSServiceBrowserResult", sizeof(*x));
 	if (!x) { LogMsg("FoundInstance: Failed to allocate memory for result %##s", answer->rdata->u.name.c); return; }
-	
+
 	verbosedebugf("FoundInstance: %s %##s", AddRecord ? "Add" : "Rmv", answer->rdata->u.name.c);
 	AssignDomainName(x->result, answer->rdata->u.name);
 	if (AddRecord)
@@ -899,6 +1055,72 @@ mDNSlocal void FoundInstance(mDNS *const m, DNSQuestion *question, const Resourc
 	*p = x;
 	}
 
+mDNSlocal mStatus AddDomainToBrowser(DNSServiceBrowser *browser, const domainname *d)
+	{
+	mStatus err = mStatus_NoError;
+	DNSServiceBrowserQuestion *ptr, *question = NULL;
+
+	for (ptr = browser->qlist; ptr; ptr = ptr->next)
+		{
+		if (SameDomainName(&ptr->q.qname, d))
+			{ debugf("Domain %##s already contained in browser", d->c); return mStatus_AlreadyRegistered; }
+		}
+	
+	question = mallocL("DNSServiceBrowserQuestion", sizeof(DNSServiceBrowserQuestion));
+	if (!question) { LogMsg("Error: malloc"); return mStatus_NoMemoryErr; }
+	AssignDomainName(question->domain, *d);
+	question->next = browser->qlist;
+	browser->qlist = question;
+	LogOperation("%5d: DNSServiceBrowse(%##s%##s) START", browser->ClientMachPort, browser->type.c, d->c);
+	err = mDNS_StartBrowse(&mDNSStorage, &question->q, &browser->type, d, mDNSInterface_Any, mDNSfalse, FoundInstance, browser);
+	if (err) LogMsg("Error: AddDomainToBrowser: mDNS_StartBrowse %d", err);
+	return err;
+	}
+
+mDNSexport void DefaultBrowseDomainChanged(const domainname *d, mDNSBool add)
+	{
+	DNSServiceBrowser *ptr;
+
+	debugf("%s default browse domain %##s", add ? "Adding" : "Removing", d->c);
+	for (ptr = DNSServiceBrowserList; ptr; ptr = ptr->next)
+		{
+		if (ptr->DefaultDomain)
+			{
+			if (add)
+				{
+				mStatus err = AddDomainToBrowser(ptr, d);
+				if (err && err != mStatus_AlreadyRegistered) LogMsg("Default browse in domain %##s for client %5d failed. Continuing", d, ptr->ClientMachPort);
+				}
+			else
+				{
+#if 0
+				/*
+				 * By cancelling the browse immediately, we may lose remove events.
+				 * Instead, we allow the browse to run.  If our previous results are no longer valid (e.g. because we
+				 * moved out from behind a firewall) we will get remove events for those names.
+				 */
+				 // find the question for this domain
+				 DNSServiceBrowserQuestion *q = ptr->qlist, *prev = NULL;
+				 while (q)
+					 {
+					 if (SameDomainName(&q->domain, d))
+						 {
+						 if (prev) prev->next = q->next;
+						 else ptr->qlist = q->next;
+						 mDNS_StopBrowse(&mDNSStorage, &q->q);
+						 freeL("DNSServiceBrowserQuestion", q);
+						 break;
+						 }
+					 prev = q;
+					 q = q->next;
+					 }
+				 if (!q) LogMsg("Requested removal of default domain %##s not in client %5d's list", d->c, ptr->ClientMachPort);
+#endif
+                 }			
+			}
+		}
+	}
+
 mDNSexport kern_return_t provide_DNSServiceBrowserCreate_rpc(mach_port_t unusedserver, mach_port_t client,
 	DNSCString regtype, DNSCString domain)
 	{
@@ -907,76 +1129,79 @@ mDNSexport kern_return_t provide_DNSServiceBrowserCreate_rpc(mach_port_t unuseds
 	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;
-	if (!regtype[0] || !MakeDomainNameFromDNSNameString(&t, regtype))      { errormsg = "Illegal regtype"; goto badparam; }
+	t.c[0] = 0;
+	mDNSs32 NumSubTypes = ChopSubTypes(regtype);	// Note: Modifies regtype string to remove trailing subtypes
+	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; }
+	domainname temp;
+	if (!MakeDomainNameFromDNSNameString(&temp, regtype)) { errormsg = "Illegal regtype";     goto badparam; }
+	if (temp.c[0] > 15 && (!domain || domain[0] == 0)) domain = "local."; // For over-long service types, we only allow domain "local"
 
 	// 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
+	AssignDomainName(x->type, t);
 	x->ClientMachPort = client;
 	x->results = NULL;
 	x->lastsuccess = 0;
-	x->qlist = NULL;	
+	x->qlist = NULL;
 	x->next = DNSServiceBrowserList;
 	DNSServiceBrowserList = x;
 
-	//!!!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; }
+		x->DefaultDomain = mDNSfalse;
+		if (!MakeDomainNameFromDNSNameString(&d, domain)) { errormsg = "Illegal domain";  goto badparam; }		
+		err = AddDomainToBrowser(x, &d);
+		if (err) { AbortClient(client, x); errormsg = "AddDomainToBrowser"; goto fail; }
 		}
 	else
 		{
 		// Start browser on all domains
+		x->DefaultDomain = mDNStrue;
 		SearchDomains = mDNSPlatformGetSearchDomainList();
 		if (!SearchDomains) { AbortClient(client, x); errormsg = "GetSearchDomainList"; goto fail; }
 		for (sdPtr = SearchDomains; sdPtr; sdPtr = sdPtr->next)
 			{
-			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; }			
-			}		
+			err = AddDomainToBrowser(x, &sdPtr->name);
+			if (err)
+				{
+				// only terminally bail if .local fails
+				if (!SameDomainName(&localdomain, &sdPtr->name))
+					LogMsg("Default browse in domain %##s failed. Continuing", sdPtr->name.c);
+				else { AbortClient(client, x); errormsg = "AddDomainToBrowser"; goto fail; }
+				}
+			}
 		}
+	
 	// Succeeded: Wrap up and return
 	EnableDeathNotificationForClient(client, x);
 	mDNS_FreeDNameList(SearchDomains);
 	return(mStatus_NoError);
-	
+
 	badparam:
 	err = mStatus_BadParamErr;
 fail:
 	LogMsg("%5d: DNSServiceBrowse(\"%s\", \"%s\") failed: %s (%ld)", client, regtype, domain, errormsg, err);
 	if (SearchDomains) mDNS_FreeDNameList(SearchDomains);
 	return(err);
-	}
+		}
 
 //*************************************************************************************************************
 // Resolve Service Info
-
-mDNSlocal void FoundInstanceInfo(mDNS *const m, ServiceInfoQuery *query)
+	
+	mDNSlocal void FoundInstanceInfo(mDNS *const m, ServiceInfoQuery *query)
 	{
 	kern_return_t status;
 	DNSServiceResolver *x = (DNSServiceResolver *)query->ServiceInfoQueryContext;
@@ -1013,7 +1238,7 @@ mDNSlocal void FoundInstanceInfo(mDNS *const m, ServiceInfoQuery *query)
 		sin6->sin6_addr		 = *(struct in6_addr*)&ifx->ifinfo.ip.ip.v6;
 		sin6->sin6_scope_id  = ifx->scope_id;
 		}
-	
+
 	if (query->info->ip.type == mDNSAddrType_IPv4)
 		{
 		struct sockaddr_in *sin = (struct sockaddr_in*)&address;
@@ -1049,7 +1274,7 @@ mDNSlocal void FoundInstanceInfo(mDNS *const m, ServiceInfoQuery *query)
 			}
 		}
 	cstring[i-1] = 0;		// Put the terminating NULL on the end
-	
+
 	LogOperation("%5d: DNSServiceResolver(%##s) -> %#a:%u", x->ClientMachPort,
 		x->i.name.c, &query->info->ip, mDNSVal16(query->info->port));
 	status = DNSServiceResolverReply_rpc(x->ClientMachPort,
@@ -1084,11 +1309,7 @@ mDNSexport kern_return_t provide_DNSServiceResolverResolve_rpc(mach_port_t unuse
 	x->ClientMachPort = client;
 	x->i.InterfaceID = mDNSInterface_Any;
 	x->i.name = srv;
-	x->ReportTime = (mDNSPlatformTimeNow() + 130 * mDNSPlatformOneSecond) | 1;
-	// Don't report errors for old iChat ("_ichat._tcp") service.
-	// New iChat ("_presence._tcp") uses DNSServiceQueryRecord() (from /usr/include/dns_sd.h) instead,
-	// and so should other applications that have valid reasons to be doing ongoing record monitoring.
-	if (SameDomainLabel(t.c, (mDNSu8*)"\x6_ichat")) x->ReportTime = 0;
+	x->ReportTime = NonZeroTime(mDNS_TimeNow(&mDNSStorage) + 130 * mDNSPlatformOneSecond);
 	x->next = DNSServiceResolverList;
 	DNSServiceResolverList = x;
 
@@ -1101,7 +1322,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);
@@ -1111,113 +1332,186 @@ fail:
 //*************************************************************************************************************
 // Registration
 
-mDNSlocal void RegCallback(mDNS *const m, ServiceRecordSet *const sr, mStatus result)
+mDNSexport void RecordUpdatedNiceLabel(mDNS *const m, mDNSs32 delay)
+	{
+	m->p->NotifyUser = NonZeroTime(m->timenow + delay);
+	}
+
+mDNSlocal void RegCallback(mDNS *const m, ServiceRecordSet *const srs, mStatus result)
 	{
-	DNSServiceRegistration *x = (DNSServiceRegistration*)sr->ServiceContext;
+	ServiceInstance *si = (ServiceInstance*)srs->ServiceContext;
 
 	if (result == mStatus_NoError)
 		{
 		kern_return_t status;
-		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);
+		LogOperation("%5d: DNSServiceRegistration(%##s, %u) Name Registered", si->ClientMachPort, srs->RR_SRV.resrec.name.c, SRS_PORT(srs));
+		status = DNSServiceRegistrationReply_rpc(si->ClientMachPort, result, MDNS_MM_TIMEOUT);
 		if (status == MACH_SEND_TIMED_OUT)
-			AbortBlockedClient(x->ClientMachPort, "registration success", x);
+			AbortBlockedClient(si->ClientMachPort, "registration success", si);
+		if (si->autoname && CountPeerRegistrations(m, srs) == 0)
+			RecordUpdatedNiceLabel(m, 0);	// Successfully got new name, tell user immediately
 		}
 
 	else if (result == mStatus_NameConflict)
 		{
-		LogOperation("%5d: DNSServiceRegistration(%##s, %u) Name Conflict", x->ClientMachPort, sr->RR_SRV.resrec.name.c, SRS_PORT(sr));
+		LogOperation("%5d: DNSServiceRegistration(%##s, %u) Name Conflict", si->ClientMachPort, srs->RR_SRV.resrec.name.c, SRS_PORT(srs));
 		// 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)
-			mDNS_RenameAndReregisterService(m, sr, mDNSNULL);
+		if (si->autoname && CountPeerRegistrations(m, srs) == 0)
+			{
+			// On conflict for an autoname service, rename and reregister *all* autoname services
+			IncrementLabelSuffix(&m->nicelabel, mDNStrue);
+			m->MainCallback(m, mStatus_ConfigChanged);
+			}
+		else if (si->autoname)
+			{
+            mDNS_RenameAndReregisterService(m, srs, mDNSNULL);
+            return;
+			}
 		else
 			{
 			// If we get a name conflict, we tell the client about it, and then they are expected to dispose
 			// of their registration in the usual way (which we will catch via client death notification).
 			// If the Mach queue is full, we forcibly abort the client immediately.
-			kern_return_t status = DNSServiceRegistrationReply_rpc(x->ClientMachPort, result, MDNS_MM_TIMEOUT);
+			kern_return_t status = DNSServiceRegistrationReply_rpc(si->ClientMachPort, result, MDNS_MM_TIMEOUT);
 			if (status == MACH_SEND_TIMED_OUT)
-				AbortBlockedClient(x->ClientMachPort, "registration conflict", x);
+				AbortBlockedClient(si->ClientMachPort, "registration conflict", NULL);
 			}
 		}
-	
+
 	else if (result == mStatus_MemFree)
 		{
-		mDNSBool *autorename = (sr == &x->ls ? &x->autorenameLS : &x->autorenameGS); 
-		if (*autorename)
+		if (si->autorename)
 			{
-			debugf("RegCallback renaming %#s to %#s", x->name.c, mDNSStorage.nicelabel.c);
-			*autorename = mDNSfalse;
-			x->name = mDNSStorage.nicelabel;
-			mDNS_RenameAndReregisterService(m, sr, &x->name);
+			debugf("RegCallback renaming %#s to %#s", si->name.c, m->nicelabel.c);
+			si->autorename = mDNSfalse;
+			si->name = m->nicelabel;
+			mDNS_RenameAndReregisterService(m, srs, &si->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)
+			// SANITY CHECK: make sure service instance is no longer in any ServiceRegistration's list
+			DNSServiceRegistration *r;
+			for (r = DNSServiceRegistrationList; r; r = r->next)
 				{
-				LogMsg("RegCallback: %##s Still in DNSServiceRegistration list; removing now", sr->RR_SRV.resrec.name.c);
-				*r = (*r)->next;
-				}
+				ServiceInstance *sp = r->regs, *prev = NULL;
+				while (sp)
+					{
+					if (sp == si)
+						{				  
+						LogMsg("RegCallback: %##s Still in DNSServiceRegistration list; removing now", srs->RR_SRV.resrec.name.c);			    
+						if (prev) prev->next = sp->next;
+						else r->regs = sp->next;
+						break;
+						}
+					prev = sp;
+					sp = sp->next;
+					}
+			    }
 			// END SANITY CHECK
-			LogOperation("%5d: DNSServiceRegistration(%##s, %u) Memory Free", x->ClientMachPort, sr->RR_SRV.resrec.name.c, SRS_PORT(sr));
-			FreeDNSServiceRegistration(sr);
+			FreeServiceInstance(si);
 			}
 		}
+
+	else if (result != mStatus_NATTraversal)
+		LogMsg("%5d: DNSServiceRegistration(%##s, %u) Unknown Result %ld", si->ClientMachPort, srs->RR_SRV.resrec.name.c, SRS_PORT(srs), result);
+	}
+
+mDNSlocal mStatus AddServiceInstance(DNSServiceRegistration *x, const domainname *domain)
+	{
+	mStatus err = 0;
+	ServiceInstance *si = NULL;
+	AuthRecord *SubTypes = NULL;
+
+	for (si = x->regs; si; si = si->next)
+		{
+		if (SameDomainName(&si->domain, domain))
+			{ LogMsg("Requested addition of domain %##s already in list", domain->c); return mStatus_AlreadyRegistered; }
+		}
 	
+	SubTypes = AllocateSubTypes(x->NumSubTypes, x->regtype);
+	if (x->NumSubTypes && !SubTypes) return mStatus_NoMemoryErr;
+	
+	si = mallocL("ServiceInstance", sizeof(*si) - sizeof(RDataBody) + x->rdsize);
+	if (!si) return mStatus_NoMemoryErr;
+
+	si->ClientMachPort = x->ClientMachPort;
+	si->autorename = mDNSfalse;
+	si->autoname = x->autoname;
+	si->name = x->autoname ? mDNSStorage.nicelabel : x->name;
+	si->domain = *domain;
+
+	err = mDNS_RegisterService(&mDNSStorage, &si->srs, &si->name, &x->type, domain, NULL, x->port, x->txtinfo, x->txt_len, SubTypes, x->NumSubTypes, mDNSInterface_Any, RegCallback, si);
+	if (!err)
+		{
+		si->next = x->regs;
+		x->regs = si;
+		}
 	else
 		{
-		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; }
+		LogMsg("Error %d for registration of service in domain %##s", err, domain->c);
+		freeL("ServiceInstance", si);
 		}
+	return err;	
 	}
 
-mDNSlocal void CheckForDuplicateRegistrations(DNSServiceRegistration *x, domainname *srv, mDNSIPPort port)
+mDNSexport void DefaultRegDomainChanged(const domainname *d, mDNSBool add)
 	{
-	int count = 1;			// Start with the one we're planning to register, then see if there are any more
-	AuthRecord *rr;
-	for (rr = mDNSStorage.ResourceRecords; rr; rr=rr->next)
-		if (rr->resrec.rrtype == kDNSType_SRV &&
-			rr->resrec.rdata->u.srv.port.NotAnInteger == port.NotAnInteger &&
-			SameDomainName(&rr->resrec.name, srv))
-			count++;
-
-	if (count > 1)
-		LogMsg("%5d: Client application registered %d identical instances of service %##s port %u.",
-			x->ClientMachPort, count, srv->c, mDNSVal16(port));
+	DNSServiceRegistration *reg;
+
+	LogMsg("%s default registration domain %##s", add ? "Adding" : "Removing", d->c);
+	for (reg = DNSServiceRegistrationList; reg; reg = reg->next)
+		{
+		if (reg->DefaultDomain)
+			{
+			if (add)
+				{
+				AddServiceInstance(reg, d);
+				}
+			else
+				{
+				ServiceInstance *si = reg->regs, *prev = NULL;
+				while (si)
+					{
+					if (SameDomainName(&si->domain, d))
+						{
+						if (prev) prev->next = si->next;
+						else reg->regs = si->next;
+						if (mDNS_DeregisterService(&mDNSStorage, &si->srs))
+							FreeServiceInstance(si);  // only free memory synchronously on error
+						break;
+						}
+					prev = si;
+					si = si->next;
+					}
+				if (!si) LogMsg("Requested removal of default domain %##s not in client %5d's list", d, reg->ClientMachPort);
+				}					
+			}
+		}
 	}
 
-// 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)
+mDNSexport kern_return_t provide_DNSServiceRegistrationCreate_rpc(mach_port_t unusedserver, mach_port_t client,
+	DNSCString name, DNSCString regtype, DNSCString domain, IPPort IpPort, DNSCString txtRecord)
 	{
-	ServiceRecordSet *srs = NULL;  // record set to use in registration operation
+	(void)unusedserver;		// Unused
 	mStatus err = mStatus_NoError;
 	const char *errormsg = "Unknown";
-	
+
+	// older versions of this code passed the port via mach IPC as an int.
+	// we continue to pass it as 4 bytes to maintain binary compatibility,
+	// but now ensure that the network byte order is preserved by using a struct
+	mDNSIPPort port;
+	port.b[0] = IpPort.bytes[2];
+	port.b[1] = IpPort.bytes[3];
+
+	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
-	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++;
-			}
-		}
+	size_t reglen = strlen(regtype) + 1;
+	if (reglen > MAX_ESCAPED_DOMAIN_NAME) { errormsg = "reglen too long"; goto badparam; }
+	mDNSs32 NumSubTypes = ChopSubTypes(regtype);	// Note: Modifies regtype string to remove trailing subtypes
+	if (NumSubTypes < 0) { errormsg = "Bad Service SubType"; goto badparam; }
 
 	// Check other parameters
 	domainlabel n;
@@ -1225,14 +1519,10 @@ mDNSlocal DNSServiceRegistration *RegisterService(mach_port_t client, DNSCString
 	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))                      { errormsg = "Bad Domain";        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 (!ConstructServiceName(&srv, &n, &t, &d))                           { errormsg = "Bad Name";          goto badparam; }
 
-	mDNSIPPort port;
-	port.NotAnInteger = notAnIntPort;
-
 	unsigned char txtinfo[1024] = "";
 	unsigned int data_len = 0;
 	unsigned int size = sizeof(RDataBody);
@@ -1264,116 +1554,148 @@ mDNSlocal DNSServiceRegistration *RegisterService(mach_port_t client, DNSCString
 	if (size < data_len)
 		size = data_len;
 
-	// Allocate memory, and handle failure
-	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
+	// 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)
 		{
-		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);
+		int count = CountExistingRegistrations(&srv, port);
+		if (count)
+			LogMsg("%5d: Client application registered %d identical instances of service %##s port %u.",
+				   client, count+1, srv.c, mDNSVal16(port));
 		}
 	
-	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
-			}
-		}
+	// Allocate memory, and handle failure
+	DNSServiceRegistration *x = mallocL("DNSServiceRegistration", sizeof(*x));
+	if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; }
+	bzero(x, sizeof(*x));
+
+	// Set up object, and link into list
+	x->ClientMachPort = client;
+	x->DefaultDomain = !domain[0];
+	x->autoname = (!name[0]);
+	x->rdsize = size;
+	x->NumSubTypes = NumSubTypes;
+	memcpy(x->regtype, regtype, reglen);
+	x->name = n;
+	x->type = t;
+	x->port = port;
+	memcpy(x->txtinfo, txtinfo, 1024);
+	x->txt_len = data_len;	
+	x->NextRef = 0;
+	x->regs = NULL;
+	
+	x->next = DNSServiceRegistrationList;
+	DNSServiceRegistrationList = x;
 
-	// Do the operation
 	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, 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
+   	err = AddServiceInstance(x, &d);
+	if (err) { AbortClient(client, x); errormsg = "mDNS_RegisterService"; goto fail; }  // bail if .local (or explicit domain) fails
 
-	if (err)
+	if (x->DefaultDomain)
 		{
-		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;
-	
+		DNameListElem *ptr, *regdomains = mDNSPlatformGetRegDomainList();
+		for (ptr = regdomains; ptr; ptr = ptr->next)
+			AddServiceInstance(x, &ptr->name);
+		mDNS_FreeDNameList(regdomains);
+		}		
+
+	// 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 NULL;
+		   client, name, regtype, domain, mDNSVal16(port), errormsg, err);
+	return(err);
 	}
 
-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)
+// This updates either the text of the field currently labelled "Local Hostname",
+// or the text of the field currently labelled "Computer Name"
+// in the Sharing Prefs Control Panel
+mDNSlocal void RecordUpdatedName(const mDNS *const m, domainlabel *n1, domainlabel *n2, char *msg, char *suffix, CFStringRef subtext)
 	{
-	// 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);
-
-fail:
-	LogMsg("%5d: DNSServiceRegister(\"%s\", \"%s\", \"%s\", %d) failed: %s (%ld)",
-		   client, name, regtype, domain, notAnIntPort, errormsg, err);
-	return mStatus_UnknownErr;
+	char oldname[MAX_DOMAIN_LABEL+1];
+	char newname[MAX_DOMAIN_LABEL+1];
+	ConvertDomainLabelToCString_unescaped(n1, oldname);
+	ConvertDomainLabelToCString_unescaped(n2, newname);
+	const CFStringRef      cfoldname = CFStringCreateWithCString(NULL, oldname,    kCFStringEncodingUTF8);
+	const CFStringRef      cfnewname = CFStringCreateWithCString(NULL, newname,    kCFStringEncodingUTF8);
+	const CFStringRef      f1        = CFStringCreateWithCString(NULL, "â%@%sâ", kCFStringEncodingUTF8);
+	const CFStringRef      f2        = CFStringCreateWithCString(NULL, "â%@%sâ", kCFStringEncodingUTF8);
+	const SCPreferencesRef session   = SCPreferencesCreate(NULL, CFSTR("mDNSResponder"), NULL);
+	*n1 = *n2;
+	if (!cfoldname || !cfnewname || !f1 || !f2 || !session || !SCPreferencesLock(session, 0))	// If we can't get the lock don't wait
+		LogMsg("RecordUpdatedName: ERROR: Couldn't create SCPreferences session");
+	else
+		{
+		const CFStringRef       s0           = CFStringCreateWithCString(NULL, msg, kCFStringEncodingUTF8);
+		const CFStringRef       s1           = CFStringCreateWithFormat(NULL, NULL, f1, cfoldname, suffix);
+		const CFStringRef       s2           = CFStringCreateWithFormat(NULL, NULL, f2, cfnewname, suffix);
+//		const CFMutableArrayRef alertMessage = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+		const CFMutableStringRef alertMessage = CFStringCreateMutable(NULL, 0);
+		Boolean result;
+		if (n2 == &m->hostlabel) result = SCPreferencesSetLocalHostName(session, cfnewname);
+		else                     result = SCPreferencesSetComputerName(session, cfnewname, kCFStringEncodingUTF8);
+		if (!result || !SCPreferencesCommitChanges(session) || !SCPreferencesApplyChanges(session) || !s0 || !s1 || !s2 || !alertMessage)
+			LogMsg("RecordUpdatedName: ERROR: Couldn't update SCPreferences");
+		else if (m->p->NotifyUser)
+			{
+//			CFArrayAppendValue(alertMessage, s0);
+			CFStringAppend(alertMessage, s0);
+			CFStringAppend(alertMessage, s1);
+			CFStringAppend(alertMessage, CFSTR(" is already in use on this network.  The name has been changed to "));
+			CFStringAppend(alertMessage, s2);
+			CFStringAppend(alertMessage, CFSTR(" automatically."));
+			CFUserNotificationDisplayNotice(60.0,			// Auto-dismiss after 60 seconds
+				kCFUserNotificationCautionAlertLevel,
+				NULL, NULL, NULL,							// iconURL, soundURL, localizationURL
+				(CFStringRef)alertMessage, subtext, NULL);	// alertHeader, alertMessage, defaultButtonTitle
+			}
+		if (s0)           CFRelease(s0);
+		if (s1)           CFRelease(s1);
+		if (s2)           CFRelease(s2);
+		if (alertMessage) CFRelease(alertMessage);
+		SCPreferencesUnlock(session);
+		}
+	if (cfoldname) CFRelease(cfoldname);
+	if (cfnewname) CFRelease(cfnewname);
+	if (f1)        CFRelease(f1);
+	if (f2)        CFRelease(f2);
+	if (session)   CFRelease(session);
 	}
-	
+
 mDNSlocal void mDNS_StatusCallback(mDNS *const m, mStatus result)
 	{
 	(void)m; // Unused
-	if (result == mStatus_ConfigChanged)
+	if (result == mStatus_NoError)	
+		{
+		// Allow three seconds in case we get a Computer Name update too -- don't want to alert the user twice
+		RecordUpdatedNiceLabel(m, mDNSPlatformOneSecond*3);
+		}
+	else if (result == mStatus_ConfigChanged)
 		{
 		DNSServiceRegistration *r;
 		for (r = DNSServiceRegistrationList; r; r=r->next)
-			if (r->autoname && !SameDomainLabel(r->name.c, mDNSStorage.nicelabel.c))
+			if (r->autoname)
 				{
-				debugf("NetworkChanged renaming %#s to %#s", r->name.c, mDNSStorage.nicelabel.c);
-				r->autorenameLS = mDNStrue;
-				mDNS_DeregisterService(&mDNSStorage, &r->ls);
-				if (r->gs) { mDNS_DeregisterService(&mDNSStorage, r->gs); r->autorenameGS = mDNStrue; }
+				ServiceInstance *si;
+				for (si = r->regs; si; si = si->next)
+					{
+					if (!SameDomainLabel(si->name.c, m->nicelabel.c))
+						{
+						debugf("NetworkChanged renaming %##s to %#s", si->srs.RR_SRV.resrec.name.c, m->nicelabel.c);
+						si->autorename = mDNStrue;
+						if (mDNS_DeregisterService(m, &si->srs))	// If service deregistered already, we can re-register immediately
+							RegCallback(m, &si->srs, mStatus_MemFree);
+						}
+					}
 				}
 		udsserver_handle_configchange();
 		}
@@ -1382,86 +1704,62 @@ mDNSlocal void mDNS_StatusCallback(mDNS *const m, mStatus result)
 		// 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 = mallocL("mStatus_GrowCache", sizeof(CacheRecord) * numrecords);
-		if (storage) mDNS_GrowCache(&mDNSStorage, storage, numrecords);
+		if (storage) mDNS_GrowCache(m, storage, numrecords);
 		}
 	}
 
 //*************************************************************************************************************
 // Add / Update / Remove records from existing Registration
 
-
-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)
-	{
-	mStatus err = mStatus_NoError;
-	const char *errormsg = "Unknown";
-	domainname *name = (domainname *)"";
-	name = &srs->RR_SRV.resrec.name;
-
-	(void)x;  // unused
-	
-	unsigned int size = sizeof(RDataBody);
-	if (size < data_len)
-		size = data_len;
-	
-	// Allocate memory, and handle failure
-	ExtraResourceRecord *extra = mallocL("ExtraResourceRecord", sizeof(*extra) - sizeof(RDataBody) + size);
-	if (!extra) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; }
-
-	// Fill in type, length, and data of new record
-	extra->r.resrec.rrtype = type;
-	extra->r.rdatastorage.MaxRDLength = size;
-	extra->r.resrec.rdlength          = data_len;
-	memcpy(&extra->r.rdatastorage.u.data, data, data_len);
-	
-	// Do the operation
-	LogOperation("%5d: DNSServiceRegistrationAddRecord(%##s, type %d, length %d) REF %p",
-		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;
-		}
-	
-	return extra;
-	
-fail:
-	LogMsg("%5d: DNSServiceRegistrationAddRecord(%##s, type %d, length %d) failed: %s (%ld)", client, name->c, type, data_len, errormsg, err);
-	return NULL;
-	}
-
-
 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
+	uint32_t id;
 	mStatus err = mStatus_NoError;
 	const char *errormsg = "Unknown";
 	if (client == (mach_port_t)-1) { err = mStatus_Invalid;         errormsg = "Client id -1 invalid"; goto fail; }
 	DNSServiceRegistration *x = DNSServiceRegistrationList;
+	ServiceInstance *si;
+	size_t size;
+	(void)unusedserver;		// Unused
 	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; }
+	if (data_len > sizeof(RDataBody)) size = data_len;
+	else size = sizeof(RDataBody);
+	
+	id = x->NextRef++;
+	*reference = (natural_t)id;
+	for (si = x->regs; si; si = si->next)
+		{			
+		// Allocate memory, and handle failure
+		ExtraResourceRecord *extra = mallocL("ExtraResourceRecord", sizeof(*extra) - sizeof(RDataBody) + size);
+		if (!extra) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; }
+		
+		// Fill in type, length, and data of new record
+		extra->r.resrec.rrtype = type;
+		extra->r.rdatastorage.MaxRDLength = size;
+		extra->r.resrec.rdlength          = data_len;
+		memcpy(&extra->r.rdatastorage.u.data, data, data_len);
+
+		// Do the operation
+		LogOperation("%5d: DNSServiceRegistrationAddRecord(%##s, type %d, length %d) REF %p",
+					 client, si->srs.RR_SRV.resrec.name.c, type, data_len, extra);
+		err = mDNS_AddRecordToService(&mDNSStorage, &si->srs, extra, &extra->r.rdatastorage, ttl);
+
+		if (err)
+			{
+			freeL("Extra Resource Record", extra);
+			errormsg = "mDNS_AddRecordToService";
+			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; }
+		extra->ClientID = id;
+		}
 
-	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:
@@ -1496,7 +1794,7 @@ mDNSlocal mStatus UpdateRecord(ServiceRecordSet *srs, mach_port_t client, AuthRe
 	// Fill in new length, and data
 	newrdata->MaxRDLength = size;
 	memcpy(&newrdata->u, data, data_len);
-	
+
 	// Do the operation
 	LogOperation("%5d: DNSServiceRegistrationUpdateRecord(%##s, new length %d)",
 		client, srs->RR_SRV.resrec.name.c, data_len);
@@ -1507,14 +1805,13 @@ mDNSlocal mStatus UpdateRecord(ServiceRecordSet *srs, mach_port_t client, AuthRe
 		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)
@@ -1523,9 +1820,9 @@ mDNSexport kern_return_t provide_DNSServiceRegistrationUpdateRecord_rpc(mach_por
 	mStatus err = mStatus_NoError;
 	const char *errormsg = "Unknown";
 	domainname *name = (domainname *)"";
-	AuthRecord *gRR, *lRR;
+	ServiceInstance *si;
 
-	(void)unusedserver;  // unused
+	(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;
@@ -1534,28 +1831,28 @@ mDNSexport kern_return_t provide_DNSServiceRegistrationUpdateRecord_rpc(mach_por
 	// 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
+	for (si = x->regs; si; si = si->next)
 		{
-		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;
+		AuthRecord *r = NULL;
 
-	if (gRR) UpdateRecord(x->gs, client, gRR, data, data_len, ttl); // don't return error if global fails
+		// Find the record we're updating. NULL reference means update the primary TXT record
+		if (!reference) r = &si->srs.RR_TXT;
+		else
+			{
+			ExtraResourceRecord *ptr;
+			for (ptr = si->srs.Extras; ptr; ptr = ptr->next)
+				{
+				if ((natural_t)ptr->ClientID == reference)
+					{ r = &ptr->r; break; }
+				}
+			if (!r) { err = mStatus_BadReferenceErr; errormsg = "No such record"; goto fail; }
+			}
+		err = UpdateRecord(&si->srs, client, r, data, data_len, ttl);
+		if (err) goto fail;  //!!!KRS this will cause failures for non-local defaults!
+		}
+					
 	return mStatus_NoError;
-	
+
 fail:
 	LogMsg("%5d: DNSServiceRegistrationUpdateRecord(%##s, %X, %d) failed: %s (%ld)", client, name->c, reference, data_len, errormsg, err);
 	return(err);
@@ -1565,23 +1862,14 @@ mDNSlocal mStatus RemoveRecord(ServiceRecordSet *srs, ExtraResourceRecord *extra
 	{
 	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: DNSServiceRegistrationRemoveRecord(%##s, %X) failed: %s", client, name->c, errormsg, err);
-	return(err);
+	err = mDNS_RemoveRecordFromService(&mDNSStorage, srs, extra, FreeExtraRR, extra);
+	if (err) LogMsg("%5d: DNSServiceRegistrationRemoveRecord (%##s) failed: %d", client, name->c, err);
+	
+	return err;
 	}
 
 mDNSexport kern_return_t provide_DNSServiceRegistrationRemoveRecord_rpc(mach_port_t unusedserver, mach_port_t client,
@@ -1591,30 +1879,28 @@ mDNSexport kern_return_t provide_DNSServiceRegistrationRemoveRecord_rpc(mach_por
 	(void)unusedserver;		// Unused
 	mStatus err = mStatus_NoError;
 	const char *errormsg = "Unknown";
-	ExtraRecordRef *ref, *prev = NULL;
 	if (client == (mach_port_t)-1) { err = mStatus_Invalid;         errormsg = "Client id -1 invalid"; goto fail; }
 	DNSServiceRegistration *x = DNSServiceRegistrationList;
+	ServiceInstance *si;
+
 	while (x && x->ClientMachPort != client) x = x->next;
 	if (!x)                        { err = mStatus_BadReferenceErr; errormsg = "No such client";       goto fail; }
 
-	ref = x->ExtraRefList;
-	while (ref)
+	for (si = x->regs; si; si = si->next)
 		{
-		if (ref == (ExtraRecordRef *)ref) break;
-		prev = ref;
-	   ref = ref->next;
+		ExtraResourceRecord *e;
+		for (e = si->srs.Extras; e; e = e->next)
+			{
+			if ((natural_t)e->ClientID == reference)
+				{
+				err = RemoveRecord(&si->srs, e, client);
+				break;
+				}
+			}
+		if (!e) { err = mStatus_BadReferenceErr; errormsg = "No such reference"; goto fail; }
 		}
-	
-	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
-
-	// delete the ref struct
-	if (prev) prev->next = ref->next;
-	else x->ExtraRefList = ref->next;
-	ref->next = NULL;
-	freeL("ExtraRecordRef", ref);
-	return err;
+
+	return mStatus_NoError;
 
 fail:
 	LogMsg("%5d: DNSServiceRegistrationRemoveRecord(%X) failed: %s (%ld)", client, reference, errormsg, err);
@@ -1705,7 +1991,7 @@ mDNSlocal void DNSserverCallback(CFMachPortRef port, void *msg, CFIndex size, vo
             break;
 
         default :
-            /* Includes success case.  */
+            /* Includes success case. */
             break;
 		}
 
@@ -1772,23 +2058,19 @@ mDNSlocal kern_return_t destroyBootstrapService()
 	return bootstrap_register(server_priv_port, (char*)kmDNSBootstrapName, MACH_PORT_NULL);
 	}
 
-mDNSlocal void ExitCallback(CFMachPortRef port, void *msg, CFIndex size, void *info)
+mDNSlocal void ExitCallback(int signal)
 	{
-	(void)port;		// Unused
-	(void)msg;		// Unused
-	(void)size;		// Unused
-	(void)info;		// Unused
-/*
+#if 0
 	CacheRecord *rr;
 	int rrcache_active = 0;
 	for (rr = mDNSStorage.rrcache; rr; rr=rr->next) if (CacheRRActive(&mDNSStorage, rr)) rrcache_active++;
 	debugf("ExitCallback: RR Cache now using %d records, %d active", mDNSStorage.rrcache_used, rrcache_active);
-*/
+#endif
 
 	LogMsgIdent(mDNSResponderVersionString, "stopping");
 
 	debugf("ExitCallback: destroyBootstrapService");
-	if (!mDNS_DebugMode)
+	if (!mDNS_DebugMode && signal != SIGHUP)
 		destroyBootstrapService();
 
 	debugf("ExitCallback: Aborting MIG clients");
@@ -1808,89 +2090,62 @@ mDNSlocal void ExitCallback(CFMachPortRef port, void *msg, CFIndex size, void *i
 	}
 
 // Send a mach_msg to ourselves (since that is signal safe) telling us to cleanup and exit
-mDNSlocal void HandleSIGTERM(int signal)
+mDNSlocal void HandleSIG(int signal)
 	{
-	(void)signal;		// Unused
 	debugf(" ");
-	debugf("SIGINT/SIGTERM");
+	debugf("HandleSIG %d", signal);
 	mach_msg_header_t header;
 	header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND, 0);
-	header.msgh_remote_port = exit_m_port;
+	header.msgh_remote_port = signal_port;
 	header.msgh_local_port = MACH_PORT_NULL;
 	header.msgh_size = sizeof(header);
-	header.msgh_id = 0;
+	header.msgh_id = signal;
 	if (mach_msg_send(&header) != MACH_MSG_SUCCESS)
-		{ LogMsg("HandleSIGTERM: mach_msg_send failed; Exiting immediately."); exit(-1); }
+		{
+		LogMsg("HandleSIG %d: mach_msg_send failed", signal);
+		if (signal == SIGHUP || signal == SIGTERM || signal == SIGINT) exit(-1);
+		}
 	}
 
-mDNSlocal void INFOCallback(CFMachPortRef port, void *msg, CFIndex size, void *info)
+mDNSlocal void INFOCallback(void)
 	{
-	(void)port;		// Unused
-	(void)msg;		// Unused
-	(void)size;		// Unused
-	(void)info;		// Unused
 	DNSServiceDomainEnumeration *e;
 	DNSServiceBrowser           *b;
 	DNSServiceResolver          *l;
 	DNSServiceRegistration      *r;
 	NetworkInterfaceInfoOSX     *i;
-	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 = mDNSStorage.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),
-				((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)
-		LogMsgNoIdent("Cache use mismatch: rrcache_totalused is %lu, true count %lu", mDNSStorage.rrcache_totalused, CacheUsed);
-	if (mDNSStorage.rrcache_active != 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);
+	udsserver_info(&mDNSStorage);
 
 	for (e = DNSServiceDomainEnumerationList; e; e=e->next)
-		LogMsgNoIdent("%5d: DomainEnumeration   %##s", e->ClientMachPort, e->dom.qname.c);
+		LogMsgNoIdent("%5d: Mach DomainEnumeration   %##s", e->ClientMachPort, e->dom.qname.c);
 
 	for (b = DNSServiceBrowserList; b; b=b->next)
 		{
 		DNSServiceBrowserQuestion *qptr;
 		for (qptr = b->qlist; qptr; qptr = qptr->next)
-			LogMsgNoIdent("%5d: ServiceBrowse       %##s", b->ClientMachPort, qptr->q.qname.c);
+			LogMsgNoIdent("%5d: Mach ServiceBrowse       %##s", b->ClientMachPort, qptr->q.qname.c);
 		}
 	for (l = DNSServiceResolverList; l; l=l->next)
-		LogMsgNoIdent("%5d: ServiceResolve      %##s", l->ClientMachPort, l->i.name.c);
+		LogMsgNoIdent("%5d: Mach ServiceResolve      %##s", l->ClientMachPort, l->i.name.c);
 
 	for (r = DNSServiceRegistrationList; r; r=r->next)
 		{
-		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));
+		ServiceInstance *si;
+		for (si = r->regs; si; si = si->next)
+			LogMsgNoIdent("%5d: Mach ServiceInstance     %##s %u", si->ClientMachPort, si->srs.RR_SRV.resrec.name.c, mDNSVal16(si->srs.RR_SRV.resrec.rdata->u.srv.port));
 		}
 
-	udsserver_info();
-
 	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);
+			LogMsgNoIdent("Interface: %s %5s(%lu) %.6a DORMANT",
+				i->sa_family == AF_INET ? "v4" : i->sa_family == AF_INET6 ? "v6" : "??", i->ifa_name, i->scope_id, &i->BSSID);
 		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,
+			LogMsgNoIdent("Interface: %s %5s(%lu) %.6a %s %s %2d %s %2d InterfaceID %p %s %s %#a",
+				i->sa_family == AF_INET ? "v4" : i->sa_family == AF_INET6 ? "v6" : "??", i->ifa_name, i->scope_id, &i->BSSID,
 				i->ifinfo.InterfaceActive ? "Active" : "      ",
 				i->ifinfo.IPv4Available ? "v4" : "  ", i->ss.sktv4,
 				i->ifinfo.IPv6Available ? "v6" : "  ", i->ss.sktv6,
@@ -1903,17 +2158,22 @@ mDNSlocal void INFOCallback(CFMachPortRef port, void *msg, CFIndex size, void *i
 	LogMsgIdent(mDNSResponderVersionString, "----  END STATE LOG  ----");
 	}
 
-mDNSlocal void HandleSIGINFO(int signal)
+mDNSlocal void SignalCallback(CFMachPortRef port, void *msg, CFIndex size, void *info)
 	{
-	(void)signal;		// Unused
-	mach_msg_header_t header;
-	header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND, 0);
-	header.msgh_remote_port = info_m_port;
-	header.msgh_local_port = MACH_PORT_NULL;
-	header.msgh_size = sizeof(header);
-	header.msgh_id = 0;
-	if (mach_msg_send(&header) != MACH_MSG_SUCCESS)
-		LogMsg("HandleSIGINFO: mach_msg_send failed; No state log will be generated.");
+	(void)port;		// Unused
+	(void)size;		// Unused
+	(void)info;		// Unused
+	mach_msg_header_t *m = (mach_msg_header_t *)msg;
+	switch(m->msgh_id)
+		{
+		case SIGHUP:  
+		case SIGINT:  
+		case SIGTERM:	ExitCallback(m->msgh_id); break;
+		case SIGINFO:	INFOCallback(); break;
+		case SIGUSR1:	LogMsg("SIGUSR1: Simulate Network Configuration Change Event");
+						mDNSMacOSXNetworkChanged(&mDNSStorage); break;
+		default: LogMsg("SignalCallback: Unknown signal %d", m->msgh_id); break;
+		}
 	}
 
 mDNSlocal kern_return_t mDNSDaemonInitialize(void)
@@ -1921,16 +2181,14 @@ mDNSlocal kern_return_t mDNSDaemonInitialize(void)
 	mStatus            err;
 	CFMachPortRef      d_port = CFMachPortCreate(NULL, ClientDeathCallback, NULL, NULL);
 	CFMachPortRef      s_port = CFMachPortCreate(NULL, DNSserverCallback, NULL, NULL);
-	CFMachPortRef      e_port = CFMachPortCreate(NULL, ExitCallback, NULL, NULL);
-	CFMachPortRef      i_port = CFMachPortCreate(NULL, INFOCallback, NULL, NULL);
+	CFMachPortRef      i_port = CFMachPortCreate(NULL, SignalCallback, NULL, NULL);
 	mach_port_t        m_port = CFMachPortGetPort(s_port);
 	char *MachServerName = mDNSMacOSXSystemBuildNumber(NULL) < 7 ? "DNSServiceDiscoveryServer" : "com.apple.mDNSResponder";
 	kern_return_t      status = bootstrap_register(bootstrap_port, MachServerName, m_port);
 	CFRunLoopSourceRef d_rls  = CFMachPortCreateRunLoopSource(NULL, d_port, 0);
 	CFRunLoopSourceRef s_rls  = CFMachPortCreateRunLoopSource(NULL, s_port, 0);
-	CFRunLoopSourceRef e_rls  = CFMachPortCreateRunLoopSource(NULL, e_port, 0);
 	CFRunLoopSourceRef i_rls  = CFMachPortCreateRunLoopSource(NULL, i_port, 0);
-	
+
 	if (status)
 		{
 		if (status == 1103)
@@ -1944,37 +2202,34 @@ 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);
-	exit_m_port = CFMachPortGetPort(e_port);
-	info_m_port = CFMachPortGetPort(i_port);
+	signal_port = CFMachPortGetPort(i_port);
 
 	CFRunLoopAddSource(CFRunLoopGetCurrent(), d_rls, kCFRunLoopDefaultMode);
 	CFRunLoopAddSource(CFRunLoopGetCurrent(), s_rls, kCFRunLoopDefaultMode);
-	CFRunLoopAddSource(CFRunLoopGetCurrent(), e_rls, kCFRunLoopDefaultMode);
 	CFRunLoopAddSource(CFRunLoopGetCurrent(), i_rls, kCFRunLoopDefaultMode);
 	CFRelease(d_rls);
 	CFRelease(s_rls);
-	CFRelease(e_rls);
 	CFRelease(i_rls);
 	if (mDNS_DebugMode) printf("Service registered with Mach Port %d\n", m_port);
-	err = udsserver_init(&mDNSStorage);
+	err = udsserver_init();
 	if (err) { LogMsg("Daemon start: udsserver_init failed"); return err; }
 	return(err);
 	}
 
-mDNSlocal mDNSs32 mDNSDaemonIdle(void)
+mDNSlocal mDNSs32 mDNSDaemonIdle(mDNS *const m)
 	{
 	// 1. Call mDNS_Execute() to let mDNSCore do what it needs to do
-	mDNSs32 nextevent = mDNS_Execute(&mDNSStorage);
+	mDNSs32 nextevent = mDNS_Execute(m);
+
+	mDNSs32 now = mDNS_TimeNow(m);
 
-	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
@@ -2023,10 +2278,46 @@ mDNSlocal mDNSs32 mDNSDaemonIdle(void)
 		if (l->ReportTime && now - l->ReportTime >= 0)
 			{
 			l->ReportTime = 0;
-			LogMsg("%5d: DNSServiceResolver(%##s) active for over two minutes. "
-				"This places considerable burden on the network.", l->ClientMachPort, l->i.name.c);
+			LogMsgNoIdent("Client application bug: DNSServiceResolver(%##s) active for over two minutes. "
+				"This places considerable burden on the network.", l->i.name.c);
 			}
 
+	if (m->p->NotifyUser)
+		{
+		if (m->p->NotifyUser - now < 0)
+			{
+			if (!SameDomainLabel(m->p->usernicelabel.c, m->nicelabel.c))
+				{
+				LogMsg("Updating Computer Name from \"%#s\" to \"%#s\"", m->p->usernicelabel.c, m->nicelabel.c);
+				RecordUpdatedName(m, &m->p->usernicelabel, &m->nicelabel, "The name of your computer ", "",
+					CFSTR("To change the name of your computer, open System Preferences and click Sharing.  Then type the name in the Computer Name field."));
+				m->p->NotifyUser = 0;	// Clear m->p->NotifyUser here -- even if the hostlabel has changed too, we don't want to bug the user with *two* alerts
+				}
+			if (!SameDomainLabel(m->p->userhostlabel.c, m->hostlabel.c))
+				{
+				LogMsg("Updating Local Hostname from \"%#s.local\" to \"%#s.local\"", m->p->userhostlabel.c, m->hostlabel.c);
+				RecordUpdatedName(m, &m->p->userhostlabel, &m->hostlabel, "This computer's local hostname ", ".local",
+					CFSTR("To change the local hostname, open System Preferences and click Sharing.  Then click Edit and type the name in the Local Hostname field."));
+				}
+			m->p->NotifyUser = 0;
+			}
+		else
+			if (nextevent - m->p->NotifyUser > 0)
+				nextevent = m->p->NotifyUser;
+		}
+
+	if (m->p->NetworkChanged)
+		{
+		if (m->p->NetworkChanged - now < 0)
+			{
+			m->p->NetworkChanged = 0;
+			mDNSMacOSXNetworkChanged(m);
+			}
+		else
+			if (nextevent - m->p->NetworkChanged > 0)
+				nextevent = m->p->NetworkChanged;
+		}
+
 	return(nextevent);
 	}
 
@@ -2034,15 +2325,18 @@ mDNSexport int main(int argc, char **argv)
 	{
 	int i;
 	kern_return_t status;
-	
+
 	for (i=1; i<argc; i++)
 		{
 		if (!strcmp(argv[i], "-d")) mDNS_DebugMode = mDNStrue;
 		}
 
-	signal(SIGINT,  HandleSIGTERM);		// SIGINT is what you get for a Ctrl-C
-	signal(SIGTERM, HandleSIGTERM);
-	signal(SIGINFO, HandleSIGINFO);
+	signal(SIGHUP,  HandleSIG);		// (Debugging) Exit cleanly and let mach_init restart us (for debugging)
+	signal(SIGINT,  HandleSIG);		// Ctrl-C: Detach from Mach BootstrapService and exit cleanly
+	signal(SIGPIPE, SIG_IGN  );		// Don't want SIGPIPE signals -- we'll handle EPIPE errors directly
+	signal(SIGTERM, HandleSIG);		// Machine shutting down: Detach from and exit cleanly like Ctrl-C
+	signal(SIGINFO, HandleSIG);		// (Debugging) Write state snapshot to syslog
+	signal(SIGUSR1, HandleSIG);		// (Debugging) Simulate network change notification from System Configuration Framework
 
 	// Register the server with mach_init for automatic restart only during normal (non-debug) mode
     if (!mDNS_DebugMode) registerBootstrapService();
@@ -2053,14 +2347,14 @@ mDNSexport int main(int argc, char **argv)
 	if (!mDNS_DebugMode)
 		{
 		int fd = open(_PATH_DEVNULL, O_RDWR, 0);
-		if (fd != -1)
+		if (fd < 0) LogMsg("open(_PATH_DEVNULL, O_RDWR, 0) failed errno %d (%s)", errno, strerror(errno));
+		else
 			{
 			// Avoid unnecessarily duplicating a file descriptor to itself
-			if (fd != STDIN_FILENO) (void)dup2(fd, STDIN_FILENO);
-			if (fd != STDOUT_FILENO) (void)dup2(fd, STDOUT_FILENO);
-			if (fd != STDERR_FILENO) (void)dup2(fd, STDERR_FILENO);
-			if (fd != STDIN_FILENO && fd != STDOUT_FILENO && fd != STDERR_FILENO) 
-				(void)close (fd);
+			if (fd != STDIN_FILENO)  if (dup2(fd, STDIN_FILENO)  < 0) LogMsg("dup2(fd, STDIN_FILENO)  failed errno %d (%s)", errno, strerror(errno));
+			if (fd != STDOUT_FILENO) if (dup2(fd, STDOUT_FILENO) < 0) LogMsg("dup2(fd, STDOUT_FILENO) failed errno %d (%s)", errno, strerror(errno));
+			if (fd != STDERR_FILENO) if (dup2(fd, STDERR_FILENO) < 0) LogMsg("dup2(fd, STDERR_FILENO) failed errno %d (%s)", errno, strerror(errno));
+			if (fd != STDIN_FILENO && fd != STDOUT_FILENO && fd != STDERR_FILENO) (void)close(fd);
 			}
 		}
 
@@ -2068,18 +2362,21 @@ mDNSexport int main(int argc, char **argv)
 	LogMsgIdent(mDNSResponderVersionString, "starting");
 	status = mDNSDaemonInitialize();
 
+#if CAN_UPDATE_DYNAMIC_STORE_WITHOUT_BEING_ROOT
 	// Now that we're finished with anything privileged, switch over to running as "nobody"
 	const struct passwd *pw = getpwnam("nobody");
 	if (pw != NULL)
 		setuid(pw->pw_uid);
 	else
 		setuid(-2);		// User "nobody" is -2; use that value if "nobody" does not appear in the password database
+#endif
 
 	if (status == 0)
 		{
+		LogMsg("Starting time value 0x%08lX (%ld)", (mDNSu32)mDNSStorage.timenow_last, mDNSStorage.timenow_last);
 		int numevents = 0;
 		int RunLoopStatus = kCFRunLoopRunTimedOut;
-		
+
 		// This is the main work loop:
 		// (1) First we give mDNSCore a chance to finish off any of its deferred work and calculate the next sleep time
 		// (2) Then we make sure we've delivered all waiting browse messages to our clients
@@ -2090,11 +2387,11 @@ 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();
+			mDNSs32 nextevent = mDNSDaemonIdle(&mDNSStorage);
 			nextevent = udsserver_idle(nextevent);
 
 			// 2. Work out how long we expect to sleep before the next scheduled task
-			mDNSs32 ticks = nextevent - mDNSPlatformTimeNow();
+			mDNSs32 ticks = nextevent - mDNS_TimeNow(&mDNSStorage);
 			static mDNSs32 RepeatedBusy = 0;	// Debugging sanity check, to guard against CPU spins
 			if (ticks > 1)
 				RepeatedBusy = 0;
@@ -2105,7 +2402,7 @@ mDNSexport int main(int argc, char **argv)
 					{ 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
 			// (a) our next wakeup time, or (b) an event occurs.
 			// The 'true' parameter makes it return after handling any event that occurs
@@ -2133,23 +2430,27 @@ mDNSexport int main(int argc, char **argv)
 
 //		uds_daemon.c support routines		/////////////////////////////////////////////
 
-// We keep a list of client-supplied event sources in PosixEventSource records 
+// 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;
+	CFSocketRef					cfs;
 	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)
+static void cf_callback(CFSocketRef s, CFSocketCallBackType t, CFDataRef dr, const void *c, void *i)
 	// Called by CFSocket when data appears on socket
 	{
+	(void)s; // Unused
+	(void)t; // Unused
+	(void)dr; // Unused
+	(void)c; // Unused
 	CFSocketEventSource	*source = (CFSocketEventSource*) i;
 	source->Callback(source->Context);
 	}
@@ -2159,7 +2460,7 @@ mStatus udsSupportAddFDToEventLoop(int fd, udsEventCallback callback, void *cont
 	{
 	CFSocketEventSource	*newSource;
 	CFSocketContext cfContext = 	{ 0, NULL, NULL, NULL, NULL 	};
-	
+
 	if (gEventSources.LinkOffset == 0)
 		InitLinkedList(&gEventSources, offsetof(CFSocketEventSource, Next));
 
@@ -2177,19 +2478,19 @@ mStatus udsSupportAddFDToEventLoop(int fd, udsEventCallback callback, void *cont
 	newSource->fd = fd;
 
 	cfContext.info = newSource;
-	if ( NULL != (newSource->SocketRef = CFSocketCreateWithNative(kCFAllocatorDefault, fd, kCFSocketReadCallBack, 
+	if ( NULL != (newSource->cfs = CFSocketCreateWithNative(kCFAllocatorDefault, fd, kCFSocketReadCallBack,
 																	cf_callback, &cfContext)) &&
-		 NULL != (newSource->RLS = CFSocketCreateRunLoopSource(kCFAllocatorDefault, newSource->SocketRef, 0)))
+		 NULL != (newSource->RLS = CFSocketCreateRunLoopSource(kCFAllocatorDefault, newSource->cfs, 0)))
 		{
 		CFRunLoopAddSource(CFRunLoopGetCurrent(), newSource->RLS, kCFRunLoopDefaultMode);
 		AddToTail(&gEventSources, newSource);
 		}
 	else
 		{
-		if (newSource->SocketRef)
+		if (newSource->cfs)
 			{
-			CFSocketInvalidate(newSource->SocketRef);  // automatically closes socket
-			CFRelease(newSource->SocketRef);
+			CFSocketInvalidate(newSource->cfs); // automatically closes socket
+			CFRelease(newSource->cfs);
 			}
 		return mStatus_NoMemoryErr;
 		}
@@ -2210,8 +2511,8 @@ mStatus udsSupportRemoveFDFromEventLoop(int fd)
 			CFRunLoopRemoveSource(CFRunLoopGetCurrent(), iSource->RLS, kCFRunLoopDefaultMode);
 			CFRunLoopSourceInvalidate(iSource->RLS);
 			CFRelease(iSource->RLS);
-			CFSocketInvalidate(iSource->SocketRef);
-			CFRelease(iSource->SocketRef);
+			CFSocketInvalidate(iSource->cfs);
+			CFRelease(iSource->cfs);
 			free(iSource);
 			return mStatus_NoError;
 			}
@@ -2219,5 +2520,9 @@ mStatus udsSupportRemoveFDFromEventLoop(int fd)
 	return mStatus_NoSuchNameErr;
 	}
 
+// If mDNSResponder crashes, then this string will be magically included in the automatically-generated crash log
+const char *__crashreporter_info__ = mDNSResponderVersionString;
+asm(".desc ___crashreporter_info__, 0x10");
+
 // 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/CFSocket.c b/mDNSMacOSX/mDNSMacOSX.c
similarity index 53%
rename from mDNSMacOSX/CFSocket.c
rename to mDNSMacOSX/mDNSMacOSX.c
index 388cdf2..eebba79 100644
--- a/mDNSMacOSX/CFSocket.c
+++ b/mDNSMacOSX/mDNSMacOSX.c
@@ -1,17 +1,16 @@
-/*
- * Copright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * 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,
@@ -19,12 +18,339 @@
  * 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: CFSocket.c,v $
+$Log: mDNSMacOSX.c,v $
+Revision 1.258  2004/12/14 00:18:05  cheshire
+Don't log dns_configuration_copy() failures in the first three minutes after boot
+
+Revision 1.257  2004/12/10 19:45:46  cheshire
+<rdar://problem/3915074> Reduce egregious stack space usage
+Reduced myCFSocketCallBack() stack frame from 9K to 512 bytes
+
+Revision 1.256  2004/12/10 04:35:43  cheshire
+<rdar://problem/3907233> Show "Note: Compiled without Apple-specific split DNS support" only once
+
+Revision 1.255  2004/12/10 04:12:54  ksekar
+<rdar://problem/3890764> Need new DefaultBrowseDomain key
+
+Revision 1.254  2004/12/10 01:55:31  ksekar
+<rdar://problem/3899067> Keychain lookups should be in lower case.
+
+Revision 1.253  2004/12/09 03:15:41  ksekar
+<rdar://problem/3806610> use _legacy instead of _default to find "empty string" browse domains
+
+Revision 1.252  2004/12/07 01:32:42  cheshire
+Don't log dns_configuration_copy() failure when running on 10.3
+
+Revision 1.251  2004/12/06 22:30:31  cheshire
+Added debugging log message
+
+Revision 1.250  2004/12/06 06:59:08  ksekar
+RegisterSplitDNS should return Unsupported error when compiled on Panther
+
+Revision 1.249  2004/12/04 00:29:46  cheshire
+Add "#ifdef MAC_OS_X_VERSION_10_4" around split-DNS code that can't be compiled on 10.3 systems
+(When compiled on 10.3, code will not include split-DNS support.)
+
+Revision 1.248  2004/12/01 20:57:20  ksekar
+<rdar://problem/3873921> Wide Area Rendezvous must be split-DNS aware
+
+Revision 1.247  2004/12/01 03:26:58  cheshire
+Remove unused variables
+
+Revision 1.246  2004/12/01 01:51:34  cheshire
+Move ReadDDNSSettingsFromConfFile() from mDNSMacOSX.c to PlatformCommon.c
+
+Revision 1.245  2004/11/30 03:24:04  cheshire
+<rdar://problem/3854544> Defer processing network configuration changes until configuration has stabilized
+
+Revision 1.244  2004/11/30 02:59:35  cheshire
+For debugging diagnostics, added identifying strings in SCDynamicStoreCreate() calls
+
+Revision 1.243  2004/11/29 19:17:29  ksekar
+<rdar://problem/3878195> Unnecessary GetUserSpecifiedDDNSConfig log messages
+
+Revision 1.242  2004/11/29 18:37:38  ksekar
+<rdar://problem/3889341> Buffer overflow in GetConfigOption
+
+Revision 1.241  2004/11/25 01:37:04  ksekar
+<rdar://problem/3894854> Config file and SCPreferences don't play well together
+
+Revision 1.240  2004/11/25 01:29:42  ksekar
+Remove unnecessary log messages
+
+Revision 1.239  2004/11/25 01:27:19  ksekar
+<rdar://problem/3885859> Don't try to advertise link-local IP addresses via dynamic update
+
+Revision 1.238  2004/11/24 22:00:59  cheshire
+Move definition of mDNSAddressIsAllDNSLinkGroup() from mDNSMacOSX.c to mDNSEmbeddedAPI.h
+
+Revision 1.237  2004/11/24 21:54:44  cheshire
+<rdar://problem/3894475> mDNSCore not receiving unicast responses properly
+
+Revision 1.236  2004/11/23 03:39:46  cheshire
+Let interface name/index mapping capability live directly in JNISupport.c,
+instead of having to call through to the daemon via IPC to get this information.
+
+Revision 1.235  2004/11/17 01:45:35  cheshire
+<rdar://problem/3847435> Rendezvous buddy list frequently becomes empty if you let the machine sleep
+Refresh our interface list on receiving kIOMessageSystemHasPoweredOn,
+in case we get no System Configuration Framework "network changed" event.
+
+Revision 1.234  2004/11/17 00:32:56  ksekar
+<rdar://problem/3880773> mDNSResponder will not discover zones contained both in Search Domains and DHCP Domain option
+
+Revision 1.233  2004/11/12 03:16:45  rpantos
+rdar://problem/3809541 Add mDNSPlatformGetInterfaceByName, mDNSPlatformGetInterfaceName
+
+Revision 1.232  2004/11/10 20:40:54  ksekar
+<rdar://problem/3868216> LLQ mobility fragile on non-primary interface
+
+Revision 1.231  2004/11/06 00:59:33  ksekar
+Don't log ENETDOWN errors for unicast destinations (pollutes log on
+wake from sleep)
+
+Revision 1.230  2004/11/05 01:04:10  ksekar
+<rdar://problem/3774577> LegacyNATDestroy() called too enthusiastically
+
+Revision 1.229  2004/11/03 03:45:16  cheshire
+<rdar://problem/3863627> mDNSResponder does not inform user of Computer Name collisions
+
+Revision 1.228  2004/11/02 23:47:32  cheshire
+<rdar://problem/3863214> Default hostname and Computer Name should be unique
+
+Revision 1.227  2004/11/02 04:23:03  cheshire
+Change to more informative name "GetUserSpecifiedLocalHostName()"
+
+Revision 1.226  2004/11/01 20:36:19  ksekar
+<rdar://problem/3802395> mDNSResponder should not receive Keychain Notifications
+
+Revision 1.225  2004/10/28 19:03:04  cheshire
+Remove \n from LogMsg() calls
+
+Revision 1.224  2004/10/28 17:47:34  cheshire
+Oops. Forgot the %d in the log message.
+
+Revision 1.223  2004/10/28 17:24:28  cheshire
+Updated "bad ifa_netmask" log message to give more information
+
+Revision 1.222  2004/10/28 03:36:34  cheshire
+<rdar://problem/3856535> Share the same port for both multicast and unicast receiving
+
+Revision 1.221  2004/10/28 03:24:41  cheshire
+Rename m->CanReceiveUnicastOn as m->CanReceiveUnicastOn5353
+
+Revision 1.220  2004/10/28 00:53:57  cheshire
+Export mDNSMacOSXNetworkChanged() so it's callable from outside this mDNSMacOSX.c;
+Add LogOperation() call to record when we get network change events
+
+Revision 1.219  2004/10/27 20:42:20  cheshire
+Clean up debugging messages
+
+Revision 1.218  2004/10/27 02:03:59  cheshire
+Update debugging messages
+
+Revision 1.217  2004/10/26 20:48:21  cheshire
+Improve logging messages
+
+Revision 1.216  2004/10/26 01:02:37  cheshire
+Update comment
+
+Revision 1.215  2004/10/25 20:09:00  ksekar
+Cleaned up config file parsing.
+
+Revision 1.214  2004/10/25 19:30:53  ksekar
+<rdar://problem/3827956> Simplify dynamic host name structures
+
+Revision 1.213  2004/10/23 01:16:01  cheshire
+<rdar://problem/3851677> uDNS operations not always reliable on multi-homed hosts
+
+Revision 1.212  2004/10/22 20:52:08  ksekar
+<rdar://problem/3799260> Create NAT port mappings for Long Lived Queries
+
+Revision 1.211  2004/10/22 01:07:11  cheshire
+<rdar://problem/3375328> select() says data is waiting; recvfrom() says there is no data
+Log error message if socket() ever returns file descriptors 0, 1 or 2 (stdin/stdout/stderr).
+These are all supposed to be remapped to /dev/null
+
+Revision 1.210  2004/10/20 02:19:54  cheshire
+Eliminate "SetupAddr invalid sa_family" warning from RegisterSearchDomains()
+
+Revision 1.209  2004/10/16 00:17:00  cheshire
+<rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check
+
+Revision 1.208  2004/10/15 23:00:18  ksekar
+<rdar://problem/3799242> Need to update LLQs on location changes
+
+Revision 1.207  2004/10/13 22:45:23  cheshire
+<rdar://problem/3438392> Ten-second delay before kIOMessageSystemHasPoweredOn message
+
+Revision 1.206  2004/10/13 22:11:46  cheshire
+Update debugging messages
+
+Revision 1.205  2004/10/12 21:10:11  cheshire
+<rdar://problem/3438376> mach_absolute_time() not monotonically increasing
+Do a NotifyOfElusiveBug() if we see mach_absolute_time() go backwards
+
+Revision 1.204  2004/10/12 03:20:52  ksekar
+<rdar://problem/3835614> Incorrect LogMsg produces garbage on errors
+
+Revision 1.203  2004/10/08 04:29:25  ksekar
+<rdar://problem/3831842> Allow default search domains to be set via hint from DHCP
+
+Revision 1.202  2004/10/04 05:56:04  cheshire
+<rdar://problem/3824730> mDNSResponder doesn't respond to certain AirPort changes
+
+Revision 1.201  2004/09/30 00:24:59  ksekar
+<rdar://problem/3695802> Dynamically update default registration domains on config change
+
+Revision 1.200  2004/09/26 23:20:35  ksekar
+<rdar://problem/3813108> Allow default registrations in multiple wide-area domains
+
+Revision 1.199  2004/09/24 23:54:55  cheshire
+<rdar://problem/3787102> Don't use kCFSocketCloseOnInvalidate
+
+Revision 1.198  2004/09/24 23:47:49  cheshire
+Correct comment and error message
+
+Revision 1.197  2004/09/24 23:39:27  cheshire
+<rdar://problem/3733705> Only IPv6 loopback address advertised on laptop w/no networking
+
+Revision 1.196  2004/09/24 20:53:04  cheshire
+Revise error message to say "Setsockopt SO_REUSEPORT failed" instead of "Flaw in Kernel"
+
+Revision 1.195  2004/09/24 19:21:45  cheshire
+<rdar://problem/3671626> Report "Address already in use" errors
+
+Revision 1.194  2004/09/24 19:16:54  cheshire
+Remove "mDNS *const m" parameter from NotifyOfElusiveBug();
+Refine error message to say "Flaw in Kernel (select/recvfrom mismatch)"
+
+Revision 1.193  2004/09/22 00:41:59  cheshire
+Move tcp connection status codes into the legal range allocated for mDNS use
+
+Revision 1.192  2004/09/21 21:02:55  cheshire
+Set up ifname before calling mDNS_RegisterInterface()
+
+Revision 1.191  2004/09/21 19:19:36  cheshire
+<rdar://problem/3760923> Combine WatchForDynDNSChanges() into WatchForNetworkChanges()
+
+Revision 1.190  2004/09/21 19:04:45  cheshire
+Strip trailing white space from the ends of lines
+
+Revision 1.189  2004/09/21 00:13:28  cheshire
+Fix build failure (io_connect_t and io_object_t are integers, not pointers)
+
+Revision 1.188  2004/09/20 23:52:02  cheshire
+CFSocket{Puma}.c renamed to mDNSMacOSX{Puma}.c
+
+Revision 1.187  2004/09/18 01:37:01  cheshire
+Update comment
+
+Revision 1.186  2004/09/18 01:11:57  ksekar
+<rdar://problem/3806734> Add a user's default domain to empty-string browse list
+
+Revision 1.185  2004/09/17 01:08:52  cheshire
+Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
+  The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
+  declared in that file are ONLY appropriate to single-address-space embedded applications.
+  For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
+
+Revision 1.184  2004/09/17 00:19:10  cheshire
+For consistency with AllDNSLinkGroupv6, rename AllDNSLinkGroup to AllDNSLinkGroupv4
+
+Revision 1.183  2004/09/17 00:15:56  cheshire
+Rename mDNSPlatformInit_ReceiveUnicast to mDNSPlatformInit_CanReceiveUnicast
+
+Revision 1.182  2004/09/16 21:36:36  cheshire
+<rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
+Changes to add necessary locking calls around unicast DNS operations
+
+Revision 1.181  2004/09/16 02:03:42  cheshire
+<rdar://problem/3802944> Change address to notify user of kernel flaw
+
+Revision 1.180  2004/09/16 01:58:22  cheshire
+Fix compiler warnings
+
+Revision 1.179  2004/09/16 00:24:49  cheshire
+<rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
+
+Revision 1.178  2004/09/15 21:51:34  cheshire
+<rdar://problem/3387020> mDNSResponder should notify user of kernel flaw
+Calling CFUserNotificationDisplayNotice too early in the boot process seems to kill
+the machine, so make sure we don't do this until at least three minutes after boot.
+
+Revision 1.177  2004/09/15 01:16:29  cheshire
+<rdar://problem/3387020> mDNSResponder should notify user of kernel flaw
+
+Revision 1.176  2004/09/14 23:42:36  cheshire
+<rdar://problem/3801296> Need to seed random number generator from platform-layer data
+
+Revision 1.175  2004/09/14 21:35:46  cheshire
+Minor code tidying, and added comments about CFRetainCounts
+
+Revision 1.174  2004/09/14 19:14:57  ksekar
+<rdar://problem/3192531> DynDNS: Discovery of DynDNS Zones via Reverse-Map PTR
+
+Revision 1.173  2004/08/25 23:35:22  ksekar
+<rdar://problem/3770615>: Error converting shared secret from base-64 to binary
+
+Revision 1.172  2004/08/25 02:01:45  cheshire
+<rdar://problem/3774777> Need to be able to get status of Dynamic DNS Host Name Update
+
+Revision 1.171  2004/08/25 01:04:42  cheshire
+Don't need to CFRelease name and array
+
+Revision 1.170  2004/08/25 00:37:28  ksekar
+<rdar://problem/3774635>: Cleanup DynDNS hostname registration code
+
+Revision 1.169  2004/08/18 17:35:41  ksekar
+<rdar://problem/3651443>: Feature #9586: Need support for Legacy NAT gateways
+
+Revision 1.168  2004/08/17 03:16:24  ksekar
+Fixed checkin 1.166 - enumeration type changed for wrong invocation of mDNS_GetDomains
+
+Revision 1.167  2004/08/17 00:52:43  ksekar
+Fix config file parse error, make semantics match SCPreferences
+configuration input.
+
+Revision 1.166  2004/08/16 19:55:07  ksekar
+Change enumeration type to BrowseDefault to construct empty-string
+browse list as result of checking 1.161.
+
+Revision 1.165  2004/08/16 19:52:40  ksekar
+Pass computer name + zone for FQDN after keychain notification,
+setting global default service registration domain to the zone.
+
+Revision 1.164  2004/08/16 16:52:37  ksekar
+Pass in zone read from keychain to mDNS_SetFQDNs.
+
+Revision 1.163  2004/08/14 03:22:42  cheshire
+<rdar://problem/3762579> Dynamic DNS UI <-> mDNSResponder glue
+Add GetUserSpecifiedDDNSName() routine
+Convert ServiceRegDomain to domainname instead of C string
+Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs
+
+Revision 1.162  2004/08/12 22:34:00  cheshire
+All strings should be read as kCFStringEncodingUTF8, not kCFStringEncodingASCII
+
+Revision 1.161  2004/08/11 00:17:46  ksekar
+<rdar://problem/3757662>: 8A227: Need Lighthouse configred machines to
+set default bit for their domains
+
+Revision 1.160  2004/07/29 19:27:16  ksekar
+NATPMP Support - minor fixes and cleanup
+
+Revision 1.159  2004/07/26 22:49:31  ksekar
+<rdar://problem/3651409>: Feature #9516: Need support for NATPMP in client
+
+Revision 1.158  2004/07/13 21:24:24  rpantos
+Fix for <rdar://problem/3701120>.
+
 Revision 1.157  2004/06/08 18:54:48  ksekar
 <rdar://problem/3681378>: mDNSResponder leaks after exploring in Printer Setup Utility
 
@@ -56,7 +382,7 @@ 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"
+from mDNSMacOSX.h to mDNSEmbeddedAPI.h), impelemted to return "local"
 only on non-OSX platforms.  Changed call to return a copy of the list
 to avoid shared memory issues.  Added a routine to free the list.
 
@@ -155,7 +481,7 @@ 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.
+Best solution is just to combine mDNSEmbeddedAPI.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
@@ -177,7 +503,7 @@ 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()
+<rdar://problem/3382647> mDNSResponder divide by zero in mDNSPlatformRawTime()
 
 Revision 1.110  2003/08/16 03:39:00  cheshire
 <rdar://problem/3338440> InterfaceID -1 indicates "local only"
@@ -256,7 +582,7 @@ Revision 1.90  2003/06/24 01:51:47  cheshire
 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
+<rdar://problem/3296061> mDNSResponder cannot handle interfaces whose total name is >3 chars
 One-line change: should say "IF_NAMESIZE", not sizeof(ifname)
 
 Revision 1.88  2003/06/12 23:38:37  cheshire
@@ -322,7 +648,7 @@ Revision 1.73  2003/05/21 17:56:29  ksekar
 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
+mDNSMacOSX.c needs to do *all* its mDNS_DeregisterInterface calls before freeing memory
 mDNS_DeregisterInterface revalidates cache record when *any* representative of an interface goes away
 
 Revision 1.71  2003/05/14 07:08:37  cheshire
@@ -428,7 +754,7 @@ 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
+Move Puma support to mDNSMacOSXPuma.c
 
 Revision 1.43  2002/09/17 01:05:28  cheshire
 Change mDNS_AdvertiseLocalAddresses to be an Init parameter instead of a global
@@ -439,7 +765,7 @@ Minor code tidying
  */
 
 // ***************************************************************************
-// mDNS-CFSocket.c:
+// mDNSMacOSX.c:
 // Supporting routines to run mDNS on a CFRunLoop platform
 // ***************************************************************************
 
@@ -452,13 +778,16 @@ Minor code tidying
 // 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 "mDNSMacOSX.h"             // Defines the specific types needed to run mDNS on this platform
+#include "mDNSEmbeddedAPI.h"          // Defines the interface provided to the client layer above
+#include "DNSCommon.h"
+#include "mDNSMacOSX.h"               // Defines the specific types needed to run mDNS on this platform
+#include "../mDNSShared/uds_daemon.h" // Defines communication interface from platform layer up to UDS daemon
+#include "PlatformCommon.h"
 
 #include <stdio.h>
-#include <unistd.h>                 // For select() and close()
 #include <stdarg.h>                 // For va_list support
 #include <net/if.h>
+#include <net/if_types.h>			// For IFT_ETHER
 #include <net/if_dl.h>
 #include <sys/uio.h>
 #include <sys/param.h>
@@ -480,12 +809,17 @@ Minor code tidying
 
 #include <Security/Security.h>
 
+#include <AvailabilityMacros.h>
+#ifdef MAC_OS_X_VERSION_10_4
+#include <dnsinfo.h>
+#endif
+
 // 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"
+#include "mDNSMacOSXPuma.c"
 #else
 #include <ifaddrs.h>
 #endif
@@ -494,20 +828,17 @@ 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;
+    int flag;
+    DNSQuestion BrowseQ;
+    DNSQuestion DefBrowseQ;
+    DNSQuestion LegacyBrowseQ;
+    DNSQuestion RegisterQ;
+    DNSQuestion DefRegisterQ;
+    ARListElem *AuthRecs;
 	} SearchListElem;
 
 
@@ -515,32 +846,108 @@ typedef struct 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)
+// for domain enumeration and default browsing/registration
+static SearchListElem *SearchList = NULL;      // where we search for _browse domains
+static DNSQuestion LegacyBrowseDomainQ;        // our local enumeration query for _legacy._browse domains
+static DNameListElem *DefBrowseList = NULL;    // cache of answers to above query (where we search for empty string browses)
+static DNameListElem *DefRegList = NULL;       // manually generated list of domains where we register for empty string registrations
+static ARListElem *SCPrefBrowseDomains = NULL; // manually generated local-only PTR records for browse domains we get from SCPreferences
+
+static domainname DynDNSRegDomain;             // Default wide-area zone for service registration
+static domainname DynDNSBrowseDomain;          // Default wide-area zone for legacy ("empty string") browses
+static domainname DynDNSHostname;
 
 #define CONFIG_FILE "/etc/mDNSResponder.conf"
-#define LH_KEYCHAIN_DESC "Lighthouse Shared Secret"
-#define LH_KEYCHAIN_SERVICE "Lighthouse"
+#define DYNDNS_KEYCHAIN_SERVICE "DynDNS Shared Secret"
 #define SYS_KEYCHAIN_PATH "/Library/Keychains/System.keychain"
-#define LH_SUFFIX "members.mac.com."
+
+// Function Prototypes
+mDNSlocal void SetSCPrefsBrowseDomain(mDNS *m, const domainname *d, mDNSBool add);
 
 // ***************************************************************************
-// Macros
+// Functions
 
-#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])
+// routines to allow access to default domain lists from daemon layer
 
-#define mDNSAddressIsAllDNSLinkGroup(X) (                                                     \
-	((X)->type == mDNSAddrType_IPv4 && mDNSSameIPv4Address((X)->ip.v4, AllDNSLinkGroup  )) || \
-	((X)->type == mDNSAddrType_IPv6 && mDNSSameIPv6Address((X)->ip.v6, AllDNSLinkGroupv6))    )
+mDNSexport DNameListElem *mDNSPlatformGetSearchDomainList(void)
+	{
+	return mDNS_CopyDNameList(DefBrowseList);
+	}
 
-// ***************************************************************************
-// Functions
+mDNSexport DNameListElem *mDNSPlatformGetRegDomainList(void)
+	{
+	return mDNS_CopyDNameList(DefRegList);
+	}
+
+// utility routines to manage registration domain lists
+
+mDNSlocal void AddDefRegDomain(domainname *d)
+	{
+	DNameListElem *newelem = NULL, *ptr;
+
+	// make sure name not already in list
+	for (ptr = DefRegList; ptr; ptr = ptr->next)
+		{
+		if (SameDomainName(&ptr->name, d))
+			{ debugf("duplicate addition of default reg domain %##s", d->c); return; }
+		}
+	
+	newelem = mallocL("DNameListElem", sizeof(*newelem));
+	if (!newelem) { LogMsg("Error - malloc"); return; }
+	AssignDomainName(newelem->name, *d);
+	newelem->next = DefRegList;
+	DefRegList = newelem;
+
+	DefaultRegDomainChanged(d, mDNStrue);
+	udsserver_default_reg_domain_changed(d, mDNStrue);
+	}
+
+mDNSlocal void RemoveDefRegDomain(domainname *d)
+	{
+	DNameListElem *ptr = DefRegList, *prev = NULL;
+
+	while (ptr)
+		{
+		if (SameDomainName(&ptr->name, d))
+			{
+			if (prev) prev->next = ptr->next;
+			else DefRegList = ptr->next;
+			freeL("DNameListElem", ptr);
+			DefaultRegDomainChanged(d, mDNSfalse);
+			udsserver_default_reg_domain_changed(d, mDNSfalse);
+			return;
+			}
+		prev = ptr;
+		ptr = ptr->next;
+		}
+	debugf("Requested removal of default registration domain %##s not in contained in list", d->c); 
+	}
+
+mDNSlocal void NotifyOfElusiveBug(const char *title, mDNSu32 radarid, const char *msg)
+	{
+	extern mDNS mDNSStorage;
+	NetworkInterfaceInfoOSX *i;
+	static int notifyCount = 0;
+	if (notifyCount) return;
+	
+	// If we display our alert early in the boot process, then it vanishes once the desktop appears.
+	// To avoid this, we don't try to display alerts in the first three minutes after boot.
+	if ((mDNSu32)(mDNSPlatformRawTime()) < (mDNSu32)(mDNSPlatformOneSecond * 180)) return;
+	
+	// Determine if we're at Apple (17.*.*.*)
+	for (i = mDNSStorage.p->InterfaceList; i; i = i->next)
+		if (i->ifinfo.ip.type == mDNSAddrType_IPv4 && i->ifinfo.ip.ip.v4.b[0] == 17)
+			break;
+	if (!i) return;	// If not at Apple, don't show the alert
+
+	// Send a notification to the user to contact coreos-networking
+	notifyCount++;
+	CFStringRef alertHeader  = CFStringCreateWithCString(NULL, title, kCFStringEncodingUTF8);
+	CFStringRef alertFormat  = CFSTR("Congratulations, you've reproduced an elusive bug. Please contact the owner of <rdar://problem/%d>. %s");
+	CFStringRef alertMessage = CFStringCreateWithFormat(NULL, NULL, alertFormat, radarid, msg);
+	CFUserNotificationDisplayNotice(0.0, kCFUserNotificationStopAlertLevel, NULL, NULL, NULL, alertHeader, alertMessage, NULL);
+	}
 
 mDNSlocal struct ifaddrs* myGetIfAddrs(int refresh)
 	{
@@ -557,6 +964,17 @@ mDNSlocal struct ifaddrs* myGetIfAddrs(int refresh)
 	return ifa;
 	}
 
+mDNSlocal NetworkInterfaceInfoOSX *SearchForInterfaceByName(mDNS *const m, const char *ifname, int type)
+	{
+	NetworkInterfaceInfoOSX *i;
+	for (i = m->p->InterfaceList; i; i = i->next)
+		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);
+	return(NULL);
+	}
+
 mDNSlocal int myIfIndexToName(u_short index, char* name)
 	{
 	struct ifaddrs *ifa;
@@ -577,7 +995,7 @@ mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(const mDNS
 			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;
@@ -591,7 +1009,8 @@ mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(const mDNS *const m
 
 // 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,
+// OR send via our primary v4 unicast socket
+mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const msg, const mDNSu8 *const end,
 	mDNSInterfaceID InterfaceID, const mDNSAddr *dst, mDNSIPPort dstPort)
 	{
 	#pragma unused(m)
@@ -604,6 +1023,16 @@ mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const DNSMessage *co
 	struct sockaddr_storage to;
 	int s = -1, err;
 
+	// Sanity check: Make sure that if we're sending a query via unicast, we're sending it using our
+	// anonymous socket created for this purpose, so that we'll receive the response.
+	// If we use one of the many multicast sockets bound to port 5353 then we may not receive responses reliably.
+	if (info && !mDNSAddrIsDNSMulticast(dst))
+		{
+		const DNSMessage *const m = (DNSMessage *)msg;
+		if ((m->h.flags.b[0] & kDNSFlag0_QR_Mask) == kDNSFlag0_QR_Query)
+			LogMsg("mDNSPlatformSendUDP: ERROR: Sending query OP from mDNS port to non-mDNS destination %#a:%d", dst, mDNSVal16(dstPort));
+		}
+
 	if (dst->type == mDNSAddrType_IPv4)
 		{
 		struct sockaddr_in *sin_to = (struct sockaddr_in*)&to;
@@ -626,15 +1055,15 @@ mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const DNSMessage *co
 		}
 	else
 		{
-		LogMsg("mDNSPlatformSendUDP: dst is not an IPv4 or IPv6 address!\n");
+		LogMsg("mDNSPlatformSendUDP: dst is not an IPv4 or IPv6 address!");
 		return mStatus_BadParamErr;
 		}
 
 	if (s >= 0)
-		verbosedebugf("mDNSPlatformSendUDP: sending on InterfaceID %X %s/%d to %#a:%d skt %d",
+		verbosedebugf("mDNSPlatformSendUDP: sending on InterfaceID %p %5s/%ld to %#a:%d skt %d",
 			InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s);
 	else
-		verbosedebugf("mDNSPlatformSendUDP: NOT sending on InterfaceID %X %s/%d (socket of this type not available)",
+		verbosedebugf("mDNSPlatformSendUDP: NOT sending on InterfaceID %p %5s/%ld (socket of this type not available)",
 			InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort));
 
 	// Note: When sending, mDNSCore may often ask us to send both a v4 multicast packet and then a v6 multicast packet
@@ -644,13 +1073,13 @@ 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
-		if (errno == EHOSTDOWN && !mDNSAddressIsAllDNSLinkGroup(dst)) return(err);
+        // Don't report EHOSTDOWN (i.e. ARP failure), ENETDOWN, or no route to host for unicast destinations
+		if (!mDNSAddressIsAllDNSLinkGroup(dst) && (errno == EHOSTDOWN || errno == ENETDOWN || errno == EHOSTUNREACH)) return(err);
 		// 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 * 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",
+		if (errno == EHOSTUNREACH && (mDNSu32)(mDNSPlatformRawTime()) < (mDNSu32)(mDNSPlatformOneSecond * 180)) return(err);
+		LogMsg("mDNSPlatformSendUDP sendto failed to send packet on InterfaceID %p %5s/%ld to %#a:%d skt %d error %d errno %d (%s) %lu",
 			InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, errno, strerror(errno), (mDNSu32)(m->timenow));
 		return(err);
 		}
@@ -683,18 +1112,18 @@ mDNSlocal ssize_t myrecvfrom(const int s, void *const buffer, const size_t max,
 	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);
+		if (errno != EWOULDBLOCK && numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) returned error %d errno %d", s, n, errno);
 		return(-1);
 		}
 	if (msg.msg_controllen < (int)sizeof(struct cmsghdr))
 		{
-		if (numLogMessages++ < 100) LogMsg("CFSocket.c: recvmsg(%d) msg.msg_controllen %d < sizeof(struct cmsghdr) %lu",
+		if (numLogMessages++ < 100) LogMsg("mDNSMacOSX.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);
+		if (numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) msg.msg_flags & MSG_CTRUNC", s);
 		return(-1);
 		}
 	
@@ -748,8 +1177,7 @@ mDNSlocal void myCFSocketCallBack(CFSocketRef cfs, CFSocketCallBackType CallBack
 	mDNSIPPort senderPort, destPort = MulticastDNSPort;
 	const CFSocketSet *ss = (const CFSocketSet *)context;
 	mDNS *const m = ss->m;
-	const mDNSInterfaceID InterfaceID = ss->info ? ss->info->ifinfo.InterfaceID : mDNSNULL;
-	DNSMessage packet;
+	mDNSInterfaceID InterfaceID = ss->info ? ss->info->ifinfo.InterfaceID : mDNSNULL;
 	struct sockaddr_storage from;
 	size_t fromlen = sizeof(from);
 	char packetifname[IF_NAMESIZE] = "";
@@ -773,7 +1201,7 @@ mDNSlocal void myCFSocketCallBack(CFSocketRef cfs, CFSocketCallBackType CallBack
 		}
 
 	mDNSu8 ttl;
-	while ((err = myrecvfrom(s1, &packet, sizeof(packet), (struct sockaddr *)&from, &fromlen, &destAddr, packetifname, &ttl)) >= 0)
+	while ((err = myrecvfrom(s1, &m->imsg, sizeof(m->imsg), (struct sockaddr *)&from, &fromlen, &destAddr, packetifname, &ttl)) >= 0)
 		{
 		count++;
 		if (from.ss_family == AF_INET)
@@ -796,27 +1224,39 @@ mDNSlocal void myCFSocketCallBack(CFSocketRef cfs, CFSocketCallBackType CallBack
 			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 (!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);
+		if (mDNSAddrIsDNSMulticast(&destAddr))
+			{
+			// Even though we indicated a specific interface in the IP_ADD_MEMBERSHIP call, a weirdness of the
+			// sockets API means that even though this socket has only officially joined the multicast group
+			// on one specific interface, the kernel will still deliver multicast packets to it no matter which
+			// interface they arrive on. According to the official Unix Powers That Be, this is Not A Bug.
+			// To work around this weirdness, we use the IP_RECVIF option to find the name of the interface
+			// on which the packet arrived, and ignore the packet if it really arrived on some other interface.
+			if (!ss->info)
+				{
+				verbosedebugf("myCFSocketCallBack got multicast packet from %#a to %#a on unicast socket (Ignored)", &senderAddr, &destAddr);
+				return;
+				}
+			else if (!strcmp(ss->info->ifa_name, packetifname))
+				verbosedebugf("myCFSocketCallBack got multicast packet from %#a to %#a on interface %#a/%s",
+					&senderAddr, &destAddr, &ss->info->ifinfo.ip, ss->info->ifa_name);
+			else
+				{
+				verbosedebugf("myCFSocketCallBack got multicast packet from %#a to %#a on interface %#a/%s (Ignored -- really arrived on interface %s)",
+					&senderAddr, &destAddr, &ss->info->ifinfo.ip, ss->info->ifa_name, packetifname);
+				return;
+				}
+			}
 		else
 			{
-			verbosedebugf("myCFSocketCallBack got 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;
+			// 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;
 			}
-		
-		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, InterfaceID, ttl);
+
+		mDNSCoreReceive(m, &m->imsg, (unsigned char*)&m->imsg + err, &senderAddr, senderPort, &destAddr, destPort, InterfaceID);
 		}
 
 	if (err < 0 && (errno != EWOULDBLOCK || count == 0))
@@ -848,8 +1288,13 @@ mDNSlocal void myCFSocketCallBack(CFSocketRef cfs, CFSocketCallBackType CallBack
 		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);
+		if (numLogMessages > 5)
+			NotifyOfElusiveBug("Flaw in Kernel (select/recvfrom mismatch)", 3375328,
+				"Alternatively, you can send email to radar-3387020@group.apple.com. "
+				"If possible, please leave your machine undisturbed so that someone can come to investigate the problem.");
+
 		sleep(1);		// After logging this error, rate limit so we don't flood syslog
-		} 
+		}
 	}
 
 // TCP socket support for unicast DNS and Dynamic DNS Update
@@ -865,7 +1310,7 @@ mDNSlocal void tcpCFSocketCallback(CFSocketRef cfs, CFSocketCallBackType Callbac
 								   const void *data, void *context)
 	{
 	#pragma unused(CallbackType, address, data)
-	mDNSBool connect = mDNSfalse;  
+	mDNSBool connect = mDNSfalse;
 	
 	tcpInfo_t *info = context;
 	if (!info->connected)
@@ -874,7 +1319,7 @@ mDNSlocal void tcpCFSocketCallback(CFSocketRef cfs, CFSocketCallBackType Callbac
 		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!  
+	// NOTE: the callback may call CloseConnection here, which frees the context structure!
 	}
 
 mDNSexport mStatus mDNSPlatformTCPConnect(const mDNSAddr *dst, mDNSOpaque16 dstport, mDNSInterfaceID InterfaceID,
@@ -882,11 +1327,10 @@ mDNSexport mStatus mDNSPlatformTCPConnect(const mDNSAddr *dst, mDNSOpaque16 dstp
 	{
 	int sd, on = 1;  // "on" for setsockopt
 	struct sockaddr_in saddr;
-	CFSocketContext cfContext = { 0, NULL, 0, 0, 0 };  
+	CFSocketContext cfContext = { 0, NULL, 0, 0, 0 };
 	tcpInfo_t *info;
 	CFSocketRef sr;
 	CFRunLoopSourceRef rls;
-	CFOptionFlags srFlags;
 	
 	(void)InterfaceID;	//!!!KRS use this if non-zero!!!
 
@@ -898,11 +1342,8 @@ mDNSexport mStatus mDNSPlatformTCPConnect(const mDNSAddr *dst, mDNSOpaque16 dstp
 		}
 
 	sd = socket(AF_INET, SOCK_STREAM, 0);
-	if (sd < 0)
-		{
-		LogMsg("ERROR: socket; %s", strerror(errno));
-		return mStatus_UnknownErr;
-		}
+	if (sd < 3) { LogMsg("mDNSPlatformTCPConnect: socket error %d errno %d (%s)", sd, errno, strerror(errno)); return mStatus_UnknownErr; }
+
 	// set non-blocking
 	if (fcntl(sd, F_SETFL, O_NONBLOCK) < 0)
 		{
@@ -930,12 +1371,8 @@ mDNSexport mStatus mDNSPlatformTCPConnect(const mDNSAddr *dst, mDNSOpaque16 dstp
 		return mStatus_UnknownErr;
 		}
 
-	// prevent closing of native socket
-	srFlags = CFSocketGetSocketFlags(sr);
-	CFSocketSetSocketFlags(sr, srFlags & (~kCFSocketCloseOnInvalidate));
-	
 	rls = CFSocketCreateRunLoopSource(kCFAllocatorDefault, sr, 0);
-	if (!rls) 
+	if (!rls)
 		{
 		LogMsg("ERROR: mDNSPlatformTCPConnect - CFSocketCreateRunLoopSource failed");
 		freeL("mDNSPlatformTCPConnect", info);
@@ -956,16 +1393,16 @@ mDNSexport mStatus mDNSPlatformTCPConnect(const mDNSAddr *dst, mDNSOpaque16 dstp
 			{
 			info->connected = 0;
 			*descriptor= sd;
-			return mStatus_ConnectionPending;
+			return mStatus_ConnPending;
 			}
 		LogMsg("ERROR: mDNSPlatformTCPConnect - connect failed: %s", strerror(errno));
 		freeL("mDNSPlatformTCPConnect", info);
 		CFSocketInvalidate(sr);
-		return mStatus_ConnectionFailed;
+		return mStatus_ConnFailed;
 		}
 	info->connected = 1;
 	*descriptor = sd;
-	return mStatus_ConnectionEstablished;
+	return mStatus_ConnEstablished;
 	}
 
 mDNSexport void mDNSPlatformTCPCloseConnection(int sd)
@@ -974,13 +1411,12 @@ mDNSexport void mDNSPlatformTCPCloseConnection(int sd)
 	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;
-		}
+	if (sd < 3) LogMsg("mDNSPlatformTCPCloseConnection: ERROR sd %d < 3", sd);
+
+    // Get the CFSocket for the descriptor
+	sr = CFSocketCreateWithNative(kCFAllocatorDefault, sd, kCFSocketNoCallBack, NULL, NULL);
+	if (!sr) { LogMsg("ERROR: mDNSPlatformTCPCloseConnection - CFSocketCreateWithNative returned NULL"); return; }
+
 	CFSocketGetContext(sr, &cfContext);
 	if (!cfContext.info)
 		{
@@ -991,10 +1427,13 @@ mDNSexport void mDNSPlatformTCPCloseConnection(int sd)
 	CFRelease(sr);  // this only releases the copy we allocated with CreateWithNative above
 	
 	info = cfContext.info;
+
+	// Note: MUST NOT close the underlying native BSD socket.
+	// CFSocketInvalidate() will do that for us, in its own good time, which may not necessarily be immediately,
+	// because it first has to unhook the sockets from its select() call, before it can safely close them.
 	CFSocketInvalidate(sr);
-	CFRelease(sr);	
-	close(sd);
-	freeL("mDNSPlatformTCPCloseConnection", info);	
+	CFRelease(sr);
+	freeL("mDNSPlatformTCPCloseConnection", info);
 	}
 
 mDNSexport int mDNSPlatformReadTCP(int sd, void *buf, int buflen)
@@ -1034,8 +1473,8 @@ mDNSlocal void GetUserSpecifiedFriendlyComputerName(domainlabel *const namelabel
 		}
 	}
 
-// This gets the text of the field currently labelled "Rendezvous Name" in the Sharing Prefs Control Panel
-mDNSlocal void GetUserSpecifiedRFC1034ComputerName(domainlabel *const namelabel)
+// This gets the text of the field currently labelled "Local Hostname" in the Sharing Prefs Control Panel
+mDNSlocal void GetUserSpecifiedLocalHostName(domainlabel *const namelabel)
 	{
 	CFStringRef cfs = SCDynamicStoreCopyLocalHostName(NULL);
 	if (cfs)
@@ -1045,9 +1484,90 @@ mDNSlocal void GetUserSpecifiedRFC1034ComputerName(domainlabel *const namelabel)
 		}
 	}
 
+mDNSlocal void GetUserSpecifiedDDNSConfig(domainname *const fqdn, domainname *const regDomain, domainname *const browseDomain)
+	{
+	char buf[MAX_ESCAPED_DOMAIN_NAME];
+
+	fqdn->c[0] = 0;
+	regDomain->c[0] = 0;
+	browseDomain->c[0] = 0;
+	buf[0] = 0;
+	
+	SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:GetUserSpecifiedDDNSConfig"), NULL, NULL);
+	if (store)
+		{
+		CFDictionaryRef dict = SCDynamicStoreCopyValue(store, CFSTR("Setup:/Network/DynamicDNS"));
+		if (dict)
+			{
+			CFArrayRef fqdnArray = CFDictionaryGetValue(dict, CFSTR("FQDN"));
+			CFArrayRef regArray = CFDictionaryGetValue(dict, CFSTR("DefaultRegistrationDomain"));
+			CFArrayRef browseArray = CFDictionaryGetValue(dict, CFSTR("DefaultBrowseDomain"));
+			if (fqdnArray)
+				{
+				CFStringRef name = CFArrayGetValueAtIndex(fqdnArray, 0);
+				if (name)
+					{
+					if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) ||
+                        !MakeDomainNameFromDNSNameString(fqdn, buf) || !fqdn->c[0])
+						LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS host name: %s", buf[0] ? buf : "(unknown)");
+					else debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS host name: %s", buf);
+					}
+				}			
+			if (regArray)
+				{
+				CFStringRef name = CFArrayGetValueAtIndex(regArray, 0);
+				if (name)
+					{
+					if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) ||
+                        !MakeDomainNameFromDNSNameString(regDomain, buf) || !regDomain->c[0])
+						LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS registration domain: %s", buf[0] ? buf : "(unknown)");
+					else debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS registration zone: %s", buf);
+					}
+				}
+			if (browseArray)
+				{
+				CFStringRef name = CFArrayGetValueAtIndex(browseArray, 0);
+				if (name)
+					{
+					if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) ||
+                        !MakeDomainNameFromDNSNameString(browseDomain, buf) || !browseDomain->c[0])
+						LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS browse domain: %s", buf[0] ? buf : "(unknown)");
+					else debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS browse zone: %s", buf);
+					}
+				}			
+			CFRelease(dict);
+			}
+		CFRelease(store);
+		}
+	}
+
+mDNSlocal void SetDDNSNameStatus(domainname *const dname, mStatus status)
+	{
+	SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:SetDDNSNameStatus"), NULL, NULL);
+	if (store)
+		{
+		char uname[MAX_ESCAPED_DOMAIN_NAME];
+		ConvertDomainNameToCString(dname, uname);
+		char *p = uname;
+		while (*p) { *p = tolower(*p); p++; }
+		const void *n1 = CFStringCreateWithCString(NULL, uname, kCFStringEncodingUTF8); // CFStringRef
+		const void *v1 = CFNumberCreate(NULL, kCFNumberSInt32Type, &status); // CFNumberRef
+		const void *n2 = CFSTR("FQDN"); // CFStringRef
+		const void *v2 = CFDictionaryCreate(NULL, &n1, &v1, 1, NULL, NULL); // CFDictionaryRef
+		CFDictionaryRef dict = CFDictionaryCreate(NULL, &n2, &v2, 1, NULL, NULL);
+		SCDynamicStoreSetValue(store, CFSTR("State:/Network/DynamicDNS"), dict);
+		CFRelease(dict);
+		CFRelease(v2);
+		CFRelease(n2);
+		CFRelease(v1);
+		CFRelease(n1);
+		CFRelease(store);
+		}
+	}
+
 // 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)
+mDNSlocal mStatus SetupSocket(mDNS *const m, CFSocketSet *cp, mDNSBool mcast, 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;
@@ -1057,12 +1577,14 @@ mDNSlocal mStatus SetupSocket(CFSocketSet *cp, mDNSIPPort port, const mDNSAddr *
 	mStatus err = mStatus_NoError;
 	char *errstr = mDNSNULL;
 
+	mDNSIPPort port = (mcast | m->CanReceiveUnicastOn5353) ? MulticastDNSPort : zeroIPPort;
+
 	if (*s >= 0) { LogMsg("SetupSocket ERROR: socket %d is already set", *s); return(-1); }
 	if (*c) { LogMsg("SetupSocket ERROR: CFSocketRef %p is already set", *c); return(-1); }
 
 	// Open the socket...
 	int skt = socket(sa_family, SOCK_DGRAM, IPPROTO_UDP);
-	if (skt < 0) { LogMsg("socket error %d errno %d (%s)", skt, errno, strerror(errno)); return(skt); }
+	if (skt < 3) { LogMsg("SetupSocket: socket error %d errno %d (%s)", skt, errno, strerror(errno)); return(skt); }
 
 	// ... with a shared UDP port, if it's for multicast receiving
 	if (port.NotAnInteger) err = setsockopt(skt, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on));
@@ -1083,11 +1605,11 @@ mDNSlocal mStatus SetupSocket(CFSocketSet *cp, mDNSIPPort port, const mDNSAddr *
 		// We ignore errors here -- we already know Jaguar doesn't support this, but we can get by without it
 		
 		// Add multicast group membership on this interface, if it's for multicast receiving
-		if (port.NotAnInteger)
+		if (mcast)
 			{
 			struct in_addr addr = { ifaddr->ip.v4.NotAnInteger };
 			struct ip_mreq imr;
-			imr.imr_multiaddr.s_addr = AllDNSLinkGroup.NotAnInteger;
+			imr.imr_multiaddr.s_addr = AllDNSLinkGroupv4.NotAnInteger;
 			imr.imr_interface        = addr;
 			err = setsockopt(skt, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(imr));
 			if (err < 0) { errstr = "setsockopt - IP_ADD_MEMBERSHIP"; goto fail; }
@@ -1133,7 +1655,7 @@ mDNSlocal mStatus SetupSocket(CFSocketSet *cp, mDNSIPPort port, const mDNSAddr *
 		err = setsockopt(skt, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
 		if (err < 0) { errstr = "setsockopt - IPV6_V6ONLY"; goto fail; }
 		
-		if (port.NotAnInteger)
+		if (mcast)
 			{
 			// Add multicast group membership on this interface, if it's for multicast receiving
 			int interface_id = if_nametoindex(cp->info->ifa_name);
@@ -1192,64 +1714,101 @@ mDNSlocal mStatus SetupSocket(CFSocketSet *cp, mDNSIPPort port, const mDNSAddr *
 
 fail:
 	LogMsg("%s error %ld errno %d (%s)", errstr, err, errno, strerror(errno));
+	if (!strcmp(errstr, "bind") && errno == EADDRINUSE)
+		NotifyOfElusiveBug("Setsockopt SO_REUSEPORT failed", 3814904,
+			"Alternatively, you can send email to radar-3387020@group.apple.com. "
+			"If possible, please leave your machine undisturbed so that someone can come to investigate the problem.");
 	close(skt);
 	return(err);
 	}
 
 mDNSlocal mStatus SetupAddr(mDNSAddr *ip, const struct sockaddr *const sa)
 	{
+	if (!sa) { LogMsg("SetupAddr ERROR: NULL sockaddr"); return(mStatus_Invalid); }
+
 	if (sa->sa_family == AF_INET)
 		{
 		struct sockaddr_in *ifa_addr = (struct sockaddr_in *)sa;
 		ip->type = mDNSAddrType_IPv4;
 		ip->ip.v4.NotAnInteger = ifa_addr->sin_addr.s_addr;
-		return(0);
+		return(mStatus_NoError);
 		}
-	else if (sa->sa_family == AF_INET6)
+
+	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);
+		return(mStatus_NoError);
 		}
-	else
+
+	LogMsg("SetupAddr invalid sa_family %d", sa->sa_family);
+	return(mStatus_Invalid);
+	}
+
+mDNSlocal mDNSEthAddr GetBSSID(char *ifa_name)
+	{
+	mDNSEthAddr eth = zeroEthAddr;
+	SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:GetBSSID"), NULL, NULL);
+	if (store)
 		{
-		LogMsg("SetupAddr invalid sa_family %d", sa->sa_family);
-		return(-1);
+		CFStringRef entityname = CFStringCreateWithFormat(NULL, NULL, CFSTR("State:/Network/Interface/%s/AirPort"), ifa_name);
+		if (entityname)
+			{
+			CFDictionaryRef dict = SCDynamicStoreCopyValue(store, entityname);
+			if (dict)
+				{
+				CFRange range = { 0, 6 };		// Offset, length
+				CFDataRef data = CFDictionaryGetValue(dict, CFSTR("BSSID"));
+				if (data && CFDataGetLength(data) == 6) CFDataGetBytes(data, range, eth.b);
+				CFRelease(dict);
+				}
+			CFRelease(entityname);
+			}
+		CFRelease(store);
 		}
+	return(eth);
 	}
 
 mDNSlocal NetworkInterfaceInfoOSX *AddInterfaceToList(mDNS *const m, struct ifaddrs *ifa)
 	{
-	mDNSu32 scope_id = if_nametoindex(ifa->ifa_name);
-	mDNSAddr ip;
-	SetupAddr(&ip, ifa->ifa_addr);
+	mDNSu32 scope_id  = if_nametoindex(ifa->ifa_name);
+	mDNSEthAddr bssid = GetBSSID(ifa->ifa_name);
+
+	mDNSAddr ip, mask;
+	if (SetupAddr(&ip,   ifa->ifa_addr   ) != mStatus_NoError) return(NULL);
+	if (SetupAddr(&mask, ifa->ifa_netmask) != mStatus_NoError) return(NULL);
+
 	NetworkInterfaceInfoOSX **p;
 	for (p = &m->p->InterfaceList; *p; p = &(*p)->next)
-		if (scope_id == (*p)->scope_id && mDNSSameAddress(&ip, &(*p)->ifinfo.ip))
+		if (scope_id == (*p)->scope_id && mDNSSameAddress(&ip, &(*p)->ifinfo.ip) && mDNSSameEthAddress(&bssid, &(*p)->BSSID))
 			{
-			debugf("AddInterfaceToList: Found existing interface %u with address %#a", scope_id, &ip);
+			debugf("AddInterfaceToList: Found existing interface %lu %.6a with address %#a at %p", scope_id, &bssid, &ip, *p);
 			(*p)->Exists = mDNStrue;
 			return(*p);
 			}
 
-	debugf("AddInterfaceToList: Making   new   interface %u with address %#a", scope_id, &ip);
 	NetworkInterfaceInfoOSX *i = (NetworkInterfaceInfoOSX *)mallocL("NetworkInterfaceInfoOSX", sizeof(*i));
+	debugf("AddInterfaceToList: Making   new   interface %lu %.6a with address %#a at %p", scope_id, &bssid, &ip, i);
 	if (!i) return(mDNSNULL);
+	bzero(i, sizeof(NetworkInterfaceInfoOSX));
 	i->ifa_name        = (char *)mallocL("NetworkInterfaceInfoOSX name", strlen(ifa->ifa_name) + 1);
 	if (!i->ifa_name) { freeL("NetworkInterfaceInfoOSX", i); return(mDNSNULL); }
 	strcpy(i->ifa_name, ifa->ifa_name);
 
-	bzero(&i->ifinfo.uDNS_info, sizeof(uDNS_NetworkInterfaceInfo));
 	i->ifinfo.InterfaceID = mDNSNULL;
 	i->ifinfo.ip          = ip;
+	i->ifinfo.mask        = mask;
+	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.McastTxRx   = mDNSfalse; // For now; will be set up later at the end of UpdateInterfaceList
 	
 	i->next            = mDNSNULL;
 	i->Exists          = mDNStrue;
 	i->scope_id        = scope_id;
+	i->BSSID           = bssid;
 	i->sa_family       = ifa->ifa_addr->sa_family;
 	i->Multicast       = (ifa->ifa_flags & IFF_MULTICAST) && !(ifa->ifa_flags & IFF_POINTOPOINT);
 
@@ -1276,94 +1835,100 @@ mDNSlocal NetworkInterfaceInfoOSX *FindRoutableIPv4(mDNS *const m, mDNSu32 scope
 mDNSlocal mStatus UpdateInterfaceList(mDNS *const m)
 	{
 	mDNSBool foundav4           = mDNSfalse;
+	mDNSBool foundav6           = 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);
-		if (mDNS_DNSRegistered(m)) mDNS_GenerateGlobalFQDN(m);
-		}
+	struct ifaddrs *v4Loopback  = NULL;
+	struct ifaddrs *v6Loopback  = NULL;
+	mDNSEthAddr PrimaryMAC      = zeroEthAddr;
+	char defaultname[32];
+	int InfoSocket              = socket(AF_INET6, SOCK_DGRAM, 0);
+	if (InfoSocket < 3) LogMsg("UpdateInterfaceList: InfoSocket error %d errno %d (%s)", InfoSocket, errno, strerror(errno));
+	if (m->SleepState) ifa = NULL;
 
 	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",
+			debugf("UpdateInterfaceList: %5s(%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",
+			debugf("UpdateInterfaceList: %5s(%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)",
+			debugf("UpdateInterfaceList: %5s(%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",
+			debugf("UpdateInterfaceList: %5s(%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",
+			debugf("UpdateInterfaceList: %5s(%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",
+			debugf("UpdateInterfaceList: %5s(%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",
+			debugf("UpdateInterfaceList: %5s(%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_flags & IFF_UP)
+
+		if (ifa->ifa_addr->sa_family == AF_LINK)
+			{
+			struct sockaddr_dl *sdl = (struct sockaddr_dl *)ifa->ifa_addr;
+			if (sdl->sdl_type == IFT_ETHER && sdl->sdl_alen == sizeof(PrimaryMAC) && mDNSSameEthAddress(&PrimaryMAC, &zeroEthAddr))
+				mDNSPlatformMemCopy(sdl->sdl_data + sdl->sdl_nlen, PrimaryMAC.b, 6);
+			}
+
+		if (ifa->ifa_flags & IFF_UP && ifa->ifa_addr)
 			if (ifa->ifa_addr->sa_family == AF_INET || ifa->ifa_addr->sa_family == AF_INET6)
 				{
-				int ifru_flags6 = 0;
-				if (ifa->ifa_addr->sa_family == AF_INET6 && InfoSocket >= 0)
+				if (!ifa->ifa_netmask)
+					{
+					mDNSAddr ip;
+					SetupAddr(&ip, ifa->ifa_addr);
+					LogMsg("getifaddrs: ifa_netmask is NULL for %5s(%d) Flags %04X Family %2d %#a",
+						ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family, &ip);
+					}
+				else if (ifa->ifa_addr->sa_family != ifa->ifa_netmask->sa_family)
 					{
-					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);
+					mDNSAddr ip;
+					SetupAddr(&ip, ifa->ifa_addr);
+					LogMsg("getifaddrs ifa_netmask for %5s(%d) Flags %04X Family %2d %#a has different family: %d",
+						ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family, &ip, ifa->ifa_netmask->sa_family);
 					}
-				if (!(ifru_flags6 & (IN6_IFF_NOTREADY | IN6_IFF_DETACHED | IN6_IFF_DEPRECATED | IN6_IFF_TEMPORARY)))
+				else
 					{
-					if (ifa->ifa_flags & IFF_LOOPBACK)
-						theLoopback = ifa;
-					else
+					int ifru_flags6 = 0;
+					if (ifa->ifa_addr->sa_family == AF_INET6 && InfoSocket >= 0)
 						{
-						AddInterfaceToList(m, ifa);
-						if (ifa->ifa_addr->sa_family == AF_INET)
-							foundav4 = mDNStrue;
+						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)
+							if (ifa->ifa_addr->sa_family == AF_INET) v4Loopback = ifa;
+							else                                     v6Loopback = ifa;
+						else
+							{
+							AddInterfaceToList(m, ifa);
+							if (ifa->ifa_addr->sa_family == AF_INET) foundav4 = mDNStrue;
+							else                                     foundav6 = 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);
+    // For efficiency, we don't register a loopback interface when other interfaces of that family are available
+	if (!foundav4 && v4Loopback) AddInterfaceToList(m, v4Loopback);
+	if (!foundav6 && v6Loopback) AddInterfaceToList(m, v6Loopback);
 
 	// Now the list is complete, set the McastTxRx setting for each interface.
 	// We always send and receive using IPv4.
@@ -1384,25 +1949,48 @@ mDNSlocal mStatus UpdateInterfaceList(mDNS *const m)
 				i->Exists = 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 (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);
-	return(NULL);
+	mDNS_snprintf(defaultname, sizeof(defaultname), "Macintosh-%02X%02X%02X%02X%02X%02X",
+		PrimaryMAC.b[0], PrimaryMAC.b[1], PrimaryMAC.b[2], PrimaryMAC.b[3], PrimaryMAC.b[4], PrimaryMAC.b[5]);
+
+	// Set up the nice label
+	domainlabel nicelabel;
+	nicelabel.c[0] = 0;
+	GetUserSpecifiedFriendlyComputerName(&nicelabel);
+	if (nicelabel.c[0] == 0) MakeDomainLabelFromLiteralString(&nicelabel, defaultname);
+
+	// Set up the RFC 1034-compliant label
+	domainlabel hostlabel;
+	hostlabel.c[0] = 0;
+	GetUserSpecifiedLocalHostName(&hostlabel);
+	if (hostlabel.c[0] == 0) MakeDomainLabelFromLiteralString(&hostlabel, defaultname);
+
+	if (SameDomainLabel(m->p->usernicelabel.c, nicelabel.c))
+		debugf("Usernicelabel (%#s) unchanged since last time; not changing m->nicelabel (%#s)", m->p->usernicelabel.c, m->nicelabel.c);
+	else
+		{
+		debugf("Updating m->nicelabel to %#s", nicelabel.c);
+		m->p->usernicelabel = m->nicelabel = nicelabel;
+		}
+
+	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_SetFQDN(m);
+		}
+
+	return(mStatus_NoError);
 	}
 
-mDNSlocal void SetupActiveInterfaces(mDNS *const m)
+// returns count of non-link local V4 addresses registered
+mDNSlocal int SetupActiveInterfaces(mDNS *const m)
 	{
 	NetworkInterfaceInfoOSX *i;
+	int count = 0;
 	for (i = m->p->InterfaceList; i; i = i->next)
 		if (i->Exists)
 			{
@@ -1423,29 +2011,31 @@ mDNSlocal void SetupActiveInterfaces(mDNS *const m)
 				// 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);
-				LogOperation("SetupActiveInterfaces: Registered  %s(%lu) InterfaceID %p %#a%s",
-					i->ifa_name, i->scope_id, primary, &n->ip, n->InterfaceActive ? " (Primary)" : "");
+				if (i->ifinfo.ip.type == mDNSAddrType_IPv4 &&  (i->ifinfo.ip.ip.v4.b[0] != 169 || i->ifinfo.ip.ip.v4.b[1] != 254)) count++;
+				LogOperation("SetupActiveInterfaces:   Registered    %5s(%lu) %.6a InterfaceID %p %#a/%#a%s",
+					i->ifa_name, i->scope_id, &i->BSSID, primary, &n->ip, &n->mask, n->InterfaceActive ? " (Primary)" : "");
 				}
 	
 			if (!n->McastTxRx)
-				debugf("SetupActiveInterfaces: No Tx/Rx on %s(%lu) InterfaceID %p %#a", i->ifa_name, i->scope_id, primary, &n->ip);
+				debugf("SetupActiveInterfaces:   No Tx/Rx on   %5s(%lu) %.6a InterfaceID %p %#a", i->ifa_name, i->scope_id, &i->BSSID, primary, &n->ip);
 			else
 				{
 				if (i->sa_family == AF_INET && primary->ss.sktv4 == -1)
 					{
-					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);
+					mStatus err = SetupSocket(m, &primary->ss, mDNStrue, &i->ifinfo.ip, AF_INET);
+					if (err == 0) debugf("SetupActiveInterfaces:   v4 socket%2d %5s(%lu) %.6a InterfaceID %p %#a",          primary->ss.sktv4, i->ifa_name, i->scope_id, &i->BSSID, n->InterfaceID, &n->ip);
+					else          LogMsg("SetupActiveInterfaces:   v4 socket%2d %5s(%lu) %.6a InterfaceID %p %#a FAILED",   primary->ss.sktv4, i->ifa_name, i->scope_id, &i->BSSID, n->InterfaceID, &n->ip);
 					}
 			
 				if (i->sa_family == AF_INET6 && primary->ss.sktv6 == -1)
 					{
-					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);
+					mStatus err = SetupSocket(m, &primary->ss, mDNStrue, &i->ifinfo.ip, AF_INET6);
+					if (err == 0) debugf("SetupActiveInterfaces:   v6 socket%2d %5s(%lu) %.6a InterfaceID %p %#a",          primary->ss.sktv6, i->ifa_name, i->scope_id, &i->BSSID, n->InterfaceID, &n->ip);
+					else          LogMsg("SetupActiveInterfaces:   v6 socket%2d %5s(%lu) %.6a InterfaceID %p %#a FAILED",   primary->ss.sktv6, i->ifa_name, i->scope_id, &i->BSSID, n->InterfaceID, &n->ip);
 					}
 				}
 			}
+	return count;
 	}
 
 mDNSlocal void MarkAllInterfacesInactive(mDNS *const m)
@@ -1455,19 +2045,29 @@ mDNSlocal void MarkAllInterfacesInactive(mDNS *const m)
 		i->Exists = mDNSfalse;
 	}
 
+mDNSlocal void CloseRunLoopSourceSocket(CFRunLoopSourceRef rls, CFSocketRef cfs)
+	{
+	// Comments show retain counts (obtained via CFGetRetainCount()) after each call.	   rls 3 cfs 3
+	CFRunLoopRemoveSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);			// rls 2 cfs 3
+	CFRelease(rls);																		// rls ? cfs 3
+	CFSocketInvalidate(cfs);															// rls ? cfs 1
+	CFRelease(cfs);																		// rls ? cfs ?
+	}
+
 mDNSlocal void CloseSocketSet(CFSocketSet *ss)
 	{
 	// Note: MUST NOT close the underlying native BSD sockets.
 	// CFSocketInvalidate() will do that for us, in its own good time, which may not necessarily be immediately,
 	// because it first has to unhook the sockets from its select() call, before it can safely close them.
-	if (ss->cfsv4) { 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); }
+	if (ss->cfsv4) CloseRunLoopSourceSocket(ss->rlsv4, ss->cfsv4);
+	if (ss->cfsv6) CloseRunLoopSourceSocket(ss->rlsv6, ss->cfsv6);
 	ss->sktv4 = ss->sktv6 = -1;
 	ss->cfsv4 = ss->cfsv6 = NULL;
 	ss->rlsv4 = ss->rlsv6 = NULL;
 	}
 
-mDNSlocal void ClearInactiveInterfaces(mDNS *const m)
+// returns count of non-link local V4 addresses deregistered
+mDNSlocal int ClearInactiveInterfaces(mDNS *const m)
 	{
 	// First pass:
 	// If an interface is going away, then deregister this from the mDNSCore.
@@ -1477,6 +2077,7 @@ mDNSlocal void ClearInactiveInterfaces(mDNS *const m)
 	// 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;
+	int count = 0;
 	for (i = m->p->InterfaceList; i; i = i->next)
 		{
 		// 1. If this interface is no longer active, or its InterfaceID is changing, deregister it
@@ -1484,9 +2085,10 @@ mDNSlocal void ClearInactiveInterfaces(mDNS *const m)
 		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)" : "");
+				LogOperation("ClearInactiveInterfaces: Deregistering %5s(%lu) %.6a InterfaceID %p %#a%s",
+					i->ifa_name, i->scope_id, &i->BSSID, i->ifinfo.InterfaceID, &i->ifinfo.ip, i->ifinfo.InterfaceActive ? " (Primary)" : "");
 				mDNS_DeregisterInterface(m, &i->ifinfo);
+				if (i->ifinfo.ip.type == mDNSAddrType_IPv4 &&  (i->ifinfo.ip.ip.v4.b[0] != 169 || i->ifinfo.ip.ip.v4.b[1] != 254)) count++;
 				i->ifinfo.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.
@@ -1514,19 +2116,89 @@ mDNSlocal void ClearInactiveInterfaces(mDNS *const m)
 		else
 			p = &i->next;
 		}
+	return count;
 	}
 
+mDNSlocal mStatus RegisterSplitDNS(mDNS *m)
+	{
+#ifndef MAC_OS_X_VERSION_10_4
+	static int MessageShown = 0;
+	(void)m;
+	if (!MessageShown) { MessageShown = 1; LogMsg("Note: Compiled without Apple-specific split DNS support"); }
+    return mStatus_UnsupportedErr;
+#else
+	int i;
+	dns_config_t *config = dns_configuration_copy();
+
+	if (!config)
+		{
+		// When running on 10.3 (build 7xxx) and earlier, we don't expect dns_configuration_copy() to succeed
+		if (mDNSMacOSXSystemBuildNumber(NULL) < 8) return mStatus_UnsupportedErr;
+
+		// On 10.4, calls to dns_configuration_copy() early in the boot process often fail.
+		// Apparently this is expected behaviour -- "not a bug".
+		// Accordingly, we suppress syslog messages for the first three minutes after boot.
+		// If we are still getting failures after three minutes, then we log them.
+		if ((mDNSu32)(mDNSPlatformRawTime()) < (mDNSu32)(mDNSPlatformOneSecond * 180)) return mStatus_UnknownErr;
+
+		LogMsg("RegisterSplitDNS: Error: dns_configuration_copy returned NULL");
+		return mStatus_UnknownErr;
+		}
+	mDNS_DeleteDNSServers(m);
+
+	LogOperation("RegisterSplitDNS: Registering %d resolvers", config->n_resolver);
+	for (i = 0; i < config->n_resolver; i++)		
+		{
+		int j, n;
+		domainname d;
+		dns_resolver_t *r = config->resolver[i];
+		if (r->port == MulticastDNSPort.NotAnInteger) continue; // ignore configurations for .local
+		if (r->search_order == DEFAULT_SEARCH_ORDER || !r->domain || !*r->domain) d.c[0] = 0; // we ignore domain for "default" resolver
+		else if (!MakeDomainNameFromDNSNameString(&d, r->domain)) { LogMsg("RegisterSplitDNS: bad domain %s", r->domain); continue; }
+
+		// check if this is the lowest-weighted server for the domain
+		for (j = 0; j < config->n_resolver; j++)
+			{
+			dns_resolver_t *p = config->resolver[j];
+			if (p->port == MulticastDNSPort.NotAnInteger) continue;
+			if (p->search_order <= r->search_order)
+				{
+				domainname tmp;				
+				if (p->search_order == DEFAULT_SEARCH_ORDER || !p->domain || !*p->domain) tmp.c[0] = '\0';
+				else if (!MakeDomainNameFromDNSNameString(&tmp, p->domain)) { LogMsg("RegisterSplitDNS: bad domain %s", p->domain); continue; }
+				if (SameDomainName(&d, &tmp))
+					if (p->search_order < r->search_order || j < i) break;  // if equal weights, pick first in list, otherwise pick lower-weight (p)
+				}
+			}
+		if (j < config->n_resolver) // found a lower-weighted resolver for this domain
+			{ debugf("Rejecting DNS server in slot %d domain %##s (slot %d outranks)", i, d.c, j); continue; }
+		// we're using this resolver - find the first IPv4 address
+		for (n = 0; n < r->n_nameserver; n++)
+			{
+			if (r->nameserver[n]->sa_family == AF_INET)
+				{
+				mDNSAddr saddr;
+				if (SetupAddr(&saddr, r->nameserver[n])) { LogMsg("RegisterSplitDNS: bad IP address"); continue; }
+				debugf("Adding dns server from slot %d %d.%d.%d.%d for domain %##s", i, saddr.ip.v4.b[0], saddr.ip.v4.b[1], saddr.ip.v4.b[2], saddr.ip.v4.b[3], d.c);
+				mDNS_AddDNSServer(m, &saddr, &d);
+				break;  // !!!KRS if we ever support round-robin servers, don't break here
+				}
+			}
+		}
+	dns_configuration_free(config);
+	return mStatus_NoError;
+#endif	
+	}
 
 mDNSlocal mStatus RegisterNameServers(mDNS *const m, CFDictionaryRef dict)
 	{
 	int i, count;
 	CFArrayRef values;
-	char            buf[256];
-	mDNSv4Addr      saddr;	
+	char buf[256];
+	mDNSAddr saddr = { mDNSAddrType_IPv4, { { { 0 } } } };
 	CFStringRef s;
 
-
-	mDNS_DeregisterDNSList(m); // deregister orig list
+	mDNS_DeleteDNSServers(m); // deregister orig list
 	values = CFDictionaryGetValue(dict, kSCPropNetDNSServerAddresses);
 	if (!values) return mStatus_NoError;
 
@@ -1535,17 +2207,18 @@ mDNSlocal mStatus RegisterNameServers(mDNS *const m, CFDictionaryRef dict)
 		{
 		s = CFArrayGetValueAtIndex(values, i);
 		if (!s) { LogMsg("ERROR: RegisterNameServers - CFArrayGetValueAtIndex"); break; }
-		if (!CFStringGetCString(s, buf, 256, kCFStringEncodingASCII))
+		if (!CFStringGetCString(s, buf, 256, kCFStringEncodingUTF8))
 			{
 			LogMsg("ERROR: RegisterNameServers - CFStringGetCString");
 			continue;
 			}
-		if (!inet_aton(buf, (struct in_addr *)saddr.b))
+		if (!inet_aton(buf, (struct in_addr *)saddr.ip.v4.b))
 			{
 			LogMsg("ERROR: RegisterNameServers - invalid address string %s", buf);
 			continue;
 			}
-		mDNS_RegisterDNS(m, &saddr);
+		LogOperation("RegisterNameServers: Adding %#a", &saddr);
+		mDNS_AddDNSServer(m, &saddr, NULL);
 		}
 	return mStatus_NoError;
 	}
@@ -1553,32 +2226,37 @@ mDNSlocal mStatus RegisterNameServers(mDNS *const m, CFDictionaryRef dict)
 mDNSlocal void FreeARElemCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
 	{
 	(void)m;  // unused
-	AuthRecordListElem *elem = rr->RecordContext;
+	ARListElem *elem = rr->RecordContext;
 	if (result == mStatus_MemFree) freeL("FreeARElemCallback", elem);
 	}
 
-mDNSlocal void FoundDomain(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)	
+mDNSlocal void FoundDomain(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
 	{
 	SearchListElem *slElem = question->QuestionContext;
-	AuthRecordListElem *arElem, *ptr, *prev;
-    AuthRecord *dereg;    
+	ARListElem *arElem, *ptr, *prev;
+    AuthRecord *dereg;
 	char *name;
 	mStatus err;
 	
 	if (AddRecord)
 		{
-		arElem = mallocL("FoundDomain - arElem", sizeof(AuthRecordListElem));
+		arElem = mallocL("FoundDomain - arElem", sizeof(ARListElem));
 		if (!arElem) { LogMsg("ERROR: malloc");  return; }
 		mDNS_SetupResourceRecord(&arElem->ar, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, 7200,  kDNSRecordTypeShared, FreeARElemCallback, arElem);
-		if (question == &slElem->browseQ) name = "_browse._dns-sd._udp.local.";
-		else                              name = "_register._dns-sd._udp.local.";
+		if      (question == &slElem->BrowseQ)       name = "_browse._dns-sd._udp.local.";
+		else if (question == &slElem->DefBrowseQ)    name = "_default._browse._dns-sd._udp.local.";
+		else if (question == &slElem->LegacyBrowseQ) name = "_legacy._browse._dns-sd._udp.local.";
+		else if (question == &slElem->RegisterQ)     name = "_register._dns-sd._udp.local.";
+		else if (question == &slElem->DefRegisterQ)  name = "_default._register._dns-sd._udp.local.";
+		else { LogMsg("FoundDomain - unknown question"); return; }
+		
 		MakeDomainNameFromDNSNameString(&arElem->ar.resrec.name, name);
-		strcpy(arElem->ar.resrec.rdata->u.name.c, answer->rdata->u.name.c);
+		AssignDomainName(arElem->ar.resrec.rdata->u.name, answer->rdata->u.name);
 		err = mDNS_Register(m, &arElem->ar);
 		if (err)
 			{
 			LogMsg("ERROR: FoundDomain - mDNS_Register returned %d", err);
-			freeL("FoundDomain - arElem", arElem);				  
+			freeL("FoundDomain - arElem", arElem);
 			return;
 			}
 		arElem->next = slElem->AuthRecs;
@@ -1590,14 +2268,14 @@ mDNSlocal void FoundDomain(mDNS *const m, DNSQuestion *question, const ResourceR
 		prev = NULL;
 		while (ptr)
 			{
-			if (SameDomainName(&ptr->ar.resrec.name, &answer->name) && SameDomainName(&ptr->ar.resrec.rdata->u.name, &answer->rdata->u.name))
+			if (SameDomainName(&ptr->ar.resrec.rdata->u.name, &answer->rdata->u.name))
 				{
 				debugf("Deregistering PTR %s -> %s", ptr->ar.resrec.name.c, ptr->ar.resrec.rdata->u.name.c);
                 dereg = &ptr->ar;
 				if (prev) prev->next = ptr->next;
 				else slElem->AuthRecs = ptr->next;
                 ptr = ptr->next;
-				err = mDNS_Deregister(m, dereg);				
+				err = mDNS_Deregister(m, dereg);
 				if (err) LogMsg("ERROR: FoundDomain - mDNS_Deregister returned %d", err);
 				}
 			else
@@ -1609,65 +2287,119 @@ mDNSlocal void FoundDomain(mDNS *const m, DNSQuestion *question, const ResourceR
 		}
 	}
 
+mDNSlocal void MarkSearchListElem(domainname *domain)
+	{
+	SearchListElem *new, *ptr;
+	
+	// if domain is in list, mark as pre-existent (0)
+	for (ptr = SearchList; ptr; ptr = ptr->next)
+		if (SameDomainName(&ptr->domain, domain))
+			{
+			if (ptr->flag != 1) ptr->flag = 0;  // gracefully handle duplicates - if it is already marked as add, don't bump down to preexistent
+			break;
+			}
+	
+	// if domain not in list, add to list, mark as add (1)
+	if (!ptr)
+		{
+		new = mallocL("MarkSearchListElem - SearchListElem", sizeof(SearchListElem));
+		if (!new) { LogMsg("ERROR: MarkSearchListElem - malloc"); return; }
+		bzero(new, sizeof(SearchListElem));
+		AssignDomainName(new->domain, *domain);
+		new->flag = 1;  // add
+		new->next = SearchList;
+		SearchList = new;
+		}
+	}
+
 mDNSlocal mStatus RegisterSearchDomains(mDNS *const m, CFDictionaryRef dict)
 	{
+	struct ifaddrs *ifa = NULL;
 	int i, count;
-	CFArrayRef values;
 	domainname domain;
-	char            buf[MAX_ESCAPED_DOMAIN_NAME];
+	char  buf[MAX_ESCAPED_DOMAIN_NAME];
 	CFStringRef s;
-	SearchListElem *new, *ptr, *prev, *freeSLPtr;
-	AuthRecordListElem *arList;
+	SearchListElem *ptr, *prev, *freeSLPtr;
+	ARListElem *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)
+	// step 1: mark each elem for removal (-1), unless we aren't passed a dictionary in which case we mark as preexistent
+	for (ptr = SearchList; ptr; ptr = ptr->next) ptr->flag = dict ? -1 : 0;
+
+	// get all the domains from "Search Domains" field of sharing prefs
+	if (dict)
 		{
-		count = CFArrayGetCount(values);
-		for (i = 0; i < count; i++)
+		CFArrayRef searchdomains = CFDictionaryGetValue(dict, kSCPropNetDNSSearchDomains);
+		if (searchdomains)
 			{
-			s = CFArrayGetValueAtIndex(values, i);
-			if (!s) { LogMsg("ERROR: RegisterNameServers - CFArrayGetValueAtIndex"); break; }
-			if (!CFStringGetCString(s, buf, MAX_ESCAPED_DOMAIN_NAME, kCFStringEncodingASCII))
+			count = CFArrayGetCount(searchdomains);
+			for (i = 0; i < count; i++)
 				{
-				LogMsg("ERROR: RegisterNameServers - CFStringGetCString");
-				continue;
-				}		   			
-			if (!MakeDomainNameFromDNSNameString(&domain, buf))
+				s = CFArrayGetValueAtIndex(searchdomains, i);
+				if (!s) { LogMsg("ERROR: RegisterSearchDomains - CFArrayGetValueAtIndex"); break; }
+				if (!CFStringGetCString(s, buf, MAX_ESCAPED_DOMAIN_NAME, kCFStringEncodingUTF8))
+					{
+					LogMsg("ERROR: RegisterSearchDomains - CFStringGetCString");
+					continue;
+					}
+				if (!MakeDomainNameFromDNSNameString(&domain, buf))
+					{
+					LogMsg("ERROR: RegisterSearchDomains - invalid search domain %s", buf);
+					continue;
+					}
+				MarkSearchListElem(&domain);
+				}
+			}
+		CFStringRef dname = CFDictionaryGetValue(dict, kSCPropNetDNSDomainName);
+		if (dname)
+			{
+			if (CFStringGetCString(dname, buf, MAX_ESCAPED_DOMAIN_NAME, kCFStringEncodingUTF8))
 				{
-				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)
+				if (MakeDomainNameFromDNSNameString(&domain, buf)) MarkSearchListElem(&domain);
+				else LogMsg("ERROR: RegisterSearchDomains - invalid domain %s", buf);
+				}
+			else LogMsg("ERROR: RegisterSearchDomains - CFStringGetCString");
+			}
+		}
+	
+	// Construct reverse-map search domains
+	ifa = myGetIfAddrs(1);
+	while (ifa)
+		{
+		mDNSAddr addr;
+		if (ifa->ifa_addr->sa_family == AF_INET && !SetupAddr(&addr, ifa->ifa_addr) && !IsPrivateV4Addr(&addr) && !(ifa->ifa_flags & IFF_LOOPBACK) && ifa->ifa_netmask)
+			{
+			mDNSAddr netmask;
+			char buffer[256];
+			if (!SetupAddr(&netmask, ifa->ifa_netmask))
 				{
-				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;
+				sprintf(buffer, "%d.%d.%d.%d.in-addr.arpa.", addr.ip.v4.b[3] & netmask.ip.v4.b[3],
+                                                             addr.ip.v4.b[2] & netmask.ip.v4.b[2],
+                                                             addr.ip.v4.b[1] & netmask.ip.v4.b[1],
+                                                             addr.ip.v4.b[0] & netmask.ip.v4.b[0]);
+				MakeDomainNameFromDNSNameString(&domain, buffer);
+				MarkSearchListElem(&domain);
 				}
 			}
+		ifa = ifa->ifa_next;
 		}
+
+	if (DynDNSRegDomain.c[0]) MarkSearchListElem(&DynDNSRegDomain);         // implicitly browse reg domain too (no-op if same as BrowseDomain)
+	
 	// 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
+			{
+			mDNS_StopQuery(m, &ptr->BrowseQ);
+			mDNS_StopQuery(m, &ptr->RegisterQ);
+			mDNS_StopQuery(m, &ptr->DefBrowseQ);
+			mDNS_StopQuery(m, &ptr->DefRegisterQ);
+			mDNS_StopQuery(m, &ptr->LegacyBrowseQ);			
+			
+            // deregister records generated from answers to the query
 			arList = ptr->AuthRecs;
 			ptr->AuthRecs = NULL;
 			while (arList)
@@ -1679,151 +2411,271 @@ mDNSlocal mStatus RegisterSearchDomains(mDNS *const m, CFDictionaryRef dict)
 				if (err) LogMsg("ERROR: RegisterSearchDomains mDNS_Deregister returned %d", err);
 				}
 			
-			// remove elem from list, delete				
+			// remove elem from list, delete
 			if (prev) prev->next = ptr->next;
 			else SearchList = ptr->next;
 			freeSLPtr = ptr;
 			ptr = ptr->next;
-			freeL("RegisterNameServers - freeSLPtr", freeSLPtr);
+			freeL("RegisterSearchDomains - 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);
+			mStatus err1, err2, err3, err4, err5;
+			err1 = mDNS_GetDomains(m, &ptr->BrowseQ,       mDNS_DomainTypeBrowse,              &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
+			err2 = mDNS_GetDomains(m, &ptr->DefBrowseQ,    mDNS_DomainTypeBrowseDefault,       &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
+			err3 = mDNS_GetDomains(m, &ptr->RegisterQ,     mDNS_DomainTypeRegistration,        &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
+			err4 = mDNS_GetDomains(m, &ptr->DefRegisterQ,  mDNS_DomainTypeRegistrationDefault, &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
+			err5 = mDNS_GetDomains(m, &ptr->LegacyBrowseQ, mDNS_DomainTypeBrowseLegacy,        &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
+			if (err1 || err2 || err3 || err4 || err5)
+				LogMsg("GetDomains for domain %##s returned error(s):\n"
+					   "%d (mDNS_DomainTypeBrowse)\n"
+					   "%d (mDNS_DomainTypeBrowseDefault)\n"
+					   "%d (mDNS_DomainTypeRegistration)\n"
+					   "%d (mDNS_DomainTypeRegistrationDefault)"
+					   "%d (mDNS_DomainTypeBrowseLegacy)\n",
+					   ptr->domain.c, err1, err2, err3, err4, err5);   
 			ptr->flag = 0;
 			}
 		
-		if (ptr->flag) { LogMsg("RegisterNameServers - unknown flag %d.  Skipping.", ptr->flag); }
+		if (ptr->flag) { LogMsg("RegisterSearchDomains - 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;
+//!!!KRS here is where we will give success/failure notification to the UI
+mDNSlocal void SCPrefsDynDNSCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
+	{
+	(void)m;  // unused
+	debugf("SCPrefsDynDNSCallback: result %d for registration of name %##s", result, rr->resrec.name.c);
+	SetDDNSNameStatus(&rr->resrec.name, result);
 	}
 
+mDNSlocal void SetSecretForDomain(mDNS *m, const domainname *domain)
+	{
+	OSStatus err = 0;
+	SecKeychainRef SysKeychain = NULL;
+	SecKeychainItemRef KeychainItem;
+	char dstring[MAX_ESCAPED_DOMAIN_NAME];
+	mDNSu32 secretlen;
+	void *secret = NULL;
+	domainname *d, canon;
+	int i, dlen;
+
+	// canonicalize name by converting to lower case (keychain and some name servers are case sensitive)
+	ConvertDomainNameToCString(domain, dstring);
+	dlen = strlen(dstring);
+	for (i = 0; i < dlen; i++) dstring[i] = tolower(dstring[i]);  // canonicalize -> lower case
+	MakeDomainNameFromDNSNameString(&canon, dstring);
+	d = &canon;		
+	
+	err = SecKeychainOpen(SYS_KEYCHAIN_PATH, &SysKeychain);
+	if (err) { LogMsg("SetSecretForDomain: couldn't open system keychain (error %d)", err); return; }
+	// find longest-match key ("account") name, excluding last label (e.g. excluding ".com")
+	while (d->c[0] && *(d->c + d->c[0] + 1))
+		{
+		if (!ConvertDomainNameToCString(d, dstring)) { LogMsg("SetSecretForDomain: bad domain %##s", d->c); return; }	
+		dlen = strlen(dstring);		
+		if (dstring[dlen-1] == '.') { dstring[dlen-1] = '\0'; dlen--; }  // chop trailing dot
+		err = SecKeychainFindGenericPassword(SysKeychain, strlen(DYNDNS_KEYCHAIN_SERVICE), DYNDNS_KEYCHAIN_SERVICE, dlen, dstring, &secretlen, &secret, &KeychainItem);
+		if (!err)
+			{
+			debugf("Setting shared secret for zone %s with key %##s", dstring, d->c);
+			mDNS_SetSecretForZone(m, d, d, secret, secretlen, mDNStrue);
+			free(secret);
+			return;
+			}
+		if (err == errSecItemNotFound) d = (domainname *)(d->c + d->c[0] + 1);
+		else
+			{
+			if (err == errSecNoSuchKeychain) debugf("SetSecretForDomain: keychain not found");
+			else LogMsg("SetSecretForDomain: SecKeychainFindGenericPassword returned error %d", err);
+			return;
+			}
+		}
+	}
 
-mDNSlocal void DNSConfigChanged(SCDynamicStoreRef session, CFArrayRef changes, void *context)
+mDNSlocal void DynDNSConfigChanged(mDNS *const m)
 	{
-	mDNS *m = context;
+	static mDNSBool LegacyNATInitialized = mDNSfalse;
+	uDNS_GlobalInfo *u = &m->uDNS_info;
 	CFDictionaryRef dict;
 	CFStringRef     key;
+	domainname BrowseDomain, RegDomain, fqdn;
+	
+	// get fqdn, zone from SCPrefs
+	GetUserSpecifiedDDNSConfig(&fqdn, &RegDomain, &BrowseDomain);
+	if (!fqdn.c[0] && !RegDomain.c[0]) ReadDDNSSettingsFromConfFile(m, CONFIG_FILE, &fqdn, &RegDomain);
 
-	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
+	if (!SameDomainName(&BrowseDomain, &DynDNSBrowseDomain))
+		{
+		if (DynDNSBrowseDomain.c[0]) SetSCPrefsBrowseDomain(m, &DynDNSBrowseDomain, mDNSfalse);
+		AssignDomainName(DynDNSBrowseDomain, BrowseDomain);
+		if (DynDNSBrowseDomain.c[0]) SetSCPrefsBrowseDomain(m, &DynDNSBrowseDomain, mDNStrue);
+		}
+	
+	if (!SameDomainName(&RegDomain, &DynDNSRegDomain))
+		{		
+		if (DynDNSRegDomain.c[0]) RemoveDefRegDomain(&DynDNSRegDomain);
+		AssignDomainName(DynDNSRegDomain, RegDomain);		
+		if (DynDNSRegDomain.c[0]) { SetSecretForDomain(m, &DynDNSRegDomain); AddDefRegDomain(&DynDNSRegDomain); }
+		}
+	
+	if (!SameDomainName(&fqdn, &DynDNSHostname))
+		{
+		if (DynDNSHostname.c[0]) mDNS_RemoveDynDNSHostName(m, &DynDNSHostname);
+		AssignDomainName(DynDNSHostname, fqdn);
+		if (DynDNSHostname.c[0])
+			{
+			SetSecretForDomain(m, &fqdn); // no-op if "zone" secret, above, is to be used for hostname
+			mDNS_AddDynDNSHostName(m, &DynDNSHostname, SCPrefsDynDNSCallback, NULL);
+			SetDDNSNameStatus(&DynDNSHostname, 1);
+			}
+		}
 
+    // get DNS settings
+	SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:DynDNSConfigChanged"), NULL, NULL);
+	if (!store) return;
+	
 	key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetDNS);
-	if (!key) {  LogMsg("ERROR: DNSConfigChanged - SCDynamicStoreKeyCreateNetworkGlobalEntity");  return;  }
-	dict = SCDynamicStoreCopyValue(session, key);
+	if (!key) {  LogMsg("ERROR: DNSConfigChanged - SCDynamicStoreKeyCreateNetworkGlobalEntity"); CFRelease(store); return;  }
+	dict = SCDynamicStoreCopyValue(store, key);
 	CFRelease(key);
-	if (dict)
+
+	// handle any changes to search domains and DNS server addresses
+	if (RegisterSplitDNS(m) != mStatus_NoError)
+		if (dict) RegisterNameServers(m, dict);  // fall back to non-split DNS aware configuration on failure
+	RegisterSearchDomains(m, dict);  // note that we register name servers *before* search domains
+	if (dict) CFRelease(dict);
+
+	// get IPv4 settings
+	key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,kSCDynamicStoreDomainState, kSCEntNetIPv4);
+	if (!key) {  LogMsg("ERROR: RouterChanged - SCDynamicStoreKeyCreateNetworkGlobalEntity"); CFRelease(store); return;  }
+	dict = SCDynamicStoreCopyValue(store, key);
+	CFRelease(key);
+	CFRelease(store);
+	if (!dict)
+		{ mDNS_SetPrimaryInterfaceInfo(m, NULL, NULL); return; } // lost v4
+
+	// handle router changes
+	mDNSAddr r;
+	char buf[256];
+	r.type = mDNSAddrType_IPv4;
+	r.ip.v4.NotAnInteger = 0;
+	CFStringRef router = CFDictionaryGetValue(dict, kSCPropNetIPv4Router);
+	if (router)
 		{
-		RegisterDNSConfig(m, dict, kSCPropNetDNSServerAddresses);
-		RegisterDNSConfig(m, dict, kSCPropNetDNSSearchDomains);		
-		CFRelease(dict);
-		}		
-	if (mDNS_DNSRegistered(m)) mDNS_GenerateGlobalFQDN(m);
-	// no-op if label & domain are unchanged
+		if (!CFStringGetCString(router, buf, 256, kCFStringEncodingUTF8))
+			LogMsg("Could not convert router to CString");
+		else inet_aton(buf, (struct in_addr *)&r.ip.v4);
+		}
+
+	// handle primary interface changes
+	CFStringRef primary = CFDictionaryGetValue(dict, kSCDynamicStorePropNetPrimaryInterface);
+	if (primary)
+		{
+		struct ifaddrs *ifa = myGetIfAddrs(1);
+
+		if (!CFStringGetCString(primary, buf, 256, kCFStringEncodingUTF8))
+			{ LogMsg("Could not convert router to CString"); goto error; }		
+
+		// find primary interface in list
+		while (ifa)
+			{
+			if (ifa->ifa_addr->sa_family == AF_INET && !strcmp(buf, ifa->ifa_name))
+				{
+				mDNSAddr ip;
+				SetupAddr(&ip, ifa->ifa_addr);
+				if (ip.ip.v4.b[0] == 169 && ip.ip.v4.b[1] == 254)
+					{ mDNS_SetPrimaryInterfaceInfo(m, NULL, NULL); break; }  // primary IP is link-local				
+				if (ip.ip.v4.NotAnInteger != u->PrimaryIP.ip.v4.NotAnInteger ||
+					r.ip.v4.NotAnInteger != u->Router.ip.v4.NotAnInteger)
+					{
+					if (LegacyNATInitialized) { LegacyNATDestroy(); LegacyNATInitialized = mDNSfalse; }
+					if (IsPrivateV4Addr(&ip))
+						{
+						mStatus err = LegacyNATInit();
+						if (err)  LogMsg("ERROR: LegacyNATInit");
+						else LegacyNATInitialized = mDNStrue;
+						}					
+					mDNS_SetPrimaryInterfaceInfo(m, &ip, r.ip.v4.NotAnInteger ? &r : NULL);
+					break;
+					}
+				}
+			ifa = ifa->ifa_next;
+			}
+		}
+
+	error:
+	CFRelease(dict);
 	}
 
-mDNSlocal mStatus WatchForDNSChanges(mDNS *const m)	
-    {
-    CFStringRef			    key;
-    CFMutableArrayRef		keyList;
-    CFRunLoopSourceRef		rls;
-    SCDynamicStoreRef 		session;
-	SCDynamicStoreContext context = { 0, m, NULL, NULL, NULL };
+mDNSexport void mDNSMacOSXNetworkChanged(mDNS *const m)
+	{
+	LogOperation("***   Network Configuration Change   ***");
+	MarkAllInterfacesInactive(m);
+	UpdateInterfaceList(m);
+	int nDeletions = ClearInactiveInterfaces(m);
+	int nAdditions = SetupActiveInterfaces(m);
+	if (nDeletions || nAdditions) mDNS_UpdateLLQs(m);
+	DynDNSConfigChanged(m);
 	
-    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;
-    }
+	if (m->MainCallback)
+		m->MainCallback(m, mStatus_ConfigChanged);
+	}
 
 mDNSlocal void NetworkChanged(SCDynamicStoreRef store, CFArrayRef changedKeys, void *context)
 	{
 	(void)store;        // Parameter not used
 	(void)changedKeys;  // Parameter not used
-	debugf("***   Network Configuration Change   ***");
-
+	LogOperation("***   NetworkChanged   ***");
 	mDNS *const m = (mDNS *const)context;
-	MarkAllInterfacesInactive(m);
-	UpdateInterfaceList(m);
-	ClearInactiveInterfaces(m);
-	SetupActiveInterfaces(m);
-	
-	if (m->MainCallback)
-		m->MainCallback(m, mStatus_ConfigChanged);
+	mDNS_Lock(m);
+	m->p->NetworkChanged = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 2);
+	if (!m->SuppressSending ||
+		m->SuppressSending - m->p->NetworkChanged < 0)
+		m->SuppressSending = m->p->NetworkChanged;
+	mDNS_Unlock(m);
 	}
 
 mDNSlocal mStatus WatchForNetworkChanges(mDNS *const m)
 	{
 	mStatus err = -1;
 	SCDynamicStoreContext context = { 0, m, NULL, NULL, NULL };
-	SCDynamicStoreRef     store    = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder"), NetworkChanged, &context);
+	SCDynamicStoreRef     store    = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:WatchForNetworkChanges"), NetworkChanged, &context);
 	CFStringRef           key1     = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv4);
 	CFStringRef           key2     = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv6);
 	CFStringRef           key3     = SCDynamicStoreKeyCreateComputerName(NULL);
 	CFStringRef           key4     = SCDynamicStoreKeyCreateHostNames(NULL);
+	CFStringRef           key5     = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetDNS);
 	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 (!store) { LogMsg("SCDynamicStoreCreate failed: %s", SCErrorString(SCError())); goto error; }
 	if (!key1 || !key2 || !key3 || !key4 || !keys || !pattern1 || !pattern2 || !patterns) goto error;
 
 	CFArrayAppendValue(keys, key1);
 	CFArrayAppendValue(keys, key2);
 	CFArrayAppendValue(keys, key3);
 	CFArrayAppendValue(keys, key4);
+	CFArrayAppendValue(keys, key5);
+	CFArrayAppendValue(keys, CFSTR("Setup:/Network/DynamicDNS"));
 	CFArrayAppendValue(patterns, pattern1);
 	CFArrayAppendValue(patterns, pattern2);
+	CFArrayAppendValue(patterns, CFSTR("State:/Network/Interface/[^/]+/AirPort"));
 	if (!SCDynamicStoreSetNotificationKeys(store, keys, patterns))
-		{ LogMsg("SCDynamicStoreSetNotificationKeys failed: %s\n", SCErrorString(SCError())); goto error; }
+		{ LogMsg("SCDynamicStoreSetNotificationKeys failed: %s", SCErrorString(SCError())); goto error; }
 
 	m->p->StoreRLS = SCDynamicStoreCreateRunLoopSource(NULL, store, 0);
-	if (!m->p->StoreRLS) { LogMsg("SCDynamicStoreCreateRunLoopSource failed: %s\n", SCErrorString(SCError())); goto error; }
+	if (!m->p->StoreRLS) { LogMsg("SCDynamicStoreCreateRunLoopSource failed: %s", SCErrorString(SCError())); goto error; }
 
 	CFRunLoopAddSource(CFRunLoopGetCurrent(), m->p->StoreRLS, kCFRunLoopDefaultMode);
 	m->p->Store = store;
@@ -1838,6 +2690,7 @@ exit:
 	if (key2)     CFRelease(key2);
 	if (key3)     CFRelease(key3);
 	if (key4)     CFRelease(key4);
+	if (key5)     CFRelease(key5);
 	if (pattern1) CFRelease(pattern1);
 	if (pattern2) CFRelease(pattern2);
 	if (keys)     CFRelease(keys);
@@ -1852,14 +2705,24 @@ mDNSlocal void PowerChanged(void *refcon, io_service_t service, natural_t messag
 	(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;
+		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");
+												// If still sleeping (didn't get 'WillPowerOn' message for some reason?) wake now
+												if (m->SleepState) mDNSCoreMachineSleep(m, false);
+												// Just to be safe, also make sure our interface list is fully up to date, in case we
+												// haven't yet received the System Configuration Framework "network changed" event that
+												// we expect to receive some time shortly after the kIOMessageSystemWillPowerOn message
+												mDNSMacOSXNetworkChanged(m);															break; // E0000300
+		case kIOMessageSystemWillRestart:		debugf("PowerChanged kIOMessageSystemWillRestart (no action)");							break; // E0000310
+		case kIOMessageSystemWillPowerOn:		debugf("PowerChanged kIOMessageSystemWillPowerOn");
+												// Make sure our interface list is cleared to the empty state, then tell mDNSCore to wake
+												mDNSMacOSXNetworkChanged(m); mDNSCoreMachineSleep(m, false);							break; // E0000320
+		default:								debugf("PowerChanged unknown message %X", messageType);									break;
 		}
 	IOAllowPowerChange(m->p->PowerConnection, (long)messageArgument);
 	}
@@ -1877,132 +2740,12 @@ 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;
 
-mDNSexport mDNSBool mDNSMacOSXSystemBuildNumber(char *HINFO_SWstring)
+mDNSexport int mDNSMacOSXSystemBuildNumber(char *HINFO_SWstring)
 	{
 	int major = 0, minor = 0;
 	char letter = 0, prodname[256]="Mac OS X", prodvers[256]="", buildver[256]="?";
@@ -2025,119 +2768,28 @@ mDNSexport mDNSBool mDNSMacOSXSystemBuildNumber(char *HINFO_SWstring)
 // 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)
+mDNSlocal mDNSBool mDNSPlatformInit_CanReceiveUnicast(void)
 	{
-	int err;
+	int err = -1;
 	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;
-
-    // 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])
+	if (s < 3)
+		LogMsg("mDNSPlatformInit_CanReceiveUnicast: socket error %d errno %d (%s)", s, errno, strerror(errno));
+	else
 		{
-		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);
-			}
+		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);
 		}
-	
-	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);
+	if (err) LogMsg("No unicast UDP responses");
+	else     debugf("Unicast UDP responses okay");
+	return(err == 0);
 	}
 
-	
+// Callback for the _legacy._browse queries - add answer to list of domains to search for empty-string browses
 mDNSlocal void FoundDefBrowseDomain(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
 	{
 	DNameListElem *ptr, *prev, *new;
@@ -2148,9 +2800,11 @@ mDNSlocal void FoundDefBrowseDomain(mDNS *const m, DNSQuestion *question, const
 		{
 		new = mallocL("FoundDefBrowseDomain", sizeof(DNameListElem));
 		if (!new) { LogMsg("ERROR: malloc"); return; }
-		strcpy(new->name.c, answer->rdata->u.name.c);
+		AssignDomainName(new->name, answer->rdata->u.name);
 		new->next = DefBrowseList;
 		DefBrowseList = new;
+		DefaultBrowseDomainChanged(&new->name, mDNStrue);
+		udsserver_default_browse_domain_changed(&new->name, mDNStrue);
 		return;
 		}
 	else
@@ -2161,18 +2815,64 @@ mDNSlocal void FoundDefBrowseDomain(mDNS *const m, DNSQuestion *question, const
 			{
 			if (SameDomainName(&ptr->name, &answer->rdata->u.name))
 				{
+				DefaultBrowseDomainChanged(&ptr->name, mDNSfalse);
+				udsserver_default_browse_domain_changed(&ptr->name, mDNSfalse);
 				if (prev) prev->next = ptr->next;
 				else DefBrowseList = ptr->next;
-				freeL("FoundDefBrowseDomain", ptr);
+				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);
-		}    
+		}
 	}
 
+// Add or remove a user-specified domain to the list of empty-string browse domains
+// Also register a non-legacy _browse PTR record so that the domain appears in enumeration lists
+mDNSlocal void SetSCPrefsBrowseDomain(mDNS *m, const domainname *d, mDNSBool add)
+	{
+	AuthRecord rec;
+	
+	// Create dummy  record pointing to the domain to be added/removed
+	mDNS_SetupResourceRecord(&rec, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, 7200,  kDNSRecordTypeShared, mDNSNULL, mDNSNULL);
+	AssignDomainName(rec.resrec.rdata->u.name, *d);
+
+	// add/remove the "_legacy" entry
+	MakeDomainNameFromDNSNameString(&rec.resrec.name, "_legacy._browse._dns-sd._udp.local.");
+	FoundDefBrowseDomain(m, &LegacyBrowseDomainQ, &rec.resrec, add);
+
+	if (add)
+		{
+		// allocate/register a non-legacy _browse PTR record
+		ARListElem *ptr = mallocL("ARListElem", sizeof(*ptr));
+		mDNS_SetupResourceRecord(&ptr->ar, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, 7200,  kDNSRecordTypeShared, FreeARElemCallback, ptr);
+		MakeDomainNameFromDNSNameString(&ptr->ar.resrec.name, "_browse._dns-sd._udp.local.");
+		AssignDomainName(ptr->ar.resrec.rdata->u.name, *d);
+		mStatus err = mDNS_Register(m, &ptr->ar);
+		if (err)
+			{
+			LogMsg("SetSCPrefsBrowseDomain: mDNS_Register returned error %d", err);
+			freeL("ARListElem", ptr);
+			}
+		else
+			{
+			ptr->next = SCPrefBrowseDomains;
+			SCPrefBrowseDomains = ptr;
+			}
+		}
+	else
+		{
+		ARListElem **remove = &SCPrefBrowseDomains;
+		while (*remove && !SameDomainName(&(*remove)->ar.resrec.rdata->u.name, d)) remove = &(*remove)->next;
+		if (!*remove) { LogMsg("SetSCPrefsBrowseDomain (remove) - domain %##s not found!", d->c); return; }
+		mDNS_Deregister(m, &(*remove)->ar);
+		*remove = (*remove)->next;
+		}
+	}
+
+
 // 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)
@@ -2186,22 +2886,15 @@ mDNSlocal void FoundDefBrowseDomain(mDNS *const m, DNSQuestion *question, const
 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);
+	err = mDNS_GetDomains(m, &LegacyBrowseDomainQ, mDNS_DomainTypeBrowseLegacy, 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);
-
+	SetSCPrefsBrowseDomain(m, &localdomain, mDNStrue);
     return mStatus_NoError;
 	}
-	
+
 mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m)
 	{
 	mStatus err;
@@ -2217,7 +2910,7 @@ mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m)
 
 	char HINFO_SWstring[256] = "";
 	if (mDNSMacOSXSystemBuildNumber(HINFO_SWstring) < 7) m->KnownBugs |= mDNS_KnownBug_PhantomInterfaces;
-	if (mDNSPlatformInit_ReceiveUnicast())               m->CanReceiveUnicast = mDNStrue;
+	if (mDNSPlatformInit_CanReceiveUnicast())            m->CanReceiveUnicastOn5353 = mDNStrue;
 
 	mDNSu32 hlen = mDNSPlatformStrLen(HINFO_HWstring);
 	mDNSu32 slen = mDNSPlatformStrLen(HINFO_SWstring);
@@ -2235,11 +2928,22 @@ mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m)
 	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);
+	err = SetupSocket(m, &m->p->unicastsockets, mDNSfalse, &zeroAddr, AF_INET);
+	err = SetupSocket(m, &m->p->unicastsockets, mDNSfalse, &zeroAddr, AF_INET6);
+
+	struct sockaddr_in s4;
+	struct sockaddr_in6 s6;
+	int n4 = sizeof(s4);
+	int n6 = sizeof(s6);
+	if (getsockname(m->p->unicastsockets.sktv4, (struct sockaddr *)&s4, &n4) < 0) LogMsg("getsockname v4 error %d (%s)", errno, strerror(errno));
+	else m->UnicastPort4.NotAnInteger = s4.sin_port;
+	if (getsockname(m->p->unicastsockets.sktv6, (struct sockaddr *)&s6, &n6) < 0) LogMsg("getsockname v6 error %d (%s)", errno, strerror(errno));
+	else m->UnicastPort6.NotAnInteger = s6.sin6_port;
 
 	m->p->InterfaceList      = mDNSNULL;
 	m->p->userhostlabel.c[0] = 0;
+	m->p->usernicelabel.c[0] = 0;
+	m->p->NotifyUser         = 0;
 	UpdateInterfaceList(m);
 	SetupActiveInterfaces(m);
 
@@ -2248,16 +2952,12 @@ mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m)
 	
 	err = WatchForPowerChanges(m);
 	if (err) return err;
-	
-	err = WatchForDNSChanges(m);
 
-	InitDNSConfig(m);
+	DynDNSRegDomain.c[0] = '\0';
+	DynDNSBrowseDomain.c[0] = '\0';
+	DynDNSConfigChanged(m);						// Get initial DNS configuration
 
-	m->uDNS_info.ServiceRegDomain[0] = '\0';
-	m->uDNS_info.NameRegDomain[0] = '\0';
-	InitAuthInfo(m);
-	ReadRegDomainFromConfig(m);	
-	
+	InitDNSConfig(m);
  	return(err);
 	}
 
@@ -2279,8 +2979,8 @@ mDNSexport void mDNSPlatformClose(mDNS *const m)
 		CFRunLoopSourceInvalidate(m->p->PowerRLS);
 		CFRelease(m->p->PowerRLS);
 		IODeregisterForSystemPower(&m->p->PowerNotifier);
-		m->p->PowerConnection = NULL;
-		m->p->PowerNotifier   = NULL;
+		m->p->PowerConnection = 0;
+		m->p->PowerNotifier   = 0;
 		m->p->PowerRLS        = NULL;
 		}
 	
@@ -2299,9 +2999,14 @@ mDNSexport void mDNSPlatformClose(mDNS *const m)
 	CloseSocketSet(&m->p->unicastsockets);
 	}
 
-mDNSexport mDNSs32  mDNSPlatformOneSecond = 1000;
+mDNSexport mDNSu32 mDNSPlatformRandomSeed(void)
+	{
+	return(mach_absolute_time());
+	}
+
+mDNSexport mDNSs32 mDNSPlatformOneSecond = 1000;
 
-mDNSexport mStatus mDNSPlatformTimeInit(mDNSs32 *timenow)
+mDNSexport mStatus mDNSPlatformTimeInit(void)
 	{
 	// Notes: Typical values for mach_timebase_info:
 	// tbi.numer = 1000 million
@@ -2323,16 +3028,27 @@ mDNSexport mStatus mDNSPlatformTimeInit(mDNSs32 *timenow)
 	// 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);
+	if (result == KERN_SUCCESS) clockdivisor = ((uint64_t)tbi.denom * 1000000) / tbi.numer;
+	return(result);
 	}
 
-mDNSexport mDNSs32  mDNSPlatformTimeNow(void)
+mDNSexport mDNSs32 mDNSPlatformRawTime(void)
 	{
-	if (clockdivisor == 0) { LogMsg("mDNSPlatformTimeNow called before mDNSPlatformTimeInit"); return(0); }
-	return((mDNSs32)(mach_absolute_time() / clockdivisor));
+	if (clockdivisor == 0) { LogMsg("mDNSPlatformRawTime called before mDNSPlatformTimeInit"); return(0); }
+
+	static uint64_t last_mach_absolute_time = 0;
+	uint64_t this_mach_absolute_time = mach_absolute_time();
+	if ((int64_t)this_mach_absolute_time - (int64_t)last_mach_absolute_time < 0)
+		{
+		LogMsg("mDNSPlatformRawTime: last_mach_absolute_time %08X%08X", last_mach_absolute_time);
+		LogMsg("mDNSPlatformRawTime: this_mach_absolute_time %08X%08X", this_mach_absolute_time);
+		// Update last_mach_absolute_time *before* calling NotifyOfElusiveBug()
+		last_mach_absolute_time = this_mach_absolute_time;
+		NotifyOfElusiveBug("mach_absolute_time went backwards!", 3438376, "");
+		}
+	last_mach_absolute_time = this_mach_absolute_time;
+
+	return((mDNSs32)(this_mach_absolute_time / clockdivisor));
 	}
 
 mDNSexport mDNSs32 mDNSPlatformUTC(void)
diff --git a/mDNSMacOSX/mDNSMacOSX.h b/mDNSMacOSX/mDNSMacOSX.h
index ba07125..2a81939 100644
--- a/mDNSMacOSX/mDNSMacOSX.h
+++ b/mDNSMacOSX/mDNSMacOSX.h
@@ -3,8 +3,6 @@
  *
  * @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
@@ -25,6 +23,43 @@
     Change History (most recent first):
 
 $Log: mDNSMacOSX.h,v $
+Revision 1.48  2004/12/07 01:31:31  cheshire
+mDNSMacOSXSystemBuildNumber() returns int, not mDNSBool
+
+Revision 1.47  2004/11/30 03:24:03  cheshire
+<rdar://problem/3854544> Defer processing network configuration changes until configuration has stabilized
+
+Revision 1.46  2004/11/03 03:45:16  cheshire
+<rdar://problem/3863627> mDNSResponder does not inform user of Computer Name collisions
+
+Revision 1.45  2004/10/28 00:53:57  cheshire
+Export mDNSMacOSXNetworkChanged() so it's callable from outside this mDNSMacOSX.c;
+Add LogOperation() call to record when we get network change events
+
+Revision 1.44  2004/10/23 01:16:01  cheshire
+<rdar://problem/3851677> uDNS operations not always reliable on multi-homed hosts
+
+Revision 1.43  2004/10/15 23:00:18  ksekar
+<rdar://problem/3799242> Need to update LLQs on location changes
+
+Revision 1.42  2004/10/04 05:56:04  cheshire
+<rdar://problem/3824730> mDNSResponder doesn't respond to certain AirPort changes
+
+Revision 1.41  2004/09/30 00:24:59  ksekar
+<rdar://problem/3695802> Dynamically update default registration domains on config change
+
+Revision 1.40  2004/09/17 01:08:52  cheshire
+Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
+  The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
+  declared in that file are ONLY appropriate to single-address-space embedded applications.
+  For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
+
+Revision 1.39  2004/08/18 17:35:41  ksekar
+<rdar://problem/3651443>: Feature #9586: Need support for Legacy NAT gateways
+
+Revision 1.38  2004/07/13 21:24:25  rpantos
+Fix for <rdar://problem/3701120>.
+
 Revision 1.37  2004/06/04 08:58:30  ksekar
 <rdar://problem/3668624>: Keychain integration for secure dynamic update
 
@@ -36,7 +71,7 @@ Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format
 
 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"
+from mDNSMacOSX.h to mDNSEmbeddedAPI.h), impelemted to return "local"
 only on non-OSX platforms.  Changed call to return a copy of the list
 to avoid shared memory issues.  Added a routine to free the list.
 
@@ -116,10 +151,10 @@ Revision 1.11  2003/07/02 21:19:51  cheshire
 <rdar://problem/3313413> Update copyright notices, etc., in source code comments
 
 Revision 1.10  2003/06/25 23:42:19  ksekar
-<rdar://problem/3249292>: Feature: New Rendezvous APIs (#7875)
+<rdar://problem/3249292>: Feature: New DNS-SD 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.
+DNS-SD APIs, and integrated with existing Mach-port based daemon.
 
 Revision 1.9  2003/06/10 01:14:11  cheshire
 <rdar://problem/3286004> New APIs require a mDNSPlatformInterfaceIDfromInterfaceIndex() call
@@ -167,7 +202,7 @@ 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
+#include "mDNSEmbeddedAPI.h"  // for domain name structure
 	
 
 typedef struct NetworkInterfaceInfoOSX_struct NetworkInterfaceInfoOSX;
@@ -192,6 +227,7 @@ struct NetworkInterfaceInfoOSX_struct
 												// 2 = exists, but McastTxRx state changed
 	char                    *ifa_name;			// Memory for this is allocated using malloc
 	mDNSu32                  scope_id;			// interface index / IPv6 scope ID
+	mDNSEthAddr              BSSID;				// BSSID of 802.11 base station, if applicable
 	u_short                  sa_family;
 	mDNSBool                 Multicast;
 	CFSocketSet              ss;
@@ -202,6 +238,9 @@ struct mDNS_PlatformSupport_struct
     NetworkInterfaceInfoOSX *InterfaceList;
     CFSocketSet              unicastsockets;
     domainlabel              userhostlabel;
+    domainlabel              usernicelabel;
+    mDNSs32                  NotifyUser;
+    mDNSs32                  NetworkChanged;
     SCDynamicStoreRef        Store;
     CFRunLoopSourceRef       StoreRLS;
     io_connect_t             PowerConnection;
@@ -209,10 +248,19 @@ struct mDNS_PlatformSupport_struct
     CFRunLoopSourceRef       PowerRLS;
     };
 
-extern mDNSBool mDNSMacOSXSystemBuildNumber(char *HINFO_SWstring);
+extern void mDNSMacOSXNetworkChanged(mDNS *const m);
+extern int mDNSMacOSXSystemBuildNumber(char *HINFO_SWstring);
 
 extern const char mDNSResponderVersionString[];
 
+// Legacy NAT Traversal Support Setup/Teardown
+extern int LegacyNATDestroy(void);
+extern int LegacyNATInit(void);
+
+// Allow platform layer to tell daemon when default registration/browse domains
+extern void DefaultRegDomainChanged(const domainname *d, mDNSBool add);
+extern void DefaultBrowseDomainChanged(const domainname *d, mDNSBool add);
+	
 #ifdef  __cplusplus
     }
 #endif
diff --git a/mDNSMacOSX/CFSocketPuma.c b/mDNSMacOSX/mDNSMacOSXPuma.c
similarity index 96%
rename from mDNSMacOSX/CFSocketPuma.c
rename to mDNSMacOSX/mDNSMacOSXPuma.c
index 3a7e266..7764e2a 100644
--- a/mDNSMacOSX/CFSocketPuma.c
+++ b/mDNSMacOSX/mDNSMacOSXPuma.c
@@ -3,8 +3,6 @@
  *
  * @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
@@ -24,7 +22,7 @@
  *
  * 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
+ * in mDNSMacOSX.c. It is included mainly as sample code for people building
  * for other platforms that (like Puma) lack the getifaddrs() call.
  * NOTE: YOU CANNOT use this code to build an mDNSResponder daemon for Puma
  * that works just like the Jaguar one, because Puma lacks other necessary
@@ -32,7 +30,10 @@
 
     Change History (most recent first):
 
-$Log: CFSocketPuma.c,v $
+$Log: mDNSMacOSXPuma.c,v $
+Revision 1.5  2004/09/20 23:52:02  cheshire
+CFSocket{Puma}.c renamed to mDNSMacOSX{Puma}.c
+
 Revision 1.4  2003/08/12 19:56:25  cheshire
 Update to APSL 2.0
 
@@ -43,7 +44,7 @@ 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
+Move Puma support to mDNSMacOSXPuma.c
 
  */
 
diff --git a/mDNSMacOSX/mDNSResponder.pbproj/project.pbxproj b/mDNSMacOSX/mDNSResponder.pbproj/project.pbxproj
index 1a2786a..8ba74f8 100644
--- a/mDNSMacOSX/mDNSResponder.pbproj/project.pbxproj
+++ b/mDNSMacOSX/mDNSResponder.pbproj/project.pbxproj
@@ -11,15 +11,9 @@
 			path = mDNSMacOSX.h;
 			refType = 4;
 		};
-		004EFB9604CC78130CCA2C71 = {
-			fileEncoding = 4;
-			isa = PBXFileReference;
-			name = dnssd_clientstub.c;
-			path = ../mDNSShared/dnssd_clientstub.c;
-			refType = 2;
-		};
 		00AD62A3032D799A0CCA2C71 = {
 			buildPhases = (
+				FFF7174A07614A8600E10551,
 				00AD62A4032D799A0CCA2C71,
 				00AD62AC032D799A0CCA2C71,
 				00AD62B3032D799A0CCA2C71,
@@ -28,12 +22,13 @@
 			buildSettings = {
 				FRAMEWORK_SEARCH_PATHS = "";
 				GCC_TREAT_WARNINGS_AS_ERRORS = YES;
+				GCC_VERSION = 3.3;
 				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)";
-				OTHER_LDFLAGS = "";
+				OTHER_CFLAGS = "-no-cpp-precomp -mdynamic-no-pic -D__MACOSX__ -DmDNSResponderVersion=$(MVERS) -D_LEGACY_NAT_TRAVERSAL_ -DMDNS_DEBUGMSGS=1";
+				OTHER_LDFLAGS = "-weak-ldnsinfo";
 				OTHER_REZFLAGS = "";
 				PRODUCT_NAME = mDNSResponder.debug;
 				REZ_EXECUTABLE = YES;
@@ -72,14 +67,16 @@
 				00AD62AD032D799A0CCA2C71,
 				00AD62AE032D799A0CCA2C71,
 				00AD62AF032D799A0CCA2C71,
-				00AD62B0032D799A0CCA2C71,
-				F5E11B5E04A28126019798ED,
-				F525E72B04AA167A01F1CF4D,
-				DBAAFE2B057E8F4D0085CAD0,
-				DBAAFE2E057E8F660085CAD0,
-				7F18A9FA0587CEF6001880B3,
 				7F18A9FB0587CEF6001880B3,
+				7F18A9FA0587CEF6001880B3,
 				7F461DB7062DBF2900672BF3,
+				DBAAFE2E057E8F660085CAD0,
+				DBAAFE2B057E8F4D0085CAD0,
+				F525E72B04AA167A01F1CF4D,
+				F5E11B5E04A28126019798ED,
+				FFCB6D75075D595E00B8AF62,
+				00AD62B0032D799A0CCA2C71,
+				7FC8F9D606D14E66007E879D,
 				00AD62B1032D799A0CCA2C71,
 			);
 			isa = PBXSourcesBuildPhase;
@@ -174,9 +171,11 @@
 				SECTORDER_FLAGS = "";
 			};
 			dependencies = (
+				FF25795106C9AB1D00376F7B,
 				00AD62BC032D7A160CCA2C71,
 				00AD62BD032D7A1B0CCA2C71,
 				00AD62BE032D7A1D0CCA2C71,
+				FF16238F07023BD2001AB7D7,
 				FFD41DDB0664169900F0C438,
 				FFD41DDC0664169B00F0C438,
 			);
@@ -249,8 +248,10 @@
 				08FB779FFE84155DC02AAC07,
 				00AD62A3032D799A0CCA2C71,
 				6575FC1C022EB76000000109,
+				FF1C919207021C84001048AB,
 				DB2CC4530662DD6800335AB3,
 				DB2CC4660662DF5C00335AB3,
+				FF25792906C9A70800376F7B,
 			);
 		};
 		08FB7794FE84155DC02AAC07 = {
@@ -268,6 +269,7 @@
 		};
 		08FB7795FE84155DC02AAC07 = {
 			children = (
+				7FC8F9D406D14E66007E879D,
 				7F461DB5062DBF2900672BF3,
 				F525E72804AA167501F1CF4D,
 				F5E11B5A04A28126019798ED,
@@ -280,10 +282,16 @@
 				DBAAFE29057E8F4D0085CAD0,
 				000753D303367C1C0CCA2C71,
 				DBAAFE2C057E8F660085CAD0,
+				FFCB6D73075D539900B8AF62,
 				FF0E0B5D065ADC7600FE4D9C,
+				FF1C919D07021D77001048AB,
 				FF485D5105632E0000130380,
+				FFF4F63A06CFE4DD00459EFD,
 				7F18A9F60587CEF6001880B3,
 				7F18A9F70587CEF6001880B3,
+				FF25794606C9A8BF00376F7B,
+				FF25794C06C9A9D500376F7B,
+				FF25794F06C9AA8B00376F7B,
 			);
 			isa = PBXGroup;
 			name = "mDNS Server Sources";
@@ -304,22 +312,23 @@
 		};
 		08FB779FFE84155DC02AAC07 = {
 			buildPhases = (
+				FF37BE9207614059003C0420,
 				08FB77A0FE84155DC02AAC07,
 				08FB77A1FE84155DC02AAC07,
 				08FB77A3FE84155DC02AAC07,
 				08FB77A5FE84155DC02AAC07,
 				FF5A0AE705632EA600743C27,
-				FF0E0B5C065ADC3800FE4D9C,
 			);
 			buildSettings = {
 				FRAMEWORK_SEARCH_PATHS = "";
 				GCC_TREAT_WARNINGS_AS_ERRORS = YES;
+				GCC_VERSION = 3.3;
 				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)";
-				OTHER_LDFLAGS = "";
+				OTHER_CFLAGS = "-no-cpp-precomp -mdynamic-no-pic -D__MACOSX__ -DmDNSResponderVersion=$(MVERS) -D_LEGACY_NAT_TRAVERSAL_";
+				OTHER_LDFLAGS = "-weak-ldnsinfo";
 				OTHER_REZFLAGS = "";
 				PRODUCT_NAME = mDNSResponder;
 				REZ_EXECUTABLE = YES;
@@ -350,14 +359,16 @@
 				6575FC0D022EB18700000109,
 				6575FC0E022EB18700000109,
 				6575FBEA022EAF5A00000109,
-				6575FBED022EAF7200000109,
-				F5E11B5C04A28126019798ED,
-				F525E72904AA167501F1CF4D,
-				DBAAFE2A057E8F4D0085CAD0,
-				DBAAFE2D057E8F660085CAD0,
-				7F18A9F80587CEF6001880B3,
 				7F18A9F90587CEF6001880B3,
+				7F18A9F80587CEF6001880B3,
 				7F461DB6062DBF2900672BF3,
+				DBAAFE2D057E8F660085CAD0,
+				DBAAFE2A057E8F4D0085CAD0,
+				F525E72904AA167501F1CF4D,
+				F5E11B5C04A28126019798ED,
+				FFCB6D74075D539900B8AF62,
+				6575FBED022EAF7200000109,
+				7FC8F9D506D14E66007E879D,
 				6575FBEE022EAF7200000109,
 			);
 			isa = PBXSourcesBuildPhase;
@@ -420,6 +431,8 @@
 				00AD62B8032D799A0CCA2C71,
 				DB2CC4670662DF5C00335AB3,
 				FFD41DDA0664157900F0C438,
+				FF25794406C9A70800376F7B,
+				FF1C919B07021C84001048AB,
 			);
 			isa = PBXGroup;
 			name = Products;
@@ -438,8 +451,8 @@
 		654BE64F02B63B93000001D1 = {
 			fileEncoding = 4;
 			isa = PBXFileReference;
-			name = mDNSClientAPI.h;
-			path = ../mDNSCore/mDNSClientAPI.h;
+			name = mDNSEmbeddedAPI.h;
+			path = ../mDNSCore/mDNSEmbeddedAPI.h;
 			refType = 4;
 		};
 		654BE65002B63B93000001D1 = {
@@ -481,7 +494,7 @@
 			fileEncoding = 4;
 			indentWidth = 4;
 			isa = PBXFileReference;
-			path = CFSocket.c;
+			path = mDNSMacOSX.c;
 			refType = 4;
 			tabWidth = 4;
 			usesTabs = 1;
@@ -596,12 +609,14 @@
 				6575FC19022EB76000000109,
 				6575FC1A022EB76000000109,
 				6575FC1B022EB76000000109,
+				FFF4F63C06CFE53300459EFD,
 			);
 			buildSettings = {
 				GCC_TREAT_WARNINGS_AS_ERRORS = YES;
+				GCC_VERSION = 3.3;
 				INSTALL_PATH = /usr/bin;
 				MACOSX_DEPLOYMENT_TARGET = 10.2;
-				OTHER_CFLAGS = "-no-cpp-precomp -D__MACOSX__ -DmDNSResponderVersion=$(MVERS)";
+				OTHER_CFLAGS = "-no-cpp-precomp -mdynamic-no-pic -D__MACOSX__ -DmDNSResponderVersion=$(MVERS)";
 				OTHER_LDFLAGS = "";
 				OTHER_REZFLAGS = "";
 				PRODUCT_NAME = mDNS;
@@ -613,9 +628,9 @@
 			dependencies = (
 			);
 			isa = PBXToolTarget;
-			name = "mDNS Command-Line tool";
+			name = "mDNS command-line tool";
 			productInstallPath = /usr/bin;
-			productName = "Sample mDNS Client";
+			productName = "mDNS command-line tool";
 			productReference = 6575FC1D022EB76000000109;
 		};
 		6575FC1D022EB76000000109 = {
@@ -626,10 +641,10 @@
 		6575FC1F022EB78C00000109 = {
 			children = (
 				6575FC20022EB7AA00000109,
-				004EFB9604CC78130CCA2C71,
+				FF1C919F07021E3F001048AB,
 			);
 			isa = PBXGroup;
-			name = SampleMulticastDNSClient;
+			name = "Command-Line Clients";
 			refType = 4;
 		};
 		6575FC20022EB7AA00000109 = {
@@ -637,7 +652,7 @@
 			indentWidth = 4;
 			isa = PBXFileReference;
 			path = SamplemDNSClient.c;
-			refType = 4;
+			refType = 2;
 			tabWidth = 4;
 			usesTabs = 0;
 		};
@@ -670,14 +685,14 @@
 //7F3
 //7F4
 		7F18A9F60587CEF6001880B3 = {
-			fileEncoding = 30;
+			fileEncoding = 4;
 			isa = PBXFileReference;
 			name = DNSCommon.c;
 			path = ../mDNSCore/DNSCommon.c;
 			refType = 2;
 		};
 		7F18A9F70587CEF6001880B3 = {
-			fileEncoding = 30;
+			fileEncoding = 4;
 			isa = PBXFileReference;
 			name = uDNS.c;
 			path = ../mDNSCore/uDNS.c;
@@ -708,7 +723,7 @@
 			};
 		};
 		7F461DB5062DBF2900672BF3 = {
-			fileEncoding = 30;
+			fileEncoding = 4;
 			isa = PBXFileReference;
 			name = DNSDigest.c;
 			path = ../mDNSCore/DNSDigest.c;
@@ -744,6 +759,24 @@
 			settings = {
 			};
 		};
+		7FC8F9D406D14E66007E879D = {
+			fileEncoding = 4;
+			isa = PBXFileReference;
+			path = LegacyNATTraversal.c;
+			refType = 2;
+		};
+		7FC8F9D506D14E66007E879D = {
+			fileRef = 7FC8F9D406D14E66007E879D;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		7FC8F9D606D14E66007E879D = {
+			fileRef = 7FC8F9D406D14E66007E879D;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
 //7F0
 //7F1
 //7F2
@@ -775,91 +808,91 @@
 			refType = 4;
 		};
 		DB2CC4430662DD1100335AB3 = {
-			fileEncoding = 30;
+			fileEncoding = 4;
 			isa = PBXFileReference;
 			name = BaseListener.java;
 			path = ../mDNSShared/Java/BaseListener.java;
 			refType = 2;
 		};
 		DB2CC4440662DD1100335AB3 = {
-			fileEncoding = 30;
+			fileEncoding = 4;
 			isa = PBXFileReference;
 			name = BrowseListener.java;
 			path = ../mDNSShared/Java/BrowseListener.java;
 			refType = 2;
 		};
 		DB2CC4450662DD1100335AB3 = {
-			fileEncoding = 30;
+			fileEncoding = 4;
 			isa = PBXFileReference;
 			name = DNSRecord.java;
 			path = ../mDNSShared/Java/DNSRecord.java;
 			refType = 2;
 		};
 		DB2CC4460662DD1100335AB3 = {
-			fileEncoding = 30;
+			fileEncoding = 4;
 			isa = PBXFileReference;
 			name = DNSSD.java;
 			path = ../mDNSShared/Java/DNSSD.java;
 			refType = 2;
 		};
 		DB2CC4470662DD1100335AB3 = {
-			fileEncoding = 30;
+			fileEncoding = 4;
 			isa = PBXFileReference;
 			name = DNSSDException.java;
 			path = ../mDNSShared/Java/DNSSDException.java;
 			refType = 2;
 		};
 		DB2CC4480662DD1100335AB3 = {
-			fileEncoding = 30;
+			fileEncoding = 4;
 			isa = PBXFileReference;
 			name = DNSSDRegistration.java;
 			path = ../mDNSShared/Java/DNSSDRegistration.java;
 			refType = 2;
 		};
 		DB2CC4490662DD1100335AB3 = {
-			fileEncoding = 30;
+			fileEncoding = 4;
 			isa = PBXFileReference;
 			name = DNSSDService.java;
 			path = ../mDNSShared/Java/DNSSDService.java;
 			refType = 2;
 		};
 		DB2CC44A0662DD1100335AB3 = {
-			fileEncoding = 30;
+			fileEncoding = 4;
 			isa = PBXFileReference;
 			name = DomainListener.java;
 			path = ../mDNSShared/Java/DomainListener.java;
 			refType = 2;
 		};
 		DB2CC44B0662DD1100335AB3 = {
-			fileEncoding = 30;
+			fileEncoding = 4;
 			isa = PBXFileReference;
 			name = JNISupport.c;
 			path = ../mDNSShared/Java/JNISupport.c;
 			refType = 2;
 		};
 		DB2CC44C0662DD1100335AB3 = {
-			fileEncoding = 30;
+			fileEncoding = 4;
 			isa = PBXFileReference;
 			name = QueryListener.java;
 			path = ../mDNSShared/Java/QueryListener.java;
 			refType = 2;
 		};
 		DB2CC44D0662DD1100335AB3 = {
-			fileEncoding = 30;
+			fileEncoding = 4;
 			isa = PBXFileReference;
 			name = RegisterListener.java;
 			path = ../mDNSShared/Java/RegisterListener.java;
 			refType = 2;
 		};
 		DB2CC44E0662DD1100335AB3 = {
-			fileEncoding = 30;
+			fileEncoding = 4;
 			isa = PBXFileReference;
 			name = ResolveListener.java;
 			path = ../mDNSShared/Java/ResolveListener.java;
 			refType = 2;
 		};
 		DB2CC44F0662DD1100335AB3 = {
-			fileEncoding = 30;
+			fileEncoding = 4;
 			isa = PBXFileReference;
 			name = TXTRecord.java;
 			path = ../mDNSShared/Java/TXTRecord.java;
@@ -909,6 +942,7 @@
 			buildSettings = {
 				DYLIB_COMPATIBILITY_VERSION = 1;
 				DYLIB_CURRENT_VERSION = 1;
+				GCC_VERSION = 3.3;
 				INSTALL_PATH = /System/Library/Java/Extensions;
 				JAVA_ARCHIVE_CLASSES = YES;
 				JAVA_ARCHIVE_COMPRESSION = YES;
@@ -1062,7 +1096,8 @@
 				DEBUGGING_SYMBOLS = NO;
 				DYLIB_COMPATIBILITY_VERSION = 1;
 				DYLIB_CURRENT_VERSION = 1;
-				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\"";
+				GCC_VERSION = 3.3;
+				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\"";
 				INSTALL_PATH = /usr/lib/java;
 				LIBRARY_STYLE = DYNAMIC;
 				OTHER_CFLAGS = "";
@@ -1107,7 +1142,7 @@
 			};
 		};
 		DBAAFE29057E8F4D0085CAD0 = {
-			fileEncoding = 30;
+			fileEncoding = 4;
 			isa = PBXFileReference;
 			name = mDNSDebug.c;
 			path = ../mDNSShared/mDNSDebug.c;
@@ -1126,7 +1161,7 @@
 			};
 		};
 		DBAAFE2C057E8F660085CAD0 = {
-			fileEncoding = 30;
+			fileEncoding = 4;
 			isa = PBXFileReference;
 			name = GenLinkedList.c;
 			path = ../mDNSShared/GenLinkedList.c;
@@ -1239,29 +1274,329 @@
 //FF2
 //FF3
 //FF4
-		FF0E0B5C065ADC3800FE4D9C = {
+		FF0E0B5D065ADC7600FE4D9C = {
+			fileEncoding = 4;
+			isa = PBXFileReference;
+			name = mDNS.1;
+			path = ../mDNSShared/mDNS.1;
+			refType = 2;
+		};
+		FF16238F07023BD2001AB7D7 = {
+			isa = PBXTargetDependency;
+			target = FF1C919207021C84001048AB;
+		};
+		FF1C919207021C84001048AB = {
+			buildPhases = (
+				FF1C919307021C84001048AB,
+				FF1C919407021C84001048AB,
+				FF1C919607021C84001048AB,
+				FF1C919807021C84001048AB,
+				FF1C919907021C84001048AB,
+			);
+			buildSettings = {
+				GCC_TREAT_WARNINGS_AS_ERRORS = YES;
+				GCC_VERSION = 3.3;
+				INSTALL_PATH = /usr/bin;
+				MACOSX_DEPLOYMENT_TARGET = 10.2;
+				OTHER_CFLAGS = "-no-cpp-precomp -mdynamic-no-pic -D__MACOSX__ -DmDNSResponderVersion=$(MVERS) -I../mDNSShared";
+				OTHER_LDFLAGS = "";
+				OTHER_REZFLAGS = "";
+				PRODUCT_NAME = "dns-sd";
+				REZ_EXECUTABLE = YES;
+				SECTORDER_FLAGS = "";
+				STRIPFLAGS = "-S";
+				WARNING_CFLAGS = "-W -Wall -Wmissing-prototypes -Wno-four-char-constants -Wno-unknown-pragmas";
+			};
+			dependencies = (
+			);
+			isa = PBXToolTarget;
+			name = "dns-sd command-line tool";
+			productInstallPath = /usr/bin;
+			productName = "dns-sd command-line tool";
+			productReference = FF1C919B07021C84001048AB;
+		};
+		FF1C919307021C84001048AB = {
+			buildActionMask = 2147483647;
+			files = (
+			);
+			isa = PBXHeadersBuildPhase;
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		FF1C919407021C84001048AB = {
+			buildActionMask = 2147483647;
+			files = (
+				FF1C91A007021E40001048AB,
+			);
+			isa = PBXSourcesBuildPhase;
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		FF1C919607021C84001048AB = {
+			buildActionMask = 2147483647;
+			files = (
+			);
+			isa = PBXFrameworksBuildPhase;
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		FF1C919807021C84001048AB = {
+			buildActionMask = 2147483647;
+			files = (
+			);
+			isa = PBXRezBuildPhase;
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		FF1C919907021C84001048AB = {
 			buildActionMask = 8;
 			dstPath = /usr/share/man/man1;
 			dstSubfolderSpec = 0;
 			files = (
-				FF0E0B5E065ADCA400FE4D9C,
+				FF1C919E07021D78001048AB,
 			);
 			isa = PBXCopyFilesBuildPhase;
 			runOnlyForDeploymentPostprocessing = 1;
 		};
-		FF0E0B5D065ADC7600FE4D9C = {
+		FF1C919B07021C84001048AB = {
+			isa = PBXExecutableFileReference;
+			path = "dns-sd";
+			refType = 3;
+		};
+		FF1C919D07021D77001048AB = {
 			fileEncoding = 4;
 			isa = PBXFileReference;
-			name = mDNS.1;
-			path = ../mDNSShared/mDNS.1;
+			name = "dns-sd.1";
+			path = "../mDNSShared/dns-sd.1";
 			refType = 2;
 		};
-		FF0E0B5E065ADCA400FE4D9C = {
-			fileRef = FF0E0B5D065ADC7600FE4D9C;
+		FF1C919E07021D78001048AB = {
+			fileRef = FF1C919D07021D77001048AB;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		FF1C919F07021E3F001048AB = {
+			fileEncoding = 4;
+			isa = PBXFileReference;
+			name = "dns-sd.c";
+			path = "../Clients/dns-sd.c";
+			refType = 2;
+		};
+		FF1C91A007021E40001048AB = {
+			fileRef = FF1C919F07021E3F001048AB;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		FF25792906C9A70800376F7B = {
+			buildPhases = (
+				FF25792A06C9A70800376F7B,
+				FF25792D06C9A70800376F7B,
+				FF25793A06C9A70800376F7B,
+				FF25793F06C9A70800376F7B,
+				FF25794006C9A70800376F7B,
+			);
+			buildSettings = {
+				FRAMEWORK_SEARCH_PATHS = "";
+				GCC_TREAT_WARNINGS_AS_ERRORS = YES;
+				GCC_VERSION = 3.3;
+				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 -mdynamic-no-pic -D__MACOSX__ -DmDNSResponderVersion=$(MVERS)";
+				OTHER_LDFLAGS = "";
+				OTHER_REZFLAGS = "";
+				PRODUCT_NAME = dnsextd;
+				REZ_EXECUTABLE = YES;
+				SECTORDER_FLAGS = "";
+				STRIPFLAGS = "-S";
+				WARNING_CFLAGS = "-W -Wall -Wmissing-prototypes -Wno-four-char-constants -Wno-unknown-pragmas";
+			};
+			dependencies = (
+			);
+			isa = PBXToolTarget;
+			name = dnsextd;
+			productInstallPath = /usr/sbin;
+			productName = mDNSResponder;
+			productReference = FF25794406C9A70800376F7B;
+		};
+		FF25792A06C9A70800376F7B = {
+			buildActionMask = 2147483647;
+			files = (
+				FF25792B06C9A70800376F7B,
+				FF25792C06C9A70800376F7B,
+			);
+			isa = PBXHeadersBuildPhase;
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		FF25792B06C9A70800376F7B = {
+			fileRef = 6575FBFF022EAFBA00000109;
 			isa = PBXBuildFile;
 			settings = {
 			};
 		};
+		FF25792C06C9A70800376F7B = {
+			fileRef = F5E11B5B04A28126019798ED;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		FF25792D06C9A70800376F7B = {
+			buildActionMask = 2147483647;
+			files = (
+				FF25793606C9A70800376F7B,
+				FF25793806C9A70800376F7B,
+				FF25794706C9A8BF00376F7B,
+				FF25794906C9A97400376F7B,
+				FF25794A06C9A98700376F7B,
+				FF25794D06C9A9D500376F7B,
+				FF25794E06C9AA3000376F7B,
+				FF25795006C9AA8B00376F7B,
+			);
+			isa = PBXSourcesBuildPhase;
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		FF25793606C9A70800376F7B = {
+			fileRef = 7F18A9F60587CEF6001880B3;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		FF25793806C9A70800376F7B = {
+			fileRef = 7F461DB5062DBF2900672BF3;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		FF25793A06C9A70800376F7B = {
+			buildActionMask = 2147483647;
+			files = (
+				FF25793B06C9A70800376F7B,
+				FF25793C06C9A70800376F7B,
+				FF25793D06C9A70800376F7B,
+				FF25793E06C9A70800376F7B,
+			);
+			isa = PBXFrameworksBuildPhase;
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		FF25793B06C9A70800376F7B = {
+			fileRef = 09AB6884FE841BABC02AAC07;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		FF25793C06C9A70800376F7B = {
+			fileRef = 65713D46025A293200000109;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		FF25793D06C9A70800376F7B = {
+			fileRef = 00CA213D02786FC30CCA2C71;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		FF25793E06C9A70800376F7B = {
+			fileRef = 7F869685066EE02400D2A2DC;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		FF25793F06C9A70800376F7B = {
+			buildActionMask = 2147483647;
+			files = (
+			);
+			isa = PBXRezBuildPhase;
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		FF25794006C9A70800376F7B = {
+			buildActionMask = 8;
+			dstPath = /usr/share/man/man8;
+			dstSubfolderSpec = 0;
+			files = (
+				FFF4F63B06CFE4DD00459EFD,
+			);
+			isa = PBXCopyFilesBuildPhase;
+			runOnlyForDeploymentPostprocessing = 1;
+		};
+		FF25794406C9A70800376F7B = {
+			isa = PBXExecutableFileReference;
+			path = dnsextd;
+			refType = 3;
+		};
+		FF25794606C9A8BF00376F7B = {
+			fileEncoding = 4;
+			isa = PBXFileReference;
+			name = dnsextd.c;
+			path = ../mDNSPosix/dnsextd.c;
+			refType = 2;
+		};
+		FF25794706C9A8BF00376F7B = {
+			fileRef = FF25794606C9A8BF00376F7B;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		FF25794906C9A97400376F7B = {
+			fileRef = 7F18A9F70587CEF6001880B3;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		FF25794A06C9A98700376F7B = {
+			fileRef = DBAAFE29057E8F4D0085CAD0;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		FF25794C06C9A9D500376F7B = {
+			fileEncoding = 4;
+			isa = PBXFileReference;
+			name = mDNSPosix.c;
+			path = ../mDNSPosix/mDNSPosix.c;
+			refType = 2;
+		};
+		FF25794D06C9A9D500376F7B = {
+			fileRef = FF25794C06C9A9D500376F7B;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		FF25794E06C9AA3000376F7B = {
+			fileRef = DBAAFE2C057E8F660085CAD0;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		FF25794F06C9AA8B00376F7B = {
+			fileEncoding = 4;
+			isa = PBXFileReference;
+			name = mDNSUNP.c;
+			path = ../mDNSPosix/mDNSUNP.c;
+			refType = 2;
+		};
+		FF25795006C9AA8B00376F7B = {
+			fileRef = FF25794F06C9AA8B00376F7B;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		FF25795106C9AB1D00376F7B = {
+			isa = PBXTargetDependency;
+			target = FF25792906C9A70800376F7B;
+		};
+		FF37BE9207614059003C0420 = {
+			buildActionMask = 2147483647;
+			files = (
+			);
+			generatedFileNames = (
+			);
+			isa = PBXShellScriptBuildPhase;
+			neededFileNames = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+			shellPath = /bin/sh;
+			shellScript = "if [ -e /usr/local/lib/libdnsinfo.a ]\nthen\nrm -f \"${OBJROOT}/libdnsinfo.a\"\nelse\ntouch ${OBJROOT}/empty.c\ncc ${OBJROOT}/empty.c -c -o \"${OBJROOT}/libdnsinfo.a\"\nrm -f ${OBJROOT}/empty.c\nfi";
+		};
 		FF485D5105632E0000130380 = {
 			fileEncoding = 4;
 			isa = PBXFileReference;
@@ -1285,6 +1620,25 @@
 			settings = {
 			};
 		};
+		FFCB6D73075D539900B8AF62 = {
+			fileEncoding = 4;
+			isa = PBXFileReference;
+			name = PlatformCommon.c;
+			path = ../mDNSShared/PlatformCommon.c;
+			refType = 2;
+		};
+		FFCB6D74075D539900B8AF62 = {
+			fileRef = FFCB6D73075D539900B8AF62;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		FFCB6D75075D595E00B8AF62 = {
+			fileRef = FFCB6D73075D539900B8AF62;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
 		FFD41DDA0664157900F0C438 = {
 			includeInIndex = 0;
 			isa = PBXZipArchiveReference;
@@ -1316,6 +1670,48 @@
 			isa = PBXTargetDependency;
 			target = DB2CC4530662DD6800335AB3;
 		};
+		FFF4F63A06CFE4DD00459EFD = {
+			fileEncoding = 4;
+			isa = PBXFileReference;
+			name = dnsextd.8;
+			path = ../mDNSShared/dnsextd.8;
+			refType = 2;
+		};
+		FFF4F63B06CFE4DD00459EFD = {
+			fileRef = FFF4F63A06CFE4DD00459EFD;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		FFF4F63C06CFE53300459EFD = {
+			buildActionMask = 8;
+			dstPath = /usr/share/man/man1;
+			dstSubfolderSpec = 0;
+			files = (
+				FFF4F63D06CFE54300459EFD,
+			);
+			isa = PBXCopyFilesBuildPhase;
+			runOnlyForDeploymentPostprocessing = 1;
+		};
+		FFF4F63D06CFE54300459EFD = {
+			fileRef = FF0E0B5D065ADC7600FE4D9C;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		FFF7174A07614A8600E10551 = {
+			buildActionMask = 2147483647;
+			files = (
+			);
+			generatedFileNames = (
+			);
+			isa = PBXShellScriptBuildPhase;
+			neededFileNames = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+			shellPath = /bin/sh;
+			shellScript = "if [ -e /usr/local/lib/libdnsinfo.a ]\nthen\nrm -f \"${OBJROOT}/libdnsinfo.a\"\nelse\ntouch ${OBJROOT}/empty.c\ncc ${OBJROOT}/empty.c -c -o \"${OBJROOT}/libdnsinfo.a\"\nrm -f ${OBJROOT}/empty.c\nfi";
+		};
 	};
 	rootObject = 08FB7793FE84155DC02AAC07;
 }
diff --git a/mDNSPosix/Client.c b/mDNSPosix/Client.c
index 193272d..ad3480c 100755
--- a/mDNSPosix/Client.c
+++ b/mDNSPosix/Client.c
@@ -1,10 +1,9 @@
-/*
- * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * 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
@@ -25,6 +24,20 @@
     Change History (most recent first):
 
 $Log: Client.c,v $
+Revision 1.14  2004/11/30 22:37:00  cheshire
+Update copyright dates and add "Mode: C; tab-width: 4" headers
+
+Revision 1.13  2004/10/19 21:33:20  cheshire
+<rdar://problem/3844991> Cannot resolve non-local registrations using the mach API
+Added flag 'kDNSServiceFlagsForceMulticast'. Passing through an interface id for a unicast name
+doesn't force multicast unless you set this flag to indicate explicitly that this is what you want
+
+Revision 1.12  2004/09/17 01:08:53  cheshire
+Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
+  The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
+  declared in that file are ONLY appropriate to single-address-space embedded applications.
+  For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
+
 Revision 1.11  2003/11/17 20:14:32  cheshire
 Typo: Wrote "domC" where it should have said "domainC"
 
@@ -70,7 +83,7 @@ First checkin
 #include <unistd.h>
 #include <stdlib.h>
 
-#include "mDNSClientAPI.h"// Defines the interface to the mDNS core code
+#include "mDNSEmbeddedAPI.h"// Defines the interface to the mDNS core code
 #include "mDNSPosix.h"    // Defines the specific types needed to run mDNS on this platform
 #include "ExampleClientApp.h"
 
@@ -236,7 +249,7 @@ int main(int argc, char **argv)
         MakeDomainNameFromDNSNameString(&type, gServiceType);
         MakeDomainNameFromDNSNameString(&domain, "local.");
 
-        status = mDNS_StartBrowse(&mDNSStorage, &question, &type, &domain, mDNSInterface_Any, BrowseCallback, NULL);
+        status = mDNS_StartBrowse(&mDNSStorage, &question, &type, &domain, mDNSInterface_Any, mDNSfalse, BrowseCallback, NULL);
     
         // Run the platform main event loop until the user types ^C. 
         // The BrowseCallback routine is responsible for printing 
diff --git a/mDNSPosix/ExampleClientApp.c b/mDNSPosix/ExampleClientApp.c
index 8561388..17843af 100644
--- a/mDNSPosix/ExampleClientApp.c
+++ b/mDNSPosix/ExampleClientApp.c
@@ -1,10 +1,9 @@
-/*
- * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * 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
@@ -25,6 +24,18 @@
     Change History (most recent first):
 
 $Log: ExampleClientApp.c,v $
+Revision 1.12  2004/11/30 22:37:00  cheshire
+Update copyright dates and add "Mode: C; tab-width: 4" headers
+
+Revision 1.11  2004/09/17 01:08:53  cheshire
+Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
+  The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
+  declared in that file are ONLY appropriate to single-address-space embedded applications.
+  For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
+
+Revision 1.10  2004/09/16 01:58:22  cheshire
+Fix compiler warnings
+
 Revision 1.9  2003/08/12 19:56:26  cheshire
 Update to APSL 2.0
 
@@ -49,7 +60,7 @@ Add log header
 #include <netdb.h>			// For gethostbyname()
 #include <signal.h>			// For SIGINT, etc.
 
-#include "mDNSClientAPI.h"  // Defines the interface to the client layer above
+#include "mDNSEmbeddedAPI.h"  // Defines the interface to the client layer above
 #include "mDNSPosix.h"      // Defines the specific types needed to run mDNS on this platform
 
 //*******************************************************************************************
@@ -60,7 +71,7 @@ static volatile mDNSBool StopNow;
 mDNSlocal void HandleSIG(int signal)
 	{
 	(void)signal;	// Unused
-	debugf("");
+	debugf("%s","");
 	debugf("HandleSIG");
 	StopNow = mDNStrue;
 	}
diff --git a/mDNSPosix/ExampleClientApp.h b/mDNSPosix/ExampleClientApp.h
index d9b20c5..fa9f0fc 100644
--- a/mDNSPosix/ExampleClientApp.h
+++ b/mDNSPosix/ExampleClientApp.h
@@ -1,10 +1,9 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * 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
@@ -25,6 +24,9 @@
     Change History (most recent first):
 
 $Log: ExampleClientApp.h,v $
+Revision 1.6  2004/11/30 22:37:00  cheshire
+Update copyright dates and add "Mode: C; tab-width: 4" headers
+
 Revision 1.5  2003/08/12 19:56:26  cheshire
 Update to APSL 2.0
 
diff --git a/mDNSPosix/Identify.c b/mDNSPosix/Identify.c
index ed9fd7d..27b2505 100644
--- a/mDNSPosix/Identify.c
+++ b/mDNSPosix/Identify.c
@@ -1,10 +1,9 @@
-/*
- * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * 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
@@ -38,6 +37,41 @@
     Change History (most recent first):
 
 $Log: Identify.c,v $
+Revision 1.33  2004/11/30 22:37:00  cheshire
+Update copyright dates and add "Mode: C; tab-width: 4" headers
+
+Revision 1.32  2004/10/19 21:33:21  cheshire
+<rdar://problem/3844991> Cannot resolve non-local registrations using the mach API
+Added flag 'kDNSServiceFlagsForceMulticast'. Passing through an interface id for a unicast name
+doesn't force multicast unless you set this flag to indicate explicitly that this is what you want
+
+Revision 1.31  2004/10/16 00:17:00  cheshire
+<rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check
+
+Revision 1.30  2004/09/21 23:29:51  cheshire
+<rdar://problem/3680045> DNSServiceResolve should delay sending packets
+
+Revision 1.29  2004/09/17 01:08:53  cheshire
+Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
+  The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
+  declared in that file are ONLY appropriate to single-address-space embedded applications.
+  For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
+
+Revision 1.28  2004/09/17 00:31:52  cheshire
+For consistency with ipv6, renamed rdata field 'ip' to 'ipv4'
+
+Revision 1.27  2004/09/16 01:58:22  cheshire
+Fix compiler warnings
+
+Revision 1.26  2004/08/24 21:55:07  cheshire
+Don't try to build IPv6 code on systems that don't have IPv6
+
+Revision 1.25  2004/07/20 23:42:37  cheshire
+Update to use only "_services._dns-sd._udp.local." meta-query for service enumeration
+
+Revision 1.24  2004/06/15 02:39:47  cheshire
+When displaying error message, only show command name, not entire path
+
 Revision 1.23  2004/05/18 23:51:26  cheshire
 Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
 
@@ -137,7 +171,7 @@ Add mDNSIdentify tool, used to discover what version of mDNSResponder a particul
 #include <arpa/inet.h>
 #include <signal.h>
 
-#include "mDNSClientAPI.h"// Defines the interface to the mDNS core code
+#include "mDNSEmbeddedAPI.h"// Defines the interface to the mDNS core code
 #include "mDNSPosix.h"    // Defines the specific types needed to run mDNS on this platform
 #include "ExampleClientApp.h"
 
@@ -177,16 +211,16 @@ mDNSlocal mDNSu32 mprintf(const char *format, ...)
 
 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 ttl)
+	const mDNSInterfaceID InterfaceID)
 	{
+	(void)dstaddr; // Unused
 	// 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);
+	// For now, the simplest way to allow that is to pretend it was received via multicast so that mDNSCore doesn't reject the packet
+	__MDNS__mDNSCoreReceive(m, msg, end, srcaddr, srcport, &AllDNSLinkGroup_v4, dstport, InterfaceID);
 	}
 
 static void NameCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
@@ -199,7 +233,7 @@ static void NameCallback(mDNS *const m, DNSQuestion *question, const ResourceRec
 		{
 		ConvertDomainNameToCString(&answer->rdata->u.name, hostname);
 		StopNow = 1;
-		mprintf("%##s %s %##s\n", answer->name.c, DNSTypeName(answer->rrtype), &answer->rdata->u.name.c);
+		mprintf("%##s %s %##s\n", answer->name.c, DNSTypeName(answer->rrtype), answer->rdata->u.name.c);
 		}
 	}
 
@@ -213,9 +247,9 @@ static void InfoCallback(mDNS *const m, DNSQuestion *question, const ResourceRec
 		if (!id.NotAnInteger) id = lastid;
 		NumAnswers++;
 		NumAddr++;
-		mprintf("%##s %s %.4a\n", answer->name.c, DNSTypeName(answer->rrtype), &answer->rdata->u.ip);
+		mprintf("%##s %s %.4a\n", answer->name.c, DNSTypeName(answer->rrtype), &answer->rdata->u.ipv4);
 		hostaddr.type = mDNSAddrType_IPv4;	// Prefer v4 target to v6 target, for now
-		hostaddr.ip.v4 = answer->rdata->u.ip;
+		hostaddr.ip.v4 = answer->rdata->u.ipv4;
 		}
 	else if (answer->rrtype == kDNSType_AAAA)
 		{
@@ -257,7 +291,7 @@ static void ServicesCallback(mDNS *const m, DNSQuestion *question, const Resourc
 		{
 		NumAnswers++;
 		NumAddr++;
-		mprintf("%##s %s %##s\n", answer->name.c, DNSTypeName(answer->rrtype), &answer->rdata->u.name.c);
+		mprintf("%##s %s %##s\n", answer->name.c, DNSTypeName(answer->rrtype), answer->rdata->u.name.c);
 		StopNow = 1;
 		}
 	}
@@ -295,9 +329,12 @@ mDNSlocal mStatus StartQuery(DNSQuestion *q, char *qname, mDNSu16 qtype, const m
 	q->Target           = target ? *target : zeroAddr;
 	q->TargetPort       = MulticastDNSPort;
 	q->TargetQID        = zeroID;
-	q->InterfaceID      = mDNSInterface_ForceMCast;
+	q->InterfaceID      = mDNSInterface_Any;
 	q->qtype            = qtype;
 	q->qclass           = kDNSClass_IN;
+	q->LongLived        = mDNSfalse;
+	q->ExpectUnique     = mDNStrue;
+	q->ForceMCast       = mDNStrue;		// Query via multicast, even for apparently uDNS names like 1.1.1.17.in-addr.arpa.
 	q->QuestionCallback = callback;
 	q->QuestionContext  = NULL;
 
@@ -333,17 +370,20 @@ mDNSlocal int DoQuery(DNSQuestion *q, char *qname, mDNSu16 qtype, const mDNSAddr
 mDNSlocal void HandleSIG(int signal)
 	{
 	(void)signal;	// Unused
-	debugf("");
+	debugf("%s","");
 	debugf("HandleSIG");
 	StopNow = 2;
 	}
 
 mDNSexport int main(int argc, char **argv)
 	{
+	const char *progname = strrchr(argv[0], '/') ? strrchr(argv[0], '/') + 1 : argv[0];
 	int this_arg = 1;
 	mStatus status;
 	struct in_addr s4;
+#if HAVE_IPV6
 	struct in6_addr s6;
+#endif
 	char buffer[256];
 	DNSQuestion q;
 
@@ -382,6 +422,7 @@ mDNSexport int main(int argc, char **argv)
 			DoQuery(&q, buffer, kDNSType_PTR, &target, NameCallback);
 			if (StopNow == 2) break;
 			}
+#if HAVE_IPV6
 		else if (inet_pton(AF_INET6, arg, &s6) == 1)
 			{
 			int i;
@@ -400,6 +441,7 @@ mDNSexport int main(int argc, char **argv)
 			DoQuery(&q, buffer, kDNSType_PTR, &target, NameCallback);
 			if (StopNow == 2) break;
 			}
+#endif
 		else
 			strcpy(hostname, arg);
 	
@@ -409,16 +451,14 @@ mDNSexport int main(int argc, char **argv)
 	
 		if (hardware[0] || software[0])
 			{
-			DNSQuestion q1, q2;
+			DNSQuestion q1;
 			printf("HINFO Hardware: %s\n", hardware);
 			printf("HINFO Software: %s\n", software);
 			// We need to make sure the services query is targeted
 			if (target.type == 0) target = hostaddr;
-			StartQuery(&q1, "_services._mdns._udp.local.",   kDNSQType_ANY, &target, ServicesCallback);
-			StartQuery(&q2, "_services._dns-sd._udp.local.", kDNSQType_ANY, &target, ServicesCallback);
+			StartQuery(&q1, "_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)
@@ -436,6 +476,6 @@ mDNSexport int main(int argc, char **argv)
 	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", progname);
 	return(-1);
 	}
diff --git a/mDNSPosix/Makefile b/mDNSPosix/Makefile
index 9d28ad5..1f8b65b 100755
--- a/mDNSPosix/Makefile
+++ b/mDNSPosix/Makefile
@@ -1,25 +1,93 @@
-# 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@
+# Copyright (c) 2002-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.
 #
 # $Log: Makefile,v $
+# Revision 1.53  2004/12/01 20:04:31  cheshire
+# Tidy up alignment
+#
+# Revision 1.52  2004/12/01 19:46:12  cheshire
+# Add install case for Suse 9 (rc*.d directories *inside* the init.d directory)
+#
+# Revision 1.51  2004/12/01 03:30:29  cheshire
+# <rdar://problem/3889346> Add Unicast DNS support to mDNSPosix
+#
+# Revision 1.50  2004/12/01 01:14:20  cheshire
+# Add $(LIBFLAGS) to cc command to build dnsextd (required for Solaris)
+#
+# Revision 1.49  2004/11/11 01:44:52  cheshire
+# Updated error message
+#
+# Revision 1.48  2004/10/06 02:22:19  cheshire
+# Changed MacRoman copyright symbol (should have been UTF-8 in any case :-) to ASCII-compatible "(c)"
+#
+# Revision 1.47  2004/10/01 22:15:54  rpantos
+# rdar://problem/3824265: Replace APSL in client lib with BSD license.
+#
+# Revision 1.46  2004/09/24 21:15:25  cheshire
+# <rdar://problem/3724985> Library "libmdns" misnamed; should be "libdns_sd"
+#
+# Revision 1.45  2004/09/22 16:23:41  cheshire
+# Modify installation for compatibility with Gentoo Linux
+# (Thanks to David Black for this information)
+#
+# Revision 1.44  2004/09/17 01:08:53  cheshire
+# Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
+#   The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
+#   declared in that file are ONLY appropriate to single-address-space embedded applications.
+#   For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
+#
+# Revision 1.43  2004/09/17 00:30:11  cheshire
+# Added some '@' signs to make build output less verbose --
+# when there's too much on the screen it's easy to miss build errors and warnings
+#
+# Revision 1.42  2004/08/24 22:04:37  cheshire
+# Need to specify -lpthread for building dnsextd
+#
+# Revision 1.41  2004/08/11 00:43:26  ksekar
+# <rdar://problem/3722542>: DNS Extension daemon for DNS Update Lease
+#
+# Revision 1.40  2004/07/08 21:45:55  cheshire
+# Make nss_mdns only build on Linux. We can add it to other targets (Solaris,
+# FreeBSD, etc., as we verify them). In particular, NSS is NOT supported on
+# OS X, so including it for "os=jaguar" or "os=panther" broke those builds.
+#
+# Revision 1.39  2004/06/29 03:34:28  cheshire
+# Add 'dot-local' Name Service Switch support from Andrew White at NICTA
+#
+# Revision 1.38  2004/06/25 02:19:40  rpantos
+# And FreeBSD...
+#
+# Revision 1.37  2004/06/25 00:51:09  rpantos
+# And fix the Java build for Posix on Solaris, too.
+#
+# Revision 1.36  2004/06/25 00:26:27  rpantos
+# Changes to fix the Posix build on Solaris.
+#
+# Revision 1.35  2004/06/18 18:51:31  cheshire
+# Add (commented out) "-pedantic" for when we want to check for "mixed declarations and code" warnings
+#
 # Revision 1.34  2004/05/25 18:29:33  cheshire
 # Move DNSServiceConstructFullName() from dnssd_clientstub.c to dnssd_clientlib.c,
 # so that it's also accessible to dnssd_clientshim.c (single address space) clients.
@@ -85,7 +153,7 @@
 #
 # 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.
+# Best solution is just to combine mDNSEmbeddedAPI.h and mDNSPlatformFunctions.h into a single file.
 #
 # Revision 1.13  2003/08/06 18:20:51  cheshire
 # Makefile cleanup
@@ -114,13 +182,13 @@
 # Added NetMonitor.c
 #
 
-# This Makefile builds an mDNSResponder daemon and a libmdns.so shared library 
+# This Makefile builds an mDNSResponder daemon and a libdns_sd.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.
+# 'sudo make install [DEBUG=1]' to install mdnsd daemon and libdns_sd.
 #
 # Notes:
 # $@ means "The file name of the target of the rule"
@@ -137,15 +205,16 @@ COREDIR = ../mDNSCore
 SHAREDDIR = ../mDNSShared
 JDK = /usr/jdk
 
-CC = cc
-LD = ld
+CC = @cc
+LD = ld -shared
 CP = cp
 RM = rm
 LN = ln -s -f
 CFLAGS_COMMON = -I. -I$(COREDIR) -I$(SHAREDDIR) -W -Wall -DPID_FILE=\"/var/run/mdnsd.pid\"
-LDFLAGS = -shared
+LIBFLAGS =
+DNSEXT_FLAGS = -D_REENTRANT -g -Wall -lpthread
 LDSUFFIX = so
-JAVACFLAGS_OS = -fPIC -shared -lmdns
+JAVACFLAGS_OS = -fPIC -shared -ldns_sd
 
 # Set up diverging paths for debug vs. prod builds
 DEBUG=0
@@ -155,7 +224,7 @@ OBJDIR = objects/debug
 BUILDDIR = build/debug
 STRIP = echo 
 else
-CFLAGS_DEBUG = -Os -DMDNS_DEBUGMSGS=0 
+CFLAGS_DEBUG = -O0 -DMDNS_DEBUGMSGS=0 
 OBJDIR = objects/prod
 BUILDDIR = build/prod
 STRIP = strip -S 
@@ -163,16 +232,29 @@ 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 -DNOT_HAVE_SOCKLEN_T -DNOT_HAVE_IF_NAMETOINDEX \
+	 -DLOG_PERROR=0 -D_XPG4_2 -D__EXTENSIONS__ -DHAVE_BROKEN_RECVIF_NAME -DUSE_TCP_LOOPBACK
+CC = gcc
+LD = gcc -shared
+LIBFLAGS = -lsocket -lnsl
+JAVACFLAGS_OS += -I$(JDK)/include/solaris
+ifneq ($(DEBUG),1)
+STRIP = strip
+endif
 else
+
 ifeq ($(os),linux)
 CFLAGS_OS = -DNOT_HAVE_SA_LEN -DUSES_NETLINK
 JAVACFLAGS_OS += -I$(JDK)/include/linux
+OPTIONALTARG = nss_mdns
+OPTINSTALL   = InstalledNSS
 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"
@@ -180,29 +262,35 @@ LOCALBASE?=/usr/local
 INSTBASE=$(LOCALBASE)
 STARTUPSCRIPTNAME=mdns.sh
 CFLAGS_OS =
+JAVACFLAGS_OS += -I$(JDK)/include/freebsd
 LDCONFIG = ldconfig
 else
+
 ifeq ($(os),openbsd)
 CFLAGS_OS = -DHAVE_BROKEN_RECVDSTADDR
 LDCONFIG = ldconfig
 else
+
 ifeq ($(os),jaguar)
 CFLAGS_OS = -DHAVE_IPV6 -no-cpp-precomp -DNOT_HAVE_SOCKLEN_T
-LD = libtool
-LDFLAGS = -dynamic -lSystem
+LD = libtool -dynamic
+LIBFLAGS = -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 -no-cpp-precomp
-LD = libtool
-LDFLAGS = -dynamic -lSystem
+CFLAGS_OS = -DHAVE_IPV6 -no-cpp-precomp #-pedantic
+LD = libtool -dynamic
+LIBFLAGS = -lSystem
 LDSUFFIX = dylib
 JDK = /System/Library/Frameworks/JavaVM.framework/Home
 JAVACFLAGS_OS = -dynamiclib -I/System/Library/Frameworks/JavaVM.framework/Headers -framework JavaVM 
 else
-$(error ERROR: Must specify target OS on command-line: "make os={jaguar,panther,linux,netbsd,freebsd,openbsd,solaris} [target]") 
+
+$(error ERROR: Must specify target OS on command-line, e.g. "make os=panther [target]".\
+Supported operating systems include: jaguar, panther, linux, netbsd, freebsd, openbsd, solaris) 
 endif
 endif
 endif
@@ -211,6 +299,12 @@ endif
 endif
 endif
 
+NSSLIBNAME  := libnss_mdns
+NSSVERSION  := 0.2
+NSSLIBFILE  := $(NSSLIBNAME)-$(NSSVERSION).so
+NSSLINKNAME := $(NSSLIBNAME).so.2
+NSSINSTPATH := /lib
+
 # If not otherwise defined, we install into /usr/lib and /usr/include
 # and our startup script is called mdns (e.g. /etc/init.d/mdns)
 INSTBASE?=/usr
@@ -224,7 +318,19 @@ CFLAGS_OS += -DHAVE_IPV6=0
 endif
 endif
 
-# If directory /etc/rc.d/init.d/ exists, then we install into that (old Linux)
+# If directory /usr/share/man exists, then we install man pages into that, else /usr/man
+ifeq ($(wildcard /usr/share/man), /usr/share/man)
+MANPATH := /usr/share/man
+else
+MANPATH := /usr/man
+endif
+
+# If directories /etc/init.d/rc*.d exist, then we install into that (Suse)
+ifeq ($(wildcard /etc/init.d/rc2.d/), /etc/init.d/rc2.d/)
+STARTUPSCRIPTDIR = /etc/init.d
+RUNLEVELSCRIPTSDIR = /etc/init.d
+else
+# else 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
@@ -238,14 +344,15 @@ else
 STARTUPSCRIPTDIR = $(INSTBASE)/etc/rc.d
 endif
 endif
+endif
 
 CFLAGS = $(CFLAGS_COMMON) $(CFLAGS_OS) $(CFLAGS_DEBUG)
 
 #############################################################################
 
-all: setup Daemon libmdns Client Responder ProxyResponder Identify NetMonitor
+all: setup Daemon libdns_sd Client Responder ProxyResponder Identify NetMonitor dnsextd $(OPTIONALTARG)
 
-install: setup InstalledDaemon InstalledLib InstalledStartup
+install: setup InstalledDaemon InstalledLib InstalledStartup InstalledManPages $(OPTINSTALL)
 
 # 'setup' sets up the build directory structure the way we want
 setup:
@@ -264,41 +371,57 @@ clean:
 # daemon target builds the daemon
 DAEMONOBJS = $(OBJDIR)/PosixDaemon.c.o $(OBJDIR)/mDNSPosix.c.o $(OBJDIR)/mDNSUNP.c.o $(OBJDIR)/mDNS.c.o \
              $(OBJDIR)/DNSDigest.c.o $(OBJDIR)/uDNS.c.o $(OBJDIR)/DNSCommon.c.o $(OBJDIR)/uds_daemon.c.o \
-             $(OBJDIR)/mDNSDebug.c.o $(OBJDIR)/dnssd_ipc.c.o $(OBJDIR)/GenLinkedList.c.o 
+             $(OBJDIR)/mDNSDebug.c.o $(OBJDIR)/dnssd_ipc.c.o $(OBJDIR)/GenLinkedList.c.o $(OBJDIR)/PlatformCommon.c.o 
 
 Daemon: setup $(BUILDDIR)/mdnsd
 	@echo "Responder daemon done"
 
 $(BUILDDIR)/mdnsd: $(DAEMONOBJS)
-	$(CC) -o $@ $+
-	$(STRIP) $@
+	$(CC) -o $@ $+ $(CFLAGS) $(LIBFLAGS)
+	@$(STRIP) $@
 
-# libmdns target builds the client library
-libmdns: setup $(BUILDDIR)/libmdns.$(LDSUFFIX)
+# libdns_sd target builds the client library
+libdns_sd: setup $(BUILDDIR)/libdns_sd.$(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) $@
+CLIENTLIBOBJS = $(OBJDIR)/dnssd_clientlib.c.so.o $(OBJDIR)/dnssd_clientstub.c.so.o $(OBJDIR)/dnssd_ipc.c.so.o
+
+$(BUILDDIR)/libdns_sd.$(LDSUFFIX): $(CLIENTLIBOBJS)
+	@$(LD) $(LIBFLAGS) -o $@ $+
+	@$(STRIP) $@
+
+# nss_mdns target builds the Name Service Switch module
+nss_mdns: setup $(BUILDDIR)/$(NSSLIBFILE)
+	@echo "Name Service Switch module done"
+
+$(BUILDDIR)/$(NSSLIBFILE): $(CLIENTLIBOBJS) $(OBJDIR)/nss_mdns.c.so.o
+	@$(LD) $(LIBFLAGS) -o $@ $+
+	@$(STRIP) $@
 
 #############################################################################
 
 # The Install targets place built stuff in their proper places
 InstalledDaemon: $(INSTBASE)/sbin/mdnsd
-	@echo $< " installed"
+	@echo $+ " installed"
 
-InstalledLib: $(INSTBASE)/lib/libmdns.$(LDSUFFIX).$(LIBVERS) $(INSTBASE)/include/dns_sd.h
-	@echo $< " installed"
+InstalledLib: $(INSTBASE)/lib/libdns_sd.$(LDSUFFIX).$(LIBVERS) $(INSTBASE)/include/dns_sd.h
+	@echo $+ " installed"
 
 InstalledStartup: $(STARTUPSCRIPTDIR)/$(STARTUPSCRIPTNAME)
-	@echo $< " installed"
+	@echo $+ " installed"
+
+InstalledNSS: $(NSSINSTPATH)/$(NSSLINKNAME) /etc/nss_mdns.conf $(MANPATH)/man5/nss_mdns.conf.5 $(MANPATH)/man8/libnss_mdns.8
+	@echo $+ " installed"
+
+InstalledManPages: $(MANPATH)/man8/mdnsd.8
+	@echo $+ " installed"
 
 $(INSTBASE)/sbin/mdnsd: $(BUILDDIR)/mdnsd
 	$(CP) $< $@
 
-$(INSTBASE)/lib/libmdns.$(LDSUFFIX).$(LIBVERS): $(BUILDDIR)/libmdns.$(LDSUFFIX)
+$(INSTBASE)/lib/libdns_sd.$(LDSUFFIX).$(LIBVERS): $(BUILDDIR)/libdns_sd.$(LDSUFFIX)
 	$(CP) $< $@
-	$(LN) $@ $(INSTBASE)/lib/libmdns.$(LDSUFFIX)
+	$(LN) $@ $(INSTBASE)/lib/libdns_sd.$(LDSUFFIX)
 ifdef LDCONFIG
     # -m means 'merge into existing database', -R means 'rescan directories'
 	$(LDCONFIG) -mR
@@ -311,6 +434,9 @@ $(STARTUPSCRIPTDIR)/$(STARTUPSCRIPTNAME): mdnsd.sh $(STARTUPSCRIPTDIR)
 	$(CP) $< $@
 	chmod ugo+x $@
 ifdef RUNLEVELSCRIPTSDIR
+ifeq ($(wildcard $(RUNLEVELSCRIPTSDIR)/runlevels/default), $(RUNLEVELSCRIPTSDIR)/runlevels/default)
+	$(LN) $@ $(RUNLEVELSCRIPTSDIR)/runlevels/default/mdns
+else
 	$(LN) $@ $(RUNLEVELSCRIPTSDIR)/rc2.d/S52mdns
 	$(LN) $@ $(RUNLEVELSCRIPTSDIR)/rc3.d/S52mdns
 	$(LN) $@ $(RUNLEVELSCRIPTSDIR)/rc4.d/S52mdns
@@ -318,6 +444,35 @@ ifdef RUNLEVELSCRIPTSDIR
 	$(LN) $@ $(RUNLEVELSCRIPTSDIR)/rc0.d/K16mdns
 	$(LN) $@ $(RUNLEVELSCRIPTSDIR)/rc6.d/K16mdns
 endif
+endif
+
+$(NSSINSTPATH)/$(NSSLINKNAME): $(NSSINSTPATH)/$(NSSLIBFILE)
+	$(LN) $< $@
+	ldconfig
+
+$(NSSINSTPATH)/$(NSSLIBFILE): $(BUILDDIR)/$(NSSLIBFILE)
+	$(CP) $< $@
+	chmod 444 $@
+
+/etc/nss_mdns.conf: nss_mdns.conf
+	$(CP) $< $@
+	chmod 444 $@
+	# Check the nsswitch.conf file.
+	# If 'mdns' does not already appear on the "hosts:" line, then add it right before 'dns'
+	cp -f /etc/nsswitch.conf /etc/nsswitch.conf.pre-mdns
+	sed -e '/mdns/!s/^\(hosts:.*\)dns\(.*\)/\1mdns dns\2/' /etc/nsswitch.conf.pre-mdns > /etc/nsswitch.conf
+
+$(MANPATH)/man5/%.5: %.5
+	cp $< $@
+	chmod 444 $@
+
+$(MANPATH)/man8/%.8: %.8
+	cp $< $@
+	chmod 444 $@
+
+$(MANPATH)/man8/mdnsd.8: $(SHAREDDIR)/mDNSResponder.8
+	cp $< $@
+	chmod 444 $@
 
 #############################################################################
 
@@ -394,20 +549,26 @@ Identify: setup $(BUILDDIR)/mDNSIdentify
 NetMonitor: setup $(BUILDDIR)/mDNSNetMonitor
 	@echo "NetMonitor done"
 
+dnsextd: setup $(BUILDDIR)/dnsextd
+	@echo "dnsextd done"
+
 $(BUILDDIR)/mDNSClientPosix:         $(APPOBJ)     $(OBJDIR)/Client.c.o
-	$(CC) $+ -o $@
+	$(CC) $+ -o $@ $(LIBFLAGS)
 
 $(BUILDDIR)/mDNSResponderPosix:      $(COMMONOBJ)  $(OBJDIR)/Responder.c.o
-	$(CC) $+ -o $@
+	$(CC) $+ -o $@ $(LIBFLAGS)
 
 $(BUILDDIR)/mDNSProxyResponderPosix: $(COMMONOBJ)  $(OBJDIR)/ProxyResponder.c.o
-	$(CC) $+ -o $@
+	$(CC) $+ -o $@ $(LIBFLAGS)
 
 $(BUILDDIR)/mDNSIdentify:            $(SPECIALOBJ) $(OBJDIR)/Identify.c.o
-	$(CC) $+ -o $@
+	$(CC) $+ -o $@ $(LIBFLAGS)
 
 $(BUILDDIR)/mDNSNetMonitor:          $(SPECIALOBJ) $(OBJDIR)/NetMonitor.c.o
-	$(CC) $+ -o $@
+	$(CC) $+ -o $@ $(LIBFLAGS)
+
+$(BUILDDIR)/dnsextd:                 $(SPECIALOBJ) $(OBJDIR)/dnsextd.c.o
+	$(CC) $+ -o $@ $(LIBFLAGS) $(DNSEXT_FLAGS)
 
 #############################################################################
 
diff --git a/mDNSPosix/NetMonitor.c b/mDNSPosix/NetMonitor.c
index 8bce09e..c8aad7b 100644
--- a/mDNSPosix/NetMonitor.c
+++ b/mDNSPosix/NetMonitor.c
@@ -1,10 +1,9 @@
-/*
- * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * 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
@@ -38,6 +37,27 @@
     Change History (most recent first):
 
 $Log: NetMonitor.c,v $
+Revision 1.70  2004/12/04 02:13:20  cheshire
+Pass proper record type in GetLargeResourceRecord() calls
+
+Revision 1.69  2004/11/30 22:37:01  cheshire
+Update copyright dates and add "Mode: C; tab-width: 4" headers
+
+Revision 1.68  2004/10/23 01:16:01  cheshire
+<rdar://problem/3851677> uDNS operations not always reliable on multi-homed hosts
+
+Revision 1.67  2004/10/16 00:17:00  cheshire
+<rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check
+
+Revision 1.66  2004/09/17 00:31:52  cheshire
+For consistency with ipv6, renamed rdata field 'ip' to 'ipv4'
+
+Revision 1.65  2004/09/16 01:58:22  cheshire
+Fix compiler warnings
+
+Revision 1.64  2004/06/15 02:39:47  cheshire
+When displaying error message, only show command name, not entire path
+
 Revision 1.63  2004/05/18 23:51:26  cheshire
 Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
 
@@ -521,7 +541,7 @@ mDNSlocal void SendUnicastQuery(mDNS *const m, HostEntry *entry, domainname *nam
 		m->ExpectUnicastResponse = m->timenow;
 		}
 
-	mDNSSendDNSMessage(&mDNSStorage, &query, qptr, InterfaceID, target, MulticastDNSPort);
+	mDNSSendDNSMessage(&mDNSStorage, &query, qptr, InterfaceID, target, MulticastDNSPort, -1, mDNSNULL);
 	}
 
 mDNSlocal void AnalyseHost(mDNS *const m, HostEntry *entry, const mDNSInterfaceID InterfaceID)
@@ -563,7 +583,7 @@ mDNSlocal void ShowSortedHostList(HostList *list, int max)
 		{
 		int len = mprintf("%#-25a", &e->addr);
 		if (len > 25) mprintf("\n%25s", "");
-		mprintf("%8d %8d %8d %8d %8d %8d %8d", e->totalops,
+		mprintf("%8lu %8lu %8lu %8lu %8lu %8lu %8lu", e->totalops,
 			e->stat[OP_probe], e->stat[OP_goodbye],
 			e->stat[OP_browseq], e->stat[OP_browsea],
 			e->stat[OP_resolveq], e->stat[OP_resolvea]);
@@ -653,7 +673,7 @@ mDNSlocal void printstats(int max)
 		if (!m) return;
 		m->printed = mDNStrue;
 		if (i==0) mprintf("%-25s%s\n", "Service Type", OPBanner);
-		mprintf("%##-25s%8d %8d %8d %8d %8d %8d %8d\n", &m->srvtype, m->totalops, m->stat[OP_probe],
+		mprintf("%##-25s%8d %8d %8d %8d %8d %8d %8d\n", m->srvtype.c, m->totalops, m->stat[OP_probe],
 			m->stat[OP_goodbye], m->stat[OP_browseq], m->stat[OP_browsea], m->stat[OP_resolveq], m->stat[OP_resolvea]);
 		}
 	}
@@ -665,7 +685,7 @@ mDNSlocal const mDNSu8 *FindUpdate(mDNS *const m, const DNSMessage *const query,
 	for (i = 0; i < query->h.numAuthorities; i++)
 		{
 		const mDNSu8 *p2 = ptr;
-		ptr = GetLargeResourceRecord(m, query, ptr, end, q->InterfaceID, 0, pkt);
+		ptr = GetLargeResourceRecord(m, query, ptr, end, q->InterfaceID, kDNSRecordTypePacketAuth, pkt);
 		if (!ptr) break;
 		if (ResourceRecordAnswersQuestion(&pkt->r.resrec, q)) return(p2);
 		}
@@ -681,7 +701,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, const mDNSAddr *dstaddr, mDNSu8 ttl)
+mDNSlocal void DisplayPacketHeader(const DNSMessage *const msg, const mDNSu8 *const end, const mDNSAddr *srcaddr, mDNSIPPort srcport, const mDNSAddr *dstaddr)
 	{
 	const char *const ptype =   (msg->h.flags.b[0] & kDNSFlag0_QR_Response)             ? "-R- " :
 								(srcport.NotAnInteger == MulticastDNSPort.NotAnInteger) ? "-Q- " : "-LQ-";
@@ -692,8 +712,6 @@ mDNSlocal void DisplayPacketHeader(const DNSMessage *const msg, const mDNSu8 *co
 
 	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)
@@ -713,12 +731,12 @@ mDNSlocal void DisplayResourceRecord(const mDNSAddr *const srcaddr, const char *
 
 	RDataBody *rd = &pktrr->rdata->u;
 	mDNSu8 *rdend = (mDNSu8 *)rd + pktrr->rdlength;
-	mDNSu32 n = mprintf("%#-16a %-5s %-5s%5d %##s -> ", srcaddr, op, DNSTypeName(pktrr->rrtype), pktrr->rroriginalttl, pktrr->name.c);
+	int n = mprintf("%#-16a %-5s %-5s%5lu %##s -> ", srcaddr, op, DNSTypeName(pktrr->rrtype), pktrr->rroriginalttl, pktrr->name.c);
 
 	switch(pktrr->rrtype)
 		{
-		case kDNSType_A:	n += mprintf("%.4a", &rd->ip); break;
-		case kDNSType_PTR:	n += mprintf("%##.*s", MaxWidth - n, &rd->name); break;
+		case kDNSType_A:	n += mprintf("%.4a", &rd->ipv4); break;
+		case kDNSType_PTR:	n += mprintf("%##.*s", MaxWidth - n, rd->name.c); break;
 		case kDNSType_HINFO:// same as kDNSType_TXT below
 		case kDNSType_TXT:	{
 							mDNSu8 *t = rd->txt.c;
@@ -745,7 +763,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, mDNSVal16(rd->srv.port)); break;
+		case kDNSType_SRV:	n += mprintf("%##s:%d", rd->srv.target.c, mDNSVal16(rd->srv.port)); break;
 		default:			{
 							mDNSu8 *s = rd->data;
 							while (s < rdend && p < buffer+MaxWidth)
@@ -792,7 +810,7 @@ mDNSlocal void DisplayError(const mDNSAddr *srcaddr, const mDNSu8 *ptr, const mD
 	}
 
 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)
+	const mDNSAddr *srcaddr, mDNSIPPort srcport, const mDNSAddr *dstaddr, const mDNSInterfaceID InterfaceID)
 	{
 	int i;
 	const mDNSu8 *ptr = msg->data;
@@ -801,7 +819,7 @@ mDNSlocal void DisplayQuery(mDNS *const m, const DNSMessage *const msg, const mD
 	HostEntry *entry = GotPacketFromHost(srcaddr, MQ ? HostPkt_Q : HostPkt_L, msg->h.id);
 	LargeCacheRecord pkt;
 
-	DisplayPacketHeader(msg, end, srcaddr, srcport, dstaddr, ttl);
+	DisplayPacketHeader(msg, end, srcaddr, srcport, dstaddr);
 	if (msg->h.id.NotAnInteger != 0xFFFF)
 		{
 		if (MQ) NumPktQ++; else NumPktL++;
@@ -838,7 +856,7 @@ mDNSlocal void DisplayQuery(mDNS *const m, const DNSMessage *const msg, const mD
 	for (i=0; i<msg->h.numAnswers; i++)
 		{
 		const mDNSu8 *ep = ptr;
-		ptr = GetLargeResourceRecord(m, msg, ptr, end, InterfaceID, 0, &pkt);
+		ptr = GetLargeResourceRecord(m, msg, ptr, end, InterfaceID, kDNSRecordTypePacketAns, &pkt);
 		if (!ptr) { DisplayError(srcaddr, ep, end, "KNOWN ANSWER"); return; }
 		DisplayResourceRecord(srcaddr, "(KA)", &pkt.r.resrec);
 		
@@ -860,14 +878,14 @@ mDNSlocal void DisplayQuery(mDNS *const m, const DNSMessage *const msg, const mD
 	}
 
 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)
+	const mDNSAddr *srcaddr, mDNSIPPort srcport, const mDNSAddr *dstaddr, const mDNSInterfaceID InterfaceID)
 	{
 	int i;
 	const mDNSu8 *ptr = msg->data;
 	HostEntry *entry = GotPacketFromHost(srcaddr, HostPkt_R, msg->h.id);
 	LargeCacheRecord pkt;
 
-	DisplayPacketHeader(msg, end, srcaddr, srcport, dstaddr, ttl);
+	DisplayPacketHeader(msg, end, srcaddr, srcport, dstaddr);
 	if (msg->h.id.NotAnInteger != 0xFFFF) NumPktR++;
 
 	for (i=0; i<msg->h.numQuestions; i++)
@@ -885,7 +903,7 @@ mDNSlocal void DisplayResponse(mDNS *const m, const DNSMessage *const msg, const
 	for (i=0; i<msg->h.numAnswers; i++)
 		{
 		const mDNSu8 *ep = ptr;
-		ptr = GetLargeResourceRecord(m, msg, ptr, end, InterfaceID, 0, &pkt);
+		ptr = GetLargeResourceRecord(m, msg, ptr, end, InterfaceID, kDNSRecordTypePacketAns, &pkt);
 		if (!ptr) { DisplayError(srcaddr, ep, end, "ANSWER"); return; }
 		if (pkt.r.resrec.rroriginalttl)
 			{
@@ -905,7 +923,7 @@ mDNSlocal void DisplayResponse(mDNS *const m, const DNSMessage *const msg, const
 	for (i=0; i<msg->h.numAuthorities; i++)
 		{
 		const mDNSu8 *ep = ptr;
-		ptr = GetLargeResourceRecord(m, msg, ptr, end, InterfaceID, 0, &pkt);
+		ptr = GetLargeResourceRecord(m, msg, ptr, end, InterfaceID, kDNSRecordTypePacketAuth, &pkt);
 		if (!ptr) { DisplayError(srcaddr, ep, end, "AUTHORITY"); return; }
 		mprintf("%#-16a (?)  **** ERROR: SHOULD NOT HAVE AUTHORITY IN mDNS RESPONSE **** %-5s %##s\n",
 			srcaddr, DNSTypeName(pkt.r.resrec.rrtype), pkt.r.resrec.name.c);
@@ -914,7 +932,7 @@ mDNSlocal void DisplayResponse(mDNS *const m, const DNSMessage *const msg, const
 	for (i=0; i<msg->h.numAdditionals; i++)
 		{
 		const mDNSu8 *ep = ptr;
-		ptr = GetLargeResourceRecord(m, msg, ptr, end, InterfaceID, 0, &pkt);
+		ptr = GetLargeResourceRecord(m, msg, ptr, end, InterfaceID, kDNSRecordTypePacketAdd, &pkt);
 		if (!ptr) { DisplayError(srcaddr, ep, end, "ADDITIONAL"); return; }
 		NumAdditionals++;
 		DisplayResourceRecord(srcaddr, (pkt.r.resrec.RecordType & kDNSRecordTypePacketUniqueMask) ? "(AD)" : "(AD+)", &pkt.r.resrec);
@@ -934,7 +952,7 @@ mDNSlocal void ProcessUnicastResponse(mDNS *const m, const DNSMessage *const msg
 	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);
+		ptr = GetLargeResourceRecord(m, msg, ptr, end, InterfaceID, kDNSRecordTypePacketAns, &pkt);
 		if (pkt.r.resrec.rroriginalttl && entry) RecordHostInfo(entry, &pkt.r.resrec);
 		}
 	}
@@ -948,7 +966,7 @@ mDNSlocal mDNSBool AddressMatchesFilterList(const mDNSAddr *srcaddr)
 	}
 
 mDNSexport void mDNSCoreReceive(mDNS *const m, DNSMessage *const msg, const mDNSu8 *const end,
-	const mDNSAddr *srcaddr, mDNSIPPort srcport, const mDNSAddr *dstaddr, mDNSIPPort dstport, const mDNSInterfaceID InterfaceID, mDNSu8 ttl)
+	const mDNSAddr *srcaddr, mDNSIPPort srcport, const mDNSAddr *dstaddr, mDNSIPPort dstport, const mDNSInterfaceID InterfaceID)
 	{
 	const mDNSu8 StdQ = kDNSFlag0_QR_Query    | kDNSFlag0_OP_StdQuery;
 	const mDNSu8 StdR = kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery;
@@ -964,17 +982,6 @@ mDNSexport void mDNSCoreReceive(mDNS *const m, DNSMessage *const msg, const mDNS
 	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",
-		(QR_OP == StdQ) ? "Query" : (QR_OP == StdR) ? "Response" : "Unkown",
-		srcaddr, dstaddr, ttl, 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");
-		}
-	
 	// For now we're only interested in monitoring IPv4 traffic.
 	// All IPv6 packets should just be duplicates of the v4 packets.
 	if (AddressMatchesFilterList(srcaddr))
@@ -987,8 +994,8 @@ mDNSexport void mDNSCoreReceive(mDNS *const m, DNSMessage *const msg, const mDNS
 			}
 		else
 			{
-			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);
+			if      (QR_OP == StdQ) DisplayQuery          (m, msg, end, srcaddr, srcport, dstaddr, InterfaceID);
+			else if (QR_OP == StdR) DisplayResponse       (m, msg, end, srcaddr, srcport, dstaddr, InterfaceID);
 			else
 				{
 				debugf("Unknown DNS packet type %02X%02X (ignored)", msg->h.flags.b[0], msg->h.flags.b[1]);
@@ -1053,7 +1060,7 @@ mDNSlocal mStatus mDNSNetMonitor(void)
 	localtime_r((time_t*)&tv_end.tv_sec, &tm);
 	mprintf("End          %3d:%02d:%02d.%06d\n", tm.tm_hour, tm.tm_min, tm.tm_sec, tv_end.tv_usec);
 	mprintf("Captured for %3d:%02d:%02d.%06d\n", h, m, s, tv_interval.tv_usec);
-	if (!Filters) mprintf("Unique source addresses seen on network: %d\n", IPv4HostList.num + IPv6HostList.num);
+	if (!Filters) mprintf("Unique source addresses seen on network: %ld\n", IPv4HostList.num + IPv6HostList.num);
 	mprintf("\n");
 	mprintf("Modern Query        Packets:      %7d   (avg%5d/min)\n", NumPktQ,        NumPktQ        * mul / div);
 	mprintf("Legacy Query        Packets:      %7d   (avg%5d/min)\n", NumPktL,        NumPktL        * mul / div);
@@ -1081,6 +1088,7 @@ mDNSlocal mStatus mDNSNetMonitor(void)
 
 mDNSexport int main(int argc, char **argv)
 	{
+	const char *progname = strrchr(argv[0], '/') ? strrchr(argv[0], '/') + 1 : argv[0];
 	int i;
 	mStatus status;
 	
@@ -1115,12 +1123,12 @@ mDNSexport int main(int argc, char **argv)
 		}
 
 	status = mDNSNetMonitor();
-	if (status) { fprintf(stderr, "%s: mDNSNetMonitor failed %ld\n", argv[0], status); return(status); }
+	if (status) { fprintf(stderr, "%s: mDNSNetMonitor failed %ld\n", progname, status); return(status); }
 	return(0);
 
 usage:
 	fprintf(stderr, "\nmDNS traffic monitor\n");
-	fprintf(stderr, "Usage: %s (<host>)\n", argv[0]);
+	fprintf(stderr, "Usage: %s (<host>)\n", progname);
 	fprintf(stderr, "Optional <host> parameter displays only packets from that host\n");
 
 	fprintf(stderr, "\nPer-packet header output:\n");
diff --git a/mDNSPosix/PosixDaemon.c b/mDNSPosix/PosixDaemon.c
index 6e943de..fcb3990 100644
--- a/mDNSPosix/PosixDaemon.c
+++ b/mDNSPosix/PosixDaemon.c
@@ -1,10 +1,9 @@
-/*
- * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * 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
@@ -22,17 +21,55 @@
  * 
  * @APPLE_LICENSE_HEADER_END@
 
- 	File:		daemon.c
+	File:		daemon.c
 
- 	Contains:	main & associated Application layer for mDNSResponder on Linux.
+	Contains:	main & associated Application layer for mDNSResponder on Linux.
 
- 	Version:	1.0
- 	Tabs:		4 spaces
-
-    Change History (most recent first):
+	Change History (most recent first):
 
 $Log: PosixDaemon.c,v $
-Revision 1.10  2004/06/08 04:59:40  cheshire
+Revision 1.22  2004/12/10 13:12:08  cheshire
+Create no-op function RecordUpdatedNiceLabel(), required by uds_daemon.c
+
+Revision 1.21  2004/12/01 20:57:20  ksekar
+<rdar://problem/3873921> Wide Area Rendezvous must be split-DNS aware
+
+Revision 1.20  2004/12/01 04:28:43  cheshire
+<rdar://problem/3872803> Darwin patches for Solaris and Suse
+Use version of daemon() provided in mDNSUNP.c instead of local copy
+
+Revision 1.19  2004/12/01 03:30:29  cheshire
+<rdar://problem/3889346> Add Unicast DNS support to mDNSPosix
+
+Revision 1.18  2004/11/30 22:45:59  cheshire
+Minor code tidying
+
+Revision 1.17  2004/11/30 22:18:59  cheshire
+<rdar://problem/3889351> Posix needs to read the list of unicast DNS servers and set server list
+
+Revision 1.16  2004/09/21 21:05:12	cheshire
+Move duplicate code out of mDNSMacOSX/daemon.c and mDNSPosix/PosixDaemon.c,
+into mDNSShared/uds_daemon.c
+
+Revision 1.15  2004/09/17 01:08:53	cheshire
+Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
+  The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
+  declared in that file are ONLY appropriate to single-address-space embedded applications.
+  For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
+
+Revision 1.14  2004/09/16 00:24:49	cheshire
+<rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
+
+Revision 1.13  2004/08/11 01:59:41	cheshire
+Remove "mDNS *globalInstance" parameter from udsserver_init()
+
+Revision 1.12  2004/06/28 23:19:19	cheshire
+Fix "Daemon_Init declared but never defined" warning on Linux
+
+Revision 1.11  2004/06/25 00:26:27	rpantos
+Changes to fix the Posix build on Solaris.
+
+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
@@ -61,7 +98,6 @@ 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>
@@ -70,218 +106,221 @@ Add support for mDNSResponder on Linux.
 #include <stdlib.h>
 #include <signal.h>
 #include <errno.h>
+#include <fcntl.h>
 #include <pwd.h>
 #include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
 
-#include "mDNSClientAPI.h"
+#include "mDNSEmbeddedAPI.h"
 #include "mDNSDebug.h"
 #include "mDNSPosix.h"
 #include "uds_daemon.h"
+#include "PlatformCommon.h"
 
+#define uDNS_SERVERS_FILE "/etc/resolv.conf"
 
-static void		ParseCmdLinArgs( int argc, char **argv);
-static void		DumpStateLog( mDNS *m);
-static mStatus	MainLoop( mDNS *m);
-
+#define CONFIG_FILE "/etc/mdnsd.conf"
+static domainname DynDNSZone;                // Default wide-area zone for service registration
+static domainname DynDNSHostname;
 
 #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)
+static int ParseDNSServers(mDNS *m, const char *filePath)
 	{
-		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");
+	char line[256];
+	char nameserver[16];
+	char keyword[10];
+	int  numOfServers = 0;
+	FILE *fp = fopen(filePath, "r");
+	if (fp == NULL) return -1;
+	while (fgets(line,sizeof(line),fp))
+		{
+		struct in_addr ina;
+		line[255]='\0';		// just to be safe
+		if (sscanf(line,"%10s %15s", keyword, nameserver) != 2) continue;	// it will skip whitespaces
+		if (strncmp(keyword,"nameserver",10)) continue;
+		if (inet_aton(nameserver, (struct in_addr *)&ina) != 0)
+			{
+			mDNSAddr DNSAddr;
+			DNSAddr.type = mDNSAddrType_IPv4;
+			DNSAddr.ip.v4.NotAnInteger = ina.s_addr;
+			mDNS_AddDNSServer(m, &DNSAddr, NULL);
+			numOfServers++;
+			}
+		}  
+	return (numOfServers > 0) ? 0 : -1;
 	}
 
-	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)
+static void Reconfigure(mDNS *m)
 	{
-		if ( 0 == strcmp( argv[1], "-debug"))
-		{
-			mDNS_DebugMode = mDNStrue;
-		}
-		else
-			printf( "Usage: mDNSResponder [-debug]\n");
+	mDNSAddr DynDNSIP;
+	mDNS_SetPrimaryInterfaceInfo(m, NULL, NULL);
+	mDNS_DeleteDNSServers(m);
+	if (ParseDNSServers(m, uDNS_SERVERS_FILE) < 0)
+		LogMsg("Unable to parse DNS server list. Unicast DNS-SD unavailable");
+	ReadDDNSSettingsFromConfFile(m, CONFIG_FILE, &DynDNSHostname, &DynDNSZone);
+	FindDefaultRouteIP(&DynDNSIP);
+	if (DynDNSHostname.c[0]) mDNS_AddDynDNSHostName(m, &DynDNSHostname, NULL, NULL);
+	if (DynDNSIP.type)       mDNS_SetPrimaryInterfaceInfo(m, &DynDNSIP, NULL);
 	}
 
-	if ( !mDNS_DebugMode)
+// Do appropriate things at startup with command line arguments. Calls exit() if unhappy.
+static void ParseCmdLinArgs(int argc, char **argv)
 	{
-		int		result = daemon( 0, 0);
-		
-		if ( result != 0)
+	if (argc > 1)
 		{
-			LogMsg("Could not run as daemon - exiting");
-			exit( result);
+		if (0 == strcmp(argv[1], "-debug")) mDNS_DebugMode = mDNStrue;
+		else printf("Usage: mDNSResponder [-debug]\n");
 		}
 
-#if __APPLE__
+	if (!mDNS_DebugMode)
 		{
-			LogMsg("The POSIX mDNSResponder should only be used on OS X for testing - exiting");
-			exit( -1);
-		}
+		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)
+static void		DumpStateLog(mDNS *const 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();
-
+	udsserver_info(m);
 	LogMsgIdent(mDNSResponderVersionString, "----  END STATE LOG  ----");
-}
+	}
 
-static mStatus	MainLoop( mDNS *m)
-// Loop until we quit.
-{
+static mStatus	MainLoop(mDNS *m) // Loop until we quit.
+	{
 	sigset_t	signals;
 	mDNSBool	gotData = mDNSfalse;
 
-	mDNSPosixListenForSignalInEventLoop( SIGINT);
-	mDNSPosixListenForSignalInEventLoop( SIGTERM);
-	mDNSPosixListenForSignalInEventLoop( SIGUSR1);
-	mDNSPosixListenForSignalInEventLoop( SIGPIPE);
+	mDNSPosixListenForSignalInEventLoop(SIGINT);
+	mDNSPosixListenForSignalInEventLoop(SIGTERM);
+	mDNSPosixListenForSignalInEventLoop(SIGUSR1);
+	mDNSPosixListenForSignalInEventLoop(SIGPIPE);
+	mDNSPosixListenForSignalInEventLoop(SIGHUP) ;
 
-	for ( ; ;)
-	{
+	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)
-		{
+		if (!gotData)
+			{
 			mDNSs32			nextTimerEvent = mDNS_Execute(m);
-		
-			nextTimerEvent = udsserver_idle( nextTimerEvent);
-	
-			ticks = nextTimerEvent - mDNSPlatformTimeNow();
+			nextTimerEvent = udsserver_idle(nextTimerEvent);
+			ticks = nextTimerEvent - mDNS_TimeNow(m);
 			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);
+		(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;
+		if (sigismember(&signals, SIGHUP )) Reconfigure(m);
+		if (sigismember(&signals, SIGUSR1)) DumpStateLog(m);
+		// SIGPIPE happens when we try to write to a dead client; death should be detected soon in request_callback() and cleaned up.
+		if (sigismember(&signals, SIGPIPE)) LogMsg("Received SIGPIPE - ignoring");
+		if (sigismember(&signals, SIGINT) || sigismember(&signals, SIGTERM)) break;
+		}
+	return EINTR;
 	}
 
-	return EINTR;
-}
+int		main(int argc, char **argv)
+	{
+	#define mDNSRecord mDNSStorage
+	mDNS_PlatformSupport	platformStorage;
+	mStatus					err;
+
+	bzero(&mDNSRecord, sizeof mDNSRecord);
+	bzero(&platformStorage, sizeof platformStorage);
+
+	ParseCmdLinArgs(argc, argv);
+
+	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();
+		
+	Reconfigure(&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;
+	}
 
 //		uds_daemon support		////////////////////////////////////////////////////////////
 
 #if MDNS_MALLOC_DEBUGGING >= 2
 #define LogMalloc LogMsg
 #else
-#define	LogMalloc(ARGS...) ((void)0)
+#define LogMalloc(ARGS...) ((void)0)
 #endif
 
-
-mStatus udsSupportAddFDToEventLoop( int fd, udsEventCallback callback, void *context)
+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);
-}
+	return mDNSPosixAddFDToEventLoop(fd, callback, context);
+	}
 
-mStatus udsSupportRemoveFDFromEventLoop( int fd)
-{
-	return mDNSPosixRemoveFDFromEventLoop( fd);
-}
+mStatus udsSupportRemoveFDFromEventLoop(int fd)
+	{
+	return mDNSPosixRemoveFDFromEventLoop(fd);
+	}
+
+mDNSexport void RecordUpdatedNiceLabel(mDNS *const m, mDNSs32 delay)
+	{
+	(void)m;
+	(void)delay;
+	// No-op, for now
+	}
 
 #if MACOSX_MDNS_MALLOC_DEBUGGING >= 1
 
 void *mallocL(char *msg, unsigned int size)
-{
+	{
 	unsigned long *mem = malloc(size+8);
 	if (!mem)
-	{
+		{
 		LogMsg("malloc( %s : %d ) failed", msg, size);
 		return(NULL); 
-	}
+		}
 	else
-	{
+		{
 		LogMalloc("malloc( %s : %lu ) = %p", msg, size, &mem[2]);
 		mem[0] = 0xDEAD1234;
 		mem[1] = size;
@@ -289,15 +328,15 @@ void *mallocL(char *msg, unsigned int 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; }
@@ -308,13 +347,11 @@ void freeL(char *msg, void *x)
 		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__ ") ";
diff --git a/mDNSPosix/ProxyResponder.c b/mDNSPosix/ProxyResponder.c
index 5030d93..bca7356 100644
--- a/mDNSPosix/ProxyResponder.c
+++ b/mDNSPosix/ProxyResponder.c
@@ -1,10 +1,9 @@
-/*
- * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * 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
@@ -25,6 +24,31 @@
     Change History (most recent first):
 
 $Log: ProxyResponder.c,v $
+Revision 1.34  2004/12/01 04:27:28  cheshire
+<rdar://problem/3872803> Darwin patches for Solaris and Suse
+Don't use uint32_t, etc. -- they require stdint.h, which doesn't exist on FreeBSD 4.x, Solaris, etc.
+
+Revision 1.33  2004/11/30 22:37:01  cheshire
+Update copyright dates and add "Mode: C; tab-width: 4" headers
+
+Revision 1.32  2004/10/26 03:59:41  cheshire
+Update comments
+
+Revision 1.31  2004/09/17 01:08:53  cheshire
+Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
+  The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
+  declared in that file are ONLY appropriate to single-address-space embedded applications.
+  For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
+
+Revision 1.30  2004/09/17 00:31:52  cheshire
+For consistency with ipv6, renamed rdata field 'ip' to 'ipv4'
+
+Revision 1.29  2004/09/16 01:58:22  cheshire
+Fix compiler warnings
+
+Revision 1.28  2004/06/25 00:26:27  rpantos
+Changes to fix the Posix build on Solaris.
+
 Revision 1.27  2004/03/12 08:03:14  cheshire
 Update comments
 
@@ -75,27 +99,32 @@ 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-existance function so that it works again
+Fixed mDNS_RegisterNoSuchService non-existence function so that it works again
 
 Revision 1.11  2003/03/31 22:49:35  cheshire
 Add "$Log" header
 
  */
 
-#include <stdio.h>			// For printf()
-#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
-#include <netdb.h>			// For gethostbyname()
-
-#include "mDNSClientAPI.h"  // Defines the interface to the client layer above
-#include "mDNSPosix.h"      // Defines the specific types needed to run mDNS on this platform
+#include <stdio.h>				// For printf()
+#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
+#include <netdb.h>				// For gethostbyname()
+
+#include "mDNSEmbeddedAPI.h"	// Defines the interface to the client layer above
+#include "mDNSPosix.h"			// Defines the specific types needed to run mDNS on this platform
 #include "ExampleClientApp.h"
 
+// Compatibility workaround: Solaris 2.5 has no INADDR_NONE
+#ifndef	INADDR_NONE
+#define	INADDR_NONE	(mDNSu32)0xffffffff
+#endif
+
 //*************************************************************************************************************
 // Globals
 static mDNS mDNSStorage;       // mDNS core uses this to store its globals
@@ -116,10 +145,10 @@ mDNSlocal void HostNameCallback(mDNS *const m, AuthRecord *const rr, mStatus res
 	{
 	ProxyHost *f = (ProxyHost*)rr->RecordContext;
 	if (result == mStatus_NoError)
-		debugf("Host name successfully registered: %##s", &rr->resrec.name);
+		debugf("Host name successfully registered: %##s", rr->resrec.name.c);
 	else
 		{
-		debugf("Host name conflict for %##s", &rr->resrec.name);
+		debugf("Host name conflict for %##s", rr->resrec.name.c);
 		mDNS_Deregister(m, &f->RR_A);
 		mDNS_Deregister(m, &f->RR_PTR);
 		exit(-1);
@@ -140,13 +169,13 @@ mDNSlocal mStatus mDNS_RegisterProxyHost(mDNS *m, ProxyHost *p)
 	mDNS_snprintf(buffer, sizeof(buffer), "%d.%d.%d.%d.in-addr.arpa.", p->ip.b[3], p->ip.b[2], p->ip.b[1], p->ip.b[0]);
 	MakeDomainNameFromDNSNameString(&p->RR_PTR.resrec.name, buffer);
 
-	p->RR_A.  resrec.rdata->u.ip   = p->ip;
+	p->RR_A.  resrec.rdata->u.ipv4 = p->ip;
 	p->RR_PTR.resrec.rdata->u.name = p->RR_A.resrec.name;
 
 	mDNS_Register(m, &p->RR_A);
 	mDNS_Register(m, &p->RR_PTR);
 
-	debugf("Made Proxy Host Records for %##s", &p->RR_A.resrec.name);
+	debugf("Made Proxy Host Records for %##s", p->RR_A.resrec.name.c);
 	
 	return(mStatus_NoError);
 	}
@@ -162,10 +191,10 @@ mDNSlocal void ServiceCallback(mDNS *const m, ServiceRecordSet *const sr, mStatu
 	{
 	switch (result)
 		{
-		case mStatus_NoError:      debugf("Callback: %##s Name Registered",   &sr->RR_SRV.resrec.name); break;
-		case mStatus_NameConflict: debugf("Callback: %##s Name Conflict",     &sr->RR_SRV.resrec.name); break;
-		case mStatus_MemFree:      debugf("Callback: %##s Memory Free",       &sr->RR_SRV.resrec.name); break;
-		default:                   debugf("Callback: %##s Unknown Result %d", &sr->RR_SRV.resrec.name, result); break;
+		case mStatus_NoError:      debugf("Callback: %##s Name Registered",    sr->RR_SRV.resrec.name.c); break;
+		case mStatus_NameConflict: debugf("Callback: %##s Name Conflict",      sr->RR_SRV.resrec.name.c); break;
+		case mStatus_MemFree:      debugf("Callback: %##s Memory Free",        sr->RR_SRV.resrec.name.c); break;
+		default:                   debugf("Callback: %##s Unknown Result %ld", sr->RR_SRV.resrec.name.c, result); break;
 		}
 
 	if (result == mStatus_NoError)
@@ -235,10 +264,10 @@ mDNSlocal void NoSuchServiceCallback(mDNS *const m, AuthRecord *const rr, mStatu
 	domainname *proxyhostname = (domainname *)rr->RecordContext;
 	switch (result)
 		{
-		case mStatus_NoError:      debugf("Callback: %##s Name Registered",   &rr->resrec.name); break;
-		case mStatus_NameConflict: debugf("Callback: %##s Name Conflict",     &rr->resrec.name); break;
-		case mStatus_MemFree:      debugf("Callback: %##s Memory Free",       &rr->resrec.name); break;
-		default:                   debugf("Callback: %##s Unknown Result %d", &rr->resrec.name, result); break;
+		case mStatus_NoError:      debugf("Callback: %##s Name Registered",    rr->resrec.name.c); break;
+		case mStatus_NameConflict: debugf("Callback: %##s Name Conflict",      rr->resrec.name.c); break;
+		case mStatus_MemFree:      debugf("Callback: %##s Memory Free",        rr->resrec.name.c); break;
+		default:                   debugf("Callback: %##s Unknown Result %ld", rr->resrec.name.c, result); break;
 		}
 
 	if (result == mStatus_NoError)
diff --git a/mDNSPosix/ReadMe.txt b/mDNSPosix/ReadMe.txt
index 06df6e7..d128c8d 100755
--- a/mDNSPosix/ReadMe.txt
+++ b/mDNSPosix/ReadMe.txt
@@ -20,8 +20,8 @@ zeroconf technologies.  This sample is designed to show how easy it is
 to make a device "Rendezvous compatible".
 
 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.
+10.2, 10.3), Solaris (SunOS 5.8), Linux (Redhat 2.4.9-21, Fedora Core 1), 
+and OpenBSD (2.9). YMMV.
 
 
 Packing List
@@ -72,6 +72,7 @@ When you compile, you will get:
 o Main products for general-purpose use (e.g. on a desktop computer):
   - mdnsd
   - libmdns
+  - nss_mdns (See nss_ReadMe.txt for important information about nss_mdns)
 
 o Standalone products for dedicated devices (printer, network camera, etc.)
   - mDNSClientPosix
@@ -82,14 +83,20 @@ o Debugging tools
   - mDNSNetMonitor
   - mDNSIdentify
 
-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)
-
-Once you've installed the header and the library, and started the
-daemon running, you can cd to the "Clients" folder and type "make".
+As root type "make install" to install six things:
+o mdnsd                   (usually in /usr/sbin)
+o libmdns                 (usually in /usr/lib)
+o dns_sd.h                (usually in /usr/include)
+o startup scripts         (e.g. in /etc/rc.d)
+o manual pages            (usually in /usr/share/man)
+o nss_mdns                (usually in /lib)
+o nss configuration files (usually in /etc)
+
+Once you've installed the files in their respective places,
+you need to start the daemon running, either by rebooting,
+or by running the startup script "/etc/init.d/mdns start"
+(the exact path may be different on your system).
+Then you can cd to the "Clients" folder and type "make".
 This builds a test client showing how to exercise all the major
 functionality of the daemon.
 
@@ -117,6 +124,11 @@ 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.
 
+Note that, strictly speaking, nss_mdns could be just another client of
+mdnsd, linking with libmdns just like any other client. However, because
+of its central role in the normal operation of multicast DNS, it is built
+and installed along with the other essential system support components.
+
 
 Clients for Embedded Systems
 ----------------------------
diff --git a/mDNSPosix/Responder.c b/mDNSPosix/Responder.c
index a8c297a..93b0c81 100755
--- a/mDNSPosix/Responder.c
+++ b/mDNSPosix/Responder.c
@@ -1,10 +1,9 @@
-/*
- * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * 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
@@ -25,6 +24,31 @@
     Change History (most recent first):
 
 $Log: Responder.c,v $
+Revision 1.27  2004/12/01 04:28:43  cheshire
+<rdar://problem/3872803> Darwin patches for Solaris and Suse
+Use version of daemon() provided in mDNSUNP.c instead of local copy
+
+Revision 1.26  2004/11/30 22:37:01  cheshire
+Update copyright dates and add "Mode: C; tab-width: 4" headers
+
+Revision 1.25  2004/11/11 02:00:51  cheshire
+Minor fixes to getopt, error message
+
+Revision 1.24  2004/11/09 19:32:10  rpantos
+Suggestion from Ademar de Souza Reis Jr. to allow comments in services file
+
+Revision 1.23  2004/09/17 01:08:54  cheshire
+Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
+  The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
+  declared in that file are ONLY appropriate to single-address-space embedded applications.
+  For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
+
+Revision 1.22  2004/09/16 01:58:22  cheshire
+Fix compiler warnings
+
+Revision 1.21  2004/06/15 03:48:07  cheshire
+Update mDNSResponderPosix to take multiple name=val arguments in a sane way
+
 Revision 1.20  2004/05/18 23:51:26  cheshire
 Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
 
@@ -89,7 +113,7 @@ First checkin
 
 */
 
-#include "mDNSClientAPI.h"// Defines the interface to the client layer above
+#include "mDNSEmbeddedAPI.h"// Defines the interface to the client layer above
 #include "mDNSPosix.h"    // Defines the specific types needed to run mDNS on this platform
 
 #include <assert.h>
@@ -250,91 +274,6 @@ static mDNSBool CheckThatServiceTypeIsUsable(const char *serviceType, mDNSBool p
     return result;
 }
 
-static mDNSBool CheckThatServiceTextIsUsable(const char *serviceText, mDNSBool printExplanation,
-                                             mDNSu8 *pStringList, mDNSu16 *pStringListLen)
-    // Checks that serviceText is a reasonable service text record 
-    // and, if it isn't and printExplanation is true, prints 
-    // an explanation of why not.  Also parse the text into 
-    // the packed PString buffer denoted by pStringList and 
-    // return the length of that buffer in *pStringListLen.
-    // Note that this routine assumes that the buffer is 
-    // sizeof(RDataBody) bytes long.
-{
-    mDNSBool result;
-    size_t   serviceTextLen;
-    
-    // Note that parsing a C string into a PString list always 
-    // expands the data by one character, so the following 
-    // compare is ">=", not ">".  Here's the logic:
-    //
-    // #1 For a string with not ^A's, the PString length is one 
-    //    greater than the C string length because we add a length 
-    //    byte.
-    // #2 For every regular (not ^A) character you add to the C 
-    //    string, you add a regular character to the PString list.
-    //    This does not affect the equivalence stated in #1.
-    // #3 For every ^A you add to the C string, you add a length 
-    //    byte to the PString list but you also eliminate the ^A, 
-    //    which again does not affect the equivalence stated in #1.
-    
-    result = mDNStrue;
-    serviceTextLen = strlen(serviceText);
-    if (result && strlen(serviceText) >= sizeof(RDataBody)) {
-        if (printExplanation) {
-            fprintf(stderr, 
-                    "%s: Service text record is too long (must be less than %d characters)\n", 
-                    gProgramName,
-                    (int) sizeof(RDataBody) );
-        }
-        result = mDNSfalse;
-    }
-    
-    // Now break the string up into PStrings delimited by ^A.
-    // We know the data will fit so we can ignore buffer overrun concerns. 
-    // However, we still have to treat runs long than 255 characters as
-    // an error.
-    
-    if (result) {
-        int         lastPStringOffset;
-        int         i;
-        int         thisPStringLen;
-        
-        // This algorithm is a little tricky.  We start by copying 
-        // the string directly into the output buffer, shifted up by 
-        // one byte.  We then fill in the first byte with a ^A. 
-        // We then walk backwards through the buffer and, for each 
-        // ^A that we find, we replace it with the difference between 
-        // its offset and the offset of the last ^A that we found
-        // (ie lastPStringOffset).
-        
-        memcpy(&pStringList[1], serviceText, serviceTextLen);
-        pStringList[0] = 1;
-        lastPStringOffset = serviceTextLen + 1;
-        for (i = serviceTextLen; i >= 0; i--) {
-            if ( pStringList[i] == 1 ) {
-                thisPStringLen = (lastPStringOffset - i - 1);
-                assert(thisPStringLen >= 0);
-                if (thisPStringLen > 255) {
-                    result = mDNSfalse;
-                    if (printExplanation) {
-                        fprintf(stderr, 
-                                "%s: Each component of the service text record must be 255 characters or less\n", 
-                                gProgramName);
-                    }
-                    break;
-                } else {
-                    pStringList[i]    = thisPStringLen;
-                    lastPStringOffset = i;
-                }
-            }
-        }
-        
-        *pStringListLen = serviceTextLen + 1;
-    }
-
-    return result;
-}
-
 static mDNSBool CheckThatPortNumberIsUsable(long portNumber, mDNSBool printExplanation)
     // Checks that portNumber is a reasonable port number
     // and, if it isn't and printExplanation is true, prints 
@@ -368,7 +307,7 @@ enum {
 static void PrintUsage()
 {
     fprintf(stderr, 
-            "Usage: %s [-v level ] [-r] [-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] [-p port] [-f file] [-b] [-P pidfile] [-x name=val ...]\n", 
             gProgramName);
     fprintf(stderr, "          -v verbose mode, level is a number from 0 to 2\n");
     fprintf(stderr, "             0 = no debugging info (default)\n");
@@ -379,13 +318,15 @@ static void PrintUsage()
     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);
-    fprintf(stderr, "          -x uses 'TXT' as the service TXT record (default is empty)\n");
     fprintf(stderr, "          -p uses 'port' as the port number (default is '%d')\n",  kDefaultPortNumber);
     fprintf(stderr, "          -f reads a service list from 'file'\n");
     fprintf(stderr, "          -b forces daemon (background) mode\n");
     fprintf(stderr, "          -P uses 'pidfile' as the PID file\n");
     fprintf(stderr, "             (default is '%s')\n",  kDefaultPIDFile);
     fprintf(stderr, "             only meaningful if -b also specified\n");
+    fprintf(stderr, "          -x stores name=val in TXT record (default is empty).\n");
+    fprintf(stderr, "             MUST be the last command-line argument;\n");
+    fprintf(stderr, "             all subsequent arguments after -x are treated as name=val pairs.\n");
 }
 
 static   mDNSBool  gAvoidPort53      = mDNStrue;
@@ -417,7 +358,7 @@ static void ParseArguments(int argc, char **argv)
     // Parse command line options using getopt.
     
     do {
-        ch = getopt(argc, argv, "v:rn:t:d:x:p:f:dPb");
+        ch = getopt(argc, argv, "v:rn:t:d:p:f:dP:bx");
         if (ch != -1) {
             switch (ch) {
                 case 'v':
@@ -447,11 +388,6 @@ static void ParseArguments(int argc, char **argv)
                 case 'd':
                     gServiceDomain = optarg;
                     break;
-                case 'x':
-                    if ( ! CheckThatServiceTextIsUsable(optarg, mDNStrue, gServiceText, &gServiceTextLen) ) {
-                        exit(1);
-                    }
-                    break;
                 case 'p':
                     gPortNumber = atol(optarg);
                     if ( ! CheckThatPortNumberIsUsable(gPortNumber, mDNStrue) ) {
@@ -467,6 +403,16 @@ static void ParseArguments(int argc, char **argv)
                 case 'P':
                     gPIDFile = optarg;
                     break;
+                case 'x':
+                	while (optind < argc)
+                		{
+                		gServiceText[gServiceTextLen] = strlen(argv[optind]);
+                		memcpy(gServiceText+gServiceTextLen+1, argv[optind], gServiceText[gServiceTextLen]);
+                		gServiceTextLen += 1 + gServiceText[gServiceTextLen];
+                		optind++;
+                		}
+                	ch = -1;
+                	break;
                 case '?':
                 default:
                     PrintUsage();
@@ -559,7 +505,7 @@ static void RegistrationCallback(mDNS *const m, ServiceRecordSet *const thisRegi
             break;
 
         default:                   
-            debugf("Callback: %##s Unknown Status %d", thisRegistration->RR_SRV.resrec.name.c, status); 
+            debugf("Callback: %##s Unknown Status %ld", thisRegistration->RR_SRV.resrec.name.c, status); 
             break;
     }
 }
@@ -621,91 +567,88 @@ static mStatus RegisterOneService(const char *  richTextHostName,
 }
 
 static mDNSBool ReadALine(char *buf, size_t bufSize, FILE *fp)
+// Read a line, skipping over any blank lines or lines starting with '#'
+{
+	mDNSBool good, skip;
+	do {
+		good = (fgets(buf, bufSize, fp) != NULL);
+		skip = (good && (buf[0] == '#' || buf[0] == '\r' || buf[0] == '\n'));
+	} while (good && skip);
+	if (good)
 	{
-    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;
-	    }
-    return good;
+		int		len = strlen( buf);
+		if ( buf[len - 1] == '\r' || buf[len - 1] == '\n')
+			buf[len - 1] = '\0';
 	}
+    return good;
+}
 
 static mStatus RegisterServicesInFile(const char *filePath)
 {
-    mStatus     status;
-    FILE *      fp;
+    mStatus     status = mStatus_NoError;
+    FILE *      fp = fopen(filePath, "r");
     int         junk;
-    mDNSBool    good;
-    int         ch;
-    char name[256];
-    char type[256];
-    const char *dom = kDefaultServiceDomain;
-    char rawText[1024];
-    mDNSu8  text[sizeof(RDataBody)];
-    mDNSu16 textLen;
-    char port[256];
     
-    status = mStatus_NoError;
-    fp = fopen(filePath, "r");
     if (fp == NULL) {
         status = mStatus_UnknownErr;
     }
     if (status == mStatus_NoError) {
-        good = mDNStrue;
+        mDNSBool good = mDNStrue;
         do {
-            // Skip over any blank lines.
-            do {
-                ch = fgetc(fp);
-            } while ( ch == '\n' || ch == '\r' );
-            if (ch != EOF) {
-                good = (ungetc(ch, fp) == ch);
-            }
+			char name[256];
+			char type[256];
+			const char *dom = kDefaultServiceDomain;
+			char rawText[1024];
+			mDNSu8  text[sizeof(RDataBody)];
+			mDNSu16 textLen = 0;
+			char port[256];
             
             // Read three lines, check them for validity, and register the service.
-            if ( good && ! feof(fp) ) {
-                good = ReadALine(name, sizeof(name), fp);               
-                if (good) {
-                    good = ReadALine(type, sizeof(type), fp);
-                }
-                if (good) {
-                	char *p = type;
-                	while (*p && *p != ' ') p++;
-                	if (*p) {
-                		*p = 0;
-                		dom = p+1;
-                	}
-                }
-                if (good) {
-                    good = ReadALine(rawText, sizeof(rawText), fp);
-                }
-                if (good) {
-                    good = ReadALine(port, sizeof(port), fp);
-                }
-                if (good) {
-                    good =     CheckThatRichTextHostNameIsUsable(name, mDNSfalse)
-                            && CheckThatServiceTypeIsUsable(type, mDNSfalse)
-                            && CheckThatServiceTextIsUsable(rawText, mDNSfalse, text, &textLen)
-                            && CheckThatPortNumberIsUsable(atol(port), mDNSfalse);
-                }
-                if (good) {
-                    status = RegisterOneService(name, type, dom, text, textLen, atol(port));
-                    if (status != mStatus_NoError) {
-                        fprintf(stderr, 
-                                "%s: Failed to register service, name = %s, type = %s, port = %s\n", 
-                                gProgramName,
-                                name,
-                                type,
-                                port);
-                        status = mStatus_NoError;       // keep reading
-                    }
-                }
-            }
+			good = ReadALine(name, sizeof(name), fp);               
+			if (good) {
+				good = ReadALine(type, sizeof(type), fp);
+			}
+			if (good) {
+				char *p = type;
+				while (*p && *p != ' ') p++;
+				if (*p) {
+					*p = 0;
+					dom = p+1;
+				}
+			}
+			if (good) {
+				good = ReadALine(port, sizeof(port), fp);
+			}
+			if (good) {
+				good =     CheckThatRichTextHostNameIsUsable(name, mDNSfalse)
+						&& CheckThatServiceTypeIsUsable(type, mDNSfalse)
+						&& CheckThatPortNumberIsUsable(atol(port), mDNSfalse);
+			}
+			if (good) {
+				while (1) {
+					if (!ReadALine(rawText, sizeof(rawText), fp)) break;
+					text[textLen] = strlen(rawText);
+					if (text[textLen] == 0) break;
+					memcpy(text + textLen + 1, rawText, text[textLen]);
+					textLen += 1 + text[textLen];
+				}
+			}
+			if (good) {
+				status = RegisterOneService(name, type, dom, text, textLen, atol(port));
+				if (status != mStatus_NoError) {
+					fprintf(stderr, 
+							"%s: Failed to register service, name = %s, type = %s, port = %s\n", 
+							gProgramName,
+							name,
+							type,
+							port);
+					status = mStatus_NoError;       // keep reading
+				}
+			}
         } while (good && !feof(fp));
 
         if ( ! good ) {
-            fprintf(stderr, "%s: Error reading service file %s\n", gProgramName, gServiceFile);
+            fprintf(stderr, "%s: Error reading service file %s\n", gProgramName, filePath);
         }
     }
     
@@ -761,43 +704,6 @@ static void DeregisterOurServices(void)
 #pragma mark **** Main
 #endif
 
-#ifdef NOT_HAVE_DAEMON
-
-    // The version of Solaris that I tested on didn't have the daemon 
-    // call.  This implementation was basically stolen from the 
-    // Mac OS X standard C library.
-    
-    static int daemon(int nochdir, int noclose)
-    {
-        int fd;
-    
-        switch (fork()) {
-        case -1:
-            return (-1);
-        case 0:
-            break;
-        default:
-            _exit(0);
-        }
-    
-        if (setsid() == -1)
-            return (-1);
-    
-        if (!nochdir)
-            (void)chdir("/");
-    
-        if (!noclose && (fd = _open("/dev/null", O_RDWR, 0)) != -1) {
-            (void)dup2(fd, STDIN_FILENO);
-            (void)dup2(fd, STDOUT_FILENO);
-            (void)dup2(fd, STDERR_FILENO);
-            if (fd > 2)
-                (void)_close(fd);
-        }
-        return (0);
-    }
-
-#endif /* NOT_HAVE_DAEMON */
-
 int main(int argc, char **argv)
 {
     mStatus status;
diff --git a/mDNSPosix/Services.txt b/mDNSPosix/Services.txt
index a7b73da..f5870bb 100755
--- a/mDNSPosix/Services.txt
+++ b/mDNSPosix/Services.txt
@@ -1,14 +1,15 @@
 Tweedlebug
 _afpovertcp._tcp.
-name=val1
 548
+name=val1
 
 Tweedlebug2
 _afpovertcp._tcp. local.
-name=val2name2=anotherattribute
 548
+name=val2
+name2=anotherattribute
 
 Tweedlebug3
-_afpovertcp._tcp. apple.com.
-name=val3
+_afpovertcp._tcp.
 548
+name=val3
diff --git a/mDNSPosix/dnsextd.c b/mDNSPosix/dnsextd.c
new file mode 100644
index 0000000..41bc5e7
--- /dev/null
+++ b/mDNSPosix/dnsextd.c
@@ -0,0 +1,1983 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+
+$Log: dnsextd.c,v $
+Revision 1.23  2004/12/06 20:24:31  ksekar
+<rdar://problem/3907303> dnsextd leaks sockets
+
+Revision 1.22  2004/12/03 20:20:29  ksekar
+<rdar://problem/3904149> dnsextd: support delivery of large records via LLQ events
+
+Revision 1.21  2004/12/03 06:11:34  ksekar
+<rdar://problem/3885059> clean up dnsextd arguments
+
+Revision 1.20  2004/12/01 04:27:28  cheshire
+<rdar://problem/3872803> Darwin patches for Solaris and Suse
+Don't use uint32_t, etc. -- they require stdint.h, which doesn't exist on FreeBSD 4.x, Solaris, etc.
+
+Revision 1.19  2004/12/01 01:16:29  cheshire
+Solaris compatibility fixes
+
+Revision 1.18  2004/11/30 23:51:06  cheshire
+Remove double semicolons
+
+Revision 1.17  2004/11/30 22:37:01  cheshire
+Update copyright dates and add "Mode: C; tab-width: 4" headers
+
+Revision 1.16  2004/11/25 02:02:28  ksekar
+Fixed verbose log message argument
+
+Revision 1.15  2004/11/19 02:35:02  ksekar
+<rdar://problem/3886317> Wide Area Rendezvous Security: Add LLQ-ID to events
+
+Revision 1.14  2004/11/17 06:17:58  cheshire
+Update comments to show correct SRV names: _dns-update._udp.<zone>. and _dns-llq._udp.<zone>.
+
+Revision 1.13  2004/11/13 02:22:36  ksekar
+<rdar://problem/3878201> Refresh Acks from daemon malformatted
+
+Revision 1.12  2004/11/12 01:05:01  ksekar
+<rdar://problem/3876757> dnsextd: daemon registers the SRV same record
+twice at startup
+
+Revision 1.11  2004/11/12 01:03:31  ksekar
+<rdar://problem/3876776> dnsextd: KnownAnswers (CacheRecords) leaked
+
+Revision 1.10  2004/11/12 00:35:28  ksekar
+<rdar://problem/3876705> dnsextd: uninitialized pointer can cause crash
+
+Revision 1.9  2004/11/10 20:38:17  ksekar
+<rdar://problem/3874168> dnsextd: allow a "fudge" in LLQ lease echo
+
+Revision 1.8  2004/11/01 17:48:14  cheshire
+Changed SOA serial number back to signed. RFC 1035 may describe it as "unsigned", but
+it's wrong. The SOA serial is a modular counter, as explained in "DNS & BIND", page
+137. Since C doesn't have a modular type, we used signed, C's closest approximation.
+
+Revision 1.7  2004/10/30 00:06:58  ksekar
+<rdar://problem/3722535> Support Long Lived Queries in DNS Extension daemon
+
+Revision 1.6  2004/09/17 01:08:54  cheshire
+Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
+  The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
+  declared in that file are ONLY appropriate to single-address-space embedded applications.
+  For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
+
+Revision 1.5  2004/09/16 00:50:54  cheshire
+Don't use MSG_WAITALL -- it returns "Invalid argument" on some Linux versions
+
+Revision 1.4  2004/09/14 23:27:48  cheshire
+Fix compile errors
+
+Revision 1.3  2004/09/02 01:39:40  cheshire
+For better readability, follow consistent convention that QR bit comes first, followed by OP bits
+
+Revision 1.2  2004/08/24 23:27:57  cheshire
+Fixes for Linux compatibility:
+Don't use strings.h
+Don't assume SIGINFO
+Don't try to set servaddr.sin_len on platforms that don't have sa_len
+
+Revision 1.1  2004/08/11 00:43:26  ksekar
+<rdar://problem/3722542>: DNS Extension daemon for DNS Update Lease
+
+*/
+
+#include "../mDNSCore/mDNSEmbeddedAPI.h"
+#include "../mDNSCore/DNSCommon.h"
+#include "../mDNSCore/mDNS.c"
+//!!!KRS we #include mDNS.c for the various constants defined there  - we should move these to DNSCommon.h
+
+#include <signal.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <string.h>
+#include <sys/time.h>
+#include <time.h>
+#include <errno.h>
+
+// Compatibility workaround
+#ifndef AF_LOCAL
+#define AF_LOCAL AF_UNIX
+#endif
+
+//
+// Constants
+//
+
+#define LOOPBACK "127.0.0.1"
+#define NS_PORT 53
+#define DAEMON_PORT 5355                // default, may be overridden via command line argument
+#define LISTENQ 128                     // tcp connection backlog
+#define RECV_BUFLEN 9000                
+#define LEASETABLE_INIT_NBUCKETS 256    // initial hashtable size (doubles as table fills)
+#define LLQ_TABLESIZE 1024              // !!!KRS make this dynamically growable
+#define EXPIRATION_INTERVAL 300          // check for expired records every 5 minutes
+#define SRV_TTL 7200                    // TTL For _dns-update SRV records
+
+// LLQ Lease bounds (seconds)
+#define LLQ_MIN_LEASE (15 * 60)
+#define LLQ_MAX_LEASE (120 * 60)
+#define LLQ_LEASE_FUDGE 60
+
+// LLQ SOA poll interval (microseconds)
+#define LLQ_MONITOR_ERR_INTERVAL (60 * 1000000)
+#define LLQ_MONITOR_INTERVAL 250000
+#ifdef SIGINFO
+#define INFO_SIGNAL SIGINFO
+#else
+#define INFO_SIGNAL SIGUSR1
+#endif
+
+#define SAME_INADDR(x,y) (*((mDNSu32 *)&x) == *((mDNSu32 *)&y))
+#define ZERO_LLQID(x) (!memcmp(x, "\x0\x0\x0\x0", 8))
+
+//
+// Data Structures
+// Structs/fields that must be locked for thread safety are explicitly commented
+//
+
+typedef struct
+	{
+    struct sockaddr_in src;
+    size_t len;
+    DNSMessage msg;
+    // Note: extra storage for oversized (TCP) messages goes here
+	} PktMsg;
+
+// lease table entry
+typedef struct RRTableElem
+	{
+    struct RRTableElem *next;
+    struct sockaddr_in cli;   // client's source address
+    long expire;              // expiration time, in seconds since epoch
+    domainname zone;          // from zone field of update message
+    CacheRecord rr;           // last field in struct allows for allocation of oversized RRs
+	} RRTableElem;
+
+typedef enum
+	{
+	RequestReceived = 0,
+	ChallengeSent   = 1,
+	Established     = 2
+	} LLQState;
+
+// llq table entry
+typedef struct LLQEntry
+	{
+    struct LLQEntry *next;     
+    struct sockaddr_in cli;   // clien'ts source address 
+    domainname qname;
+    mDNSu16 qtype;
+    mDNSu8 id[8];
+    LLQState state;
+    mDNSu32 lease;            // original lease, in seconds
+    mDNSs32 expire;           // expiration, absolute, in seconds since epoch
+    CacheRecord *KnownAnswers;// !!!KRS this should be shared amongst identical questions
+	} LLQEntry;
+
+// daemon-wide information
+typedef struct 
+	{
+    // server variables - read only after initialization (no locking)
+    struct in_addr saddr;      // server address
+    domainname zone;           // zone being updated
+    int tcpsd;                 // listening TCP socket
+    int udpsd;                 // listening UDP socket
+
+    // daemon variables - read only after initialization (no locking)
+    uDNS_AuthInfo *AuthInfo;   // linked list of keys for signing deletion updates
+    mDNSIPPort port;           // listening port
+
+    // lease table variables (locked via mutex after initialization)
+    RRTableElem **table;       // hashtable for records with leases
+    pthread_mutex_t tablelock; // mutex for lease table
+    mDNSs32 nbuckets;          // buckets allocated
+    mDNSs32 nelems;            // elements in table
+
+    // LLQ table variables
+    LLQEntry *LLQTable[LLQ_TABLESIZE];  // !!!KRS change this and RRTable to use a common data structure
+    int LLQEventListenSock;       // Unix domain socket pair - polling thread writes to ServPollSock, which wakes
+    int LLQServPollSock;          // the main thread listening on EventListenSock, indicating that the zone has changed
+	} DaemonInfo;
+
+// args passed to UDP request handler thread as void*
+typedef struct
+	{
+    PktMsg pkt;
+    struct sockaddr_in cliaddr;
+    DaemonInfo *d;
+	} UDPRequestArgs;
+
+// args passed to TCP request handler thread as void*
+typedef struct
+	{
+    int sd;                     // socket connected to client
+    struct sockaddr_in cliaddr; 
+    DaemonInfo *d;
+	} TCPRequestArgs;
+
+//
+// Global Variables
+//
+
+// booleans to determine runtime output
+// read-only after initialization (no mutex protection)
+static mDNSBool foreground = 0;
+static mDNSBool verbose = 0;
+
+// globals set via signal handler (accessed exclusively by main select loop and signal handler)
+static mDNSBool terminate = 0;
+static mDNSBool dumptable = 0;
+
+//
+// Logging Routines
+// Log messages are delivered to syslog unless -f option specified
+//
+
+// common message logging subroutine
+mDNSlocal void PrintLog(const char *buffer)
+	{
+	if (foreground)	
+		{
+		fprintf(stderr,"%s\n", buffer);
+		fflush(stderr);
+		}
+	else				
+		{
+		openlog("dnsextd", LOG_CONS | LOG_PERROR, LOG_DAEMON);
+		syslog(LOG_ERR, "%s", buffer);
+		closelog();
+		}
+	}
+
+// Verbose Logging (conditional on -v option)
+mDNSlocal void VLog(const char *format, ...)
+	{
+   	unsigned char buffer[512];
+	va_list ptr;
+
+	if (!verbose) return;
+	va_start(ptr,format);
+	buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0;
+	va_end(ptr);
+ 	PrintLog(buffer);
+	}
+
+// Unconditional Logging
+mDNSlocal void Log(const char *format, ...)
+	{
+   	unsigned char buffer[512];
+	va_list ptr;
+
+	va_start(ptr,format);
+	buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0;
+	va_end(ptr);
+ 	PrintLog(buffer);
+	}
+
+// Error Logging
+// prints message "dnsextd <function>: <operation> - <error message>" 
+// must be compiled w/ -D_REENTRANT  for thread-safe errno usage
+mDNSlocal void LogErr(const char *fn, const char *operation)
+	{
+	char buf[512];
+	snprintf(buf, sizeof(buf), "%s: %s - %s", fn, operation, strerror(errno));
+	PrintLog(buf);
+	}
+
+//
+// Networking Utility Routines
+//
+
+// Convert DNS Message Header from Network to Host byte order
+mDNSlocal void HdrNToH(PktMsg *pkt)
+	{
+	// Read the integer parts which are in IETF byte-order (MSB first, LSB second)
+	mDNSu8 *ptr = (mDNSu8 *)&pkt->msg.h.numQuestions;
+	pkt->msg.h.numQuestions   = (mDNSu16)((mDNSu16)ptr[0] <<  8 | ptr[1]);
+	pkt->msg.h.numAnswers     = (mDNSu16)((mDNSu16)ptr[2] <<  8 | ptr[3]);
+	pkt->msg.h.numAuthorities = (mDNSu16)((mDNSu16)ptr[4] <<  8 | ptr[5]);
+	pkt->msg.h.numAdditionals = (mDNSu16)((mDNSu16)ptr[6] <<  8 | ptr[7]);
+	}
+
+// Convert DNS Message Header from Host to Network byte order
+mDNSlocal void HdrHToN(PktMsg *pkt)
+	{
+	mDNSu16 numQuestions   = pkt->msg.h.numQuestions;
+	mDNSu16 numAnswers     = pkt->msg.h.numAnswers;
+	mDNSu16 numAuthorities = pkt->msg.h.numAuthorities;
+	mDNSu16 numAdditionals = pkt->msg.h.numAdditionals;
+	mDNSu8 *ptr = (mDNSu8 *)&pkt->msg.h.numQuestions;
+
+	// Put all the integer values in IETF byte-order (MSB first, LSB second)
+	*ptr++ = (mDNSu8)(numQuestions   >> 8);
+	*ptr++ = (mDNSu8)(numQuestions   &  0xFF);
+	*ptr++ = (mDNSu8)(numAnswers     >> 8);
+	*ptr++ = (mDNSu8)(numAnswers     &  0xFF);
+	*ptr++ = (mDNSu8)(numAuthorities >> 8);
+	*ptr++ = (mDNSu8)(numAuthorities &  0xFF);
+	*ptr++ = (mDNSu8)(numAdditionals >> 8);
+	*ptr++ = (mDNSu8)(numAdditionals &  0xFF);
+	}
+
+// create a socket connected to nameserver
+// caller terminates connection via close()
+mDNSlocal int ConnectToServer(DaemonInfo *d)
+	{
+	struct sockaddr_in servaddr;
+	int sd;
+	
+	bzero(&servaddr, sizeof(servaddr));
+	if (d->saddr.s_addr) servaddr.sin_addr = d->saddr;
+	else                 inet_pton(AF_INET, LOOPBACK, &d->saddr);  // use loopback if server not explicitly specified			
+	servaddr.sin_port = htons(NS_PORT);
+	servaddr.sin_family = AF_INET;
+#ifndef NOT_HAVE_SA_LEN
+	servaddr.sin_len = sizeof(servaddr); 
+#endif
+	sd = socket(AF_INET, SOCK_STREAM, 0);
+	if (sd < 0) { LogErr("ConnectToServer", "socket");  return -1; }
+	if (connect(sd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) { LogErr("ConnectToServer", "connect"); return -1; }
+	return sd;
+	}
+
+// send an entire block of data over a connected socket, blocking if buffers are full
+mDNSlocal int MySend(int sd, const void *msg, int len)
+	{
+	int n, nsent = 0;
+
+	while (nsent < len)
+		{
+		n = send(sd, (char *)msg + nsent, len - nsent, 0);
+		if (n < 0) { LogErr("MySend", "send");  return -1; }
+		nsent += n;
+		}
+	return 0;
+	}
+
+// Transmit a DNS message, prefixed by its length, over TCP, blocking if necessary
+mDNSlocal int SendTCPMsg(int sd, PktMsg *pkt)
+	{
+	// send the lenth, in network byte order
+	mDNSu16 len = htons((mDNSu16)pkt->len);
+	if (MySend(sd, &len, sizeof(len)) < 0) return -1;
+
+	// send the message
+	return MySend(sd, &pkt->msg, pkt->len);
+	}
+
+// Receive len bytes, waiting until we have all of them.
+// Returns number of bytes read (which should always be the number asked for).
+static int my_recv(const int sd, void *const buf, const int len)
+    {
+    // Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions;
+    // use an explicit while() loop instead.
+    // Also, don't try to do '+=' arithmetic on the original "void *" pointer --
+    // arithmetic on "void *" pointers is compiler-dependent.
+    int remaining = len;
+    char *ptr = (char *)buf;
+    while (remaining)
+    	{
+    	ssize_t num_read = recv(sd, ptr, remaining, 0);
+    	if ((num_read == 0) || (num_read < 0) || (num_read > remaining)) return -1;
+    	ptr       += num_read;
+    	remaining -= num_read;
+    	}
+    return(len);
+    }
+
+// Return a DNS Message read off of a TCP socket, or NULL on failure
+// If storage is non-null, result is placed in that buffer.  Otherwise,
+// returned value is allocated with Malloc, and contains sufficient extra
+// storage for a Lease OPT RR
+
+mDNSlocal PktMsg *ReadTCPMsg(int sd, PktMsg *storage)
+	{	
+	int nread, allocsize;
+	mDNSu16 msglen = 0;	
+	PktMsg *pkt = NULL;
+	int srclen;
+	
+	nread = my_recv(sd, &msglen, sizeof(msglen));
+	if (nread < 0) { LogErr("TCPRequestForkFn", "recv"); goto error; }
+	msglen = ntohs(msglen);
+	if (nread != sizeof(msglen)) { Log("Could not read length field of message"); goto error; }	
+
+	if (storage)
+		{
+		if (msglen > sizeof(storage->msg)) { Log("ReadTCPMsg: provided buffer too small."); goto error; }
+		pkt = storage;
+		}
+	else
+		{
+		// buffer extra space to add an OPT RR
+		if (msglen > sizeof(DNSMessage)) allocsize = sizeof(PktMsg) - sizeof(DNSMessage) + msglen;
+		else                             allocsize = sizeof(PktMsg);		
+		pkt = malloc(allocsize);
+		if (!pkt) { LogErr("ReadTCPMsg", "malloc"); goto error; }
+		bzero(pkt, sizeof(*pkt));
+		}
+	
+	pkt->len = msglen;
+	srclen = sizeof(pkt->src);
+	if (getpeername(sd, (struct sockaddr *)&pkt->src, &srclen) ||
+		srclen != sizeof(pkt->src)) { LogErr("ReadTCPMsg", "getpeername"); bzero(&pkt->src, sizeof(pkt->src)); }
+	nread = my_recv(sd, &pkt->msg, msglen);
+	if (nread < 0) { LogErr("TCPRequestForkFn", "recv"); goto error; }
+	if (nread != msglen) { Log("Could not read entire message"); goto error; }
+	if (pkt->len < sizeof(DNSMessageHeader))
+		{ Log("ReadTCPMsg: Message too short (%d bytes)", pkt->len);  goto error; }	
+	HdrNToH(pkt);
+	return pkt;
+	//!!!KRS convert to HBO here?
+	error:
+	if (pkt && pkt != storage) free(pkt);
+	return NULL;
+	}
+
+//
+// Dynamic Update Utility Routines
+//
+
+// Get the lease life of records in a dynamic update
+// returns -1 on error or if no lease present
+mDNSlocal mDNSs32 GetPktLease(PktMsg *pkt)
+	{
+	mDNSs32 lease = -1;
+	const mDNSu8 *ptr = NULL, *end = (mDNSu8 *)&pkt->msg + pkt->len;
+	LargeCacheRecord lcr;
+	int i;
+	
+	HdrNToH(pkt);
+	ptr = LocateAdditionals(&pkt->msg, end);
+	if (ptr) 
+		for (i = 0; i < pkt->msg.h.numAdditionals; i++)
+			{
+			ptr = GetLargeResourceRecord(NULL, &pkt->msg, ptr, end, 0, kDNSRecordTypePacketAdd, &lcr);
+			if (!ptr) { Log("Unable to read additional record"); break; }
+			if (lcr.r.resrec.rrtype == kDNSType_OPT)
+				{
+				if (lcr.r.resrec.rdlength < LEASE_OPT_SIZE) continue;
+				if (lcr.r.resrec.rdata->u.opt.opt != kDNSOpt_Lease) continue;
+				lease = (mDNSs32)lcr.r.resrec.rdata->u.opt.OptData.lease;
+				break;
+				}
+			}
+
+	HdrHToN(pkt);
+	return lease;
+	}
+
+// check if a request and server response complete a successful dynamic update
+mDNSlocal mDNSBool SuccessfulUpdateTransaction(PktMsg *request, PktMsg *reply)
+	{
+	char buf[32];
+	char *vlogmsg = NULL;
+	
+	// check messages
+	if (!request || !reply) { vlogmsg = "NULL message"; goto failure; }
+	if (request->len < sizeof(DNSMessageHeader) || reply->len < sizeof(DNSMessageHeader)) { vlogmsg = "Malformatted message"; goto failure; }
+
+	// check request operation
+	if ((request->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask) != (request->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask))
+		{ vlogmsg = "Request opcode not an update"; goto failure; }
+
+	// check result
+	if ((reply->msg.h.flags.b[1] & kDNSFlag1_RC)) { vlogmsg = "Reply contains non-zero rcode";  goto failure; }
+	if ((reply->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask) != (kDNSFlag0_OP_Update | kDNSFlag0_QR_Response))
+		{ vlogmsg = "Reply opcode not an update response"; goto failure; }
+
+	VLog("Successful update from %s", inet_ntop(AF_INET, &request->src.sin_addr, buf, 32));
+	return mDNStrue;		
+
+	failure:
+	VLog("Request %s: %s", inet_ntop(AF_INET, &request->src.sin_addr, buf, 32), vlogmsg);
+	return mDNSfalse;
+	}
+
+// Allocate an appropriately sized CacheRecord and copy data from original
+mDNSlocal CacheRecord *CopyCacheRecord(CacheRecord *orig)
+	{
+	CacheRecord *cr;
+	size_t size = sizeof(*cr);
+	if (orig->resrec.rdlength > InlineCacheRDSize) size += orig->resrec.rdlength - InlineCacheRDSize;
+	cr = malloc(size);
+	if (!cr) { LogErr("CopyCacheRecord", "malloc"); return NULL; }
+	memcpy(cr, orig, size);
+	cr->resrec.rdata = (RData*)&cr->rdatastorage;
+	return cr;
+	}
+
+
+//
+// Lease Hashtable Utility Routines
+//
+
+// double hash table size
+// caller must lock table prior to invocation
+mDNSlocal void RehashTable(DaemonInfo *d)
+	{
+	RRTableElem *ptr, *tmp, **new;
+	int i, bucket, newnbuckets = d->nbuckets * 2;
+
+	new = malloc(sizeof(RRTableElem *) * newnbuckets);
+	if (!new) { LogErr("RehashTable", "malloc");  return; }
+	bzero(new, newnbuckets * sizeof(RRTableElem *));
+
+	for (i = 0; i < d->nbuckets; i++)
+		{
+		ptr = d->table[i];
+		while (ptr)
+			{
+			bucket = ptr->rr.resrec.namehash % newnbuckets;
+			tmp = ptr;
+			ptr = ptr->next;
+			tmp->next = new[bucket];
+			new[bucket] = tmp;
+			}
+		}
+	d->nbuckets = newnbuckets;
+	}
+
+// print entire contents of hashtable, invoked via SIGINFO
+mDNSlocal void PrintLeaseTable(DaemonInfo *d)
+	{
+	int i;
+	RRTableElem *ptr;
+	char rrbuf[80], addrbuf[16];
+	struct timeval now;
+	int hr, min, sec;
+
+	if (gettimeofday(&now, NULL)) { LogErr("PrintTable", "gettimeofday"); return; }
+	if (pthread_mutex_lock(&d->tablelock)) { LogErr("PrintTable", "pthread_mutex_lock"); return; }
+	
+	Log("Dumping Lease Table Contents (table contains %d resource records)", d->nelems);
+	for (i = 0; i < d->nbuckets; i++)
+		{
+		for (ptr = d->table[i]; ptr; ptr = ptr->next)
+			{
+			hr = ((ptr->expire - now.tv_sec) / 60) / 60;
+			min = ((ptr->expire - now.tv_sec) / 60) % 60;
+			sec = (ptr->expire - now.tv_sec) % 60;
+			Log("Update from %s, Expires in %d:%d:%d\n\t%s", inet_ntop(AF_INET, &ptr->cli.sin_addr, addrbuf, 16), hr, min, sec,
+				GetRRDisplayString_rdb(&ptr->rr.resrec, &ptr->rr.resrec.rdata->u, rrbuf));
+			}
+		}
+	pthread_mutex_unlock(&d->tablelock);
+	}
+
+//
+// Startup SRV Registration Routines 
+// Register _dns-update._udp/_tcp.<zone> SRV records indicating the port on which
+// the daemon accepts requests  
+//
+
+// delete all RRS of a given name/type
+mDNSlocal mDNSu8 *putRRSetDeletion(DNSMessage *msg, mDNSu8 *ptr, mDNSu8 *limit,  ResourceRecord *rr)
+	{
+	ptr = putDomainNameAsLabels(msg, ptr, limit, &rr->name);
+	if (!ptr || ptr + 10 >= limit) return NULL;  // out of space
+	ptr[0] = (mDNSu8)(rr->rrtype  >> 8);
+	ptr[1] = (mDNSu8)(rr->rrtype  &  0xFF);
+	ptr[2] = (mDNSu8)((mDNSu16)kDNSQClass_ANY >> 8);
+	ptr[3] = (mDNSu8)((mDNSu16)kDNSQClass_ANY &  0xFF);
+	bzero(ptr+4, sizeof(rr->rroriginalttl) + sizeof(rr->rdlength)); // zero ttl/rdata
+	msg->h.mDNS_numUpdates++;
+	return ptr + 10;
+	}
+
+mDNSlocal mDNSu8 *PutUpdateSRV(DaemonInfo *d, PktMsg *pkt, mDNSu8 *ptr, char *regtype, mDNSBool registration)
+	{
+	AuthRecord rr;
+	char hostname[1024], buf[80];
+	mDNSu8 *end = (mDNSu8 *)&pkt->msg + sizeof(DNSMessage);
+	
+	mDNS_SetupResourceRecord(&rr, NULL, 0, kDNSType_SRV, SRV_TTL, kDNSRecordTypeUnique, NULL, NULL);
+	rr.resrec.rrclass = kDNSClass_IN;
+	rr.resrec.rdata->u.srv.priority = 0;
+	rr.resrec.rdata->u.srv.weight = 0;
+	rr.resrec.rdata->u.srv.port.NotAnInteger = d->port.NotAnInteger;
+	if (!gethostname(hostname, 1024) < 0 || MakeDomainNameFromDNSNameString(&rr.resrec.rdata->u.srv.target, hostname))
+		rr.resrec.rdata->u.srv.target.c[0] = '\0';
+	
+	MakeDomainNameFromDNSNameString(&rr.resrec.name, regtype);
+	strcpy(rr.resrec.name.c + strlen(rr.resrec.name.c), d->zone.c);
+	VLog("%s  %s", registration ? "Registering SRV record" : "Deleting existing RRSet",
+		 GetRRDisplayString_rdb(&rr.resrec, &rr.resrec.rdata->u, buf));
+	if (registration) ptr = PutResourceRecord(&pkt->msg, ptr, &pkt->msg.h.mDNS_numUpdates, &rr.resrec);
+	else              ptr = putRRSetDeletion(&pkt->msg, ptr, end, &rr.resrec);
+	return ptr;
+	}
+
+
+// perform dynamic update.
+// specify deletion by passing false for the register parameter, otherwise register the records.
+mDNSlocal int UpdateSRV(DaemonInfo *d, mDNSBool registration)
+	{
+	int sd = -1;
+	mDNSOpaque16 id;
+	PktMsg pkt;
+	mDNSu8 *ptr = pkt.msg.data;
+	mDNSu8 *end = (mDNSu8 *)&pkt.msg + sizeof(DNSMessage);
+	mDNSu16 nAdditHBO;  // num additionas, in host byte order, required by message digest routine
+	PktMsg *reply = NULL;
+
+	int result = -1;	
+
+	// Initialize message
+	id.NotAnInteger = 0;
+	InitializeDNSMessage(&pkt.msg.h, id, UpdateReqFlags);
+	pkt.src.sin_addr.s_addr = htonl(INADDR_ANY); // address field set solely for verbose logging in subroutines
+	pkt.src.sin_family = AF_INET;
+	
+	// format message body
+	ptr = putZone(&pkt.msg, ptr, end, &d->zone, mDNSOpaque16fromIntVal(kDNSClass_IN));
+	if (!ptr) goto end;
+
+	ptr = PutUpdateSRV(d, &pkt, ptr, "_dns-update._udp.", registration); if (!ptr) goto end;
+	ptr = PutUpdateSRV(d, &pkt, ptr, "_dns-update._tcp.", registration); if (!ptr) goto end;
+	ptr = PutUpdateSRV(d, &pkt, ptr, "_dns-llq._udp.", registration);    if (!ptr) goto end;	
+	
+	nAdditHBO = pkt.msg.h.numAdditionals;
+	HdrHToN(&pkt);
+	if (d->AuthInfo)
+		{
+		ptr = DNSDigest_SignMessage(&pkt.msg, &ptr, &nAdditHBO, d->AuthInfo);
+		if (!ptr) goto end;
+		}
+	pkt.len = ptr - (mDNSu8 *)&pkt.msg;
+	
+	// send message, receive reply
+	sd = ConnectToServer(d);
+	if (sd < 0) { Log("UpdateSRV: ConnectToServer failed"); goto end; }  
+	if (SendTCPMsg(sd, &pkt)) { Log("UpdateSRV: SendTCPMsg failed"); }
+	reply = ReadTCPMsg(sd, NULL);
+	if (!SuccessfulUpdateTransaction(&pkt, reply))
+		Log("SRV record registration failed with rcode %d", reply->msg.h.flags.b[1] & kDNSFlag1_RC);
+	else result = 0;
+	
+	end:
+	if (!ptr) { Log("UpdateSRV: Error constructing lease expiration update"); }
+	if (sd >= 0) close(sd);	
+	if (reply) free(reply);
+	return result;
+   	}
+
+// wrapper routines/macros
+#define ClearUpdateSRV(d) UpdateSRV(d, 0)
+
+// clear any existing records prior to registration
+mDNSlocal int SetUpdateSRV(DaemonInfo *d)
+	{
+	int err;
+
+	err = ClearUpdateSRV(d);         // clear any existing record
+	if (!err) err = UpdateSRV(d, 1);
+	return err;
+	}
+
+//
+// Argument Parsing and Configuration
+//
+
+// read authentication information for a zone from command line argument
+// global optind corresponds to keyname argument on entry
+mDNSlocal int ReadAuthKey(int argc, char *argv[], DaemonInfo *d)
+	{
+	uDNS_AuthInfo *auth = NULL;
+	char keybuf[512];
+	mDNSs32 keylen;
+	
+	auth = malloc(sizeof(*auth));
+	if (!auth) { perror("ReadAuthKey, malloc");  goto error; }
+	auth->next = NULL;
+	if (argc < optind + 1) return -1;  // keyname + secret 
+	if (!MakeDomainNameFromDNSNameString(&auth->keyname, optarg))
+		{ fprintf(stderr, "Bad key name %s", optarg); goto error; }
+	keylen = DNSDigest_Base64ToBin(argv[optind++], keybuf, 512);
+	if (keylen < 0)
+		{ fprintf(stderr, "Bad shared secret %s (must be base-64 encoded string)", argv[optind-1]); goto error; }
+	DNSDigest_ConstructHMACKey(auth, keybuf, (mDNSu32)keylen);
+	d->AuthInfo = auth;
+	return 0;
+
+	error:
+	if (auth) free(auth);
+	return -1;	
+	}
+
+mDNSlocal int SetPort(DaemonInfo *d, char *PortAsString)
+	{
+	long l;
+
+	l = strtol(PortAsString, NULL, 10);                    // convert string to long
+	if ((!l && errno == EINVAL) || l > 65535) return -1;   // error check conversion
+	d->port.NotAnInteger = htons((mDNSu16)l);              // set to network byte order
+	return 0;
+	}
+	
+mDNSlocal void PrintUsage(void)
+	{
+	fprintf(stderr, "Usage: dnsextd -z <zone> [-vf] [ -s server ] [-k zone keyname secret] ...\n"
+			"Use \"dnsextd -h\" for help\n");
+	}
+
+mDNSlocal void PrintHelp(void)
+	{
+	fprintf(stderr, "\n\n");
+	PrintUsage();
+
+	fprintf(stderr, 
+			"dnsextd is a daemon that implements DNS extensions supporting Dynamic DNS Update Leases\n"
+            "and Long Lived Queries, used in Wide-Area DNS Service Discovery, on behalf of name servers\n"
+			"that do not natively support these extensions.  (See dns-sd.org for more info on DNS Service\n"
+			"Discovery, Update Leases, and Long Lived Queries.)\n\n"
+
+            "dnsextd requires one argument,the zone, which is the domain for which Update Leases\n"
+            "and Long Lived Queries are to be administered.  dnsextd communicates directly with the\n"
+			"primary master server for this zone.\n\n"
+
+			"The options are as follows:\n\n"
+
+			"-f    Run daemon in foreground.\n\n"
+
+			"-h    Print help.\n\n"
+
+			"-k    Specify TSIG authentication key for dynamic updates from daemon to name server.\n"
+			"      -k option is followed by the name of the key, and the shared secret as a base-64\n"
+            "      encoded string.  This key/secret are used by the daemon to delete resource records\n"
+            "      from the server when leases expire.  Clients are responsible for signing their\n"
+            "      update requests.\n\n"
+			
+			"-s    Specify address (IPv4 address in dotted-decimal notation) of the Primary Master\n"
+			"      name server.  Defaults to loopback (127.0.0.1), i.e. daemon and name server\n"
+			"      running on the same machine.\n\n"
+
+			"-v    Verbose output.\n\n"
+		);		   
+	}
+
+// Note: ProcessArgs called before process is daemonized, and therefore must open no descriptors
+// returns 0 (success) if program is to continue execution
+// output control arguments (-f, -v) do not affect this routine
+mDNSlocal int ProcessArgs(int argc, char *argv[], DaemonInfo *d)
+	{
+	int opt;
+
+	if (argc < 2) goto arg_error;
+
+	d->port.NotAnInteger = htons(DAEMON_PORT);  // default, may be overriden by command option
+	while ((opt = getopt(argc, argv, "z:p:hfvs:k:")) != -1)
+		{
+		switch(opt)
+			{
+			case 'p': if (SetPort(d, optarg) < 0) goto arg_error;
+        			  break;
+
+			case 'h': PrintHelp();    return -1;
+			case 'f': foreground = 1; break;
+			case 'v': verbose = 1;    break;
+			case 's': if (!inet_pton(AF_INET, optarg, &d->saddr)) goto arg_error;
+				      break;
+			case 'k': if (ReadAuthKey(argc, argv, d) < 0) goto arg_error;
+				      break;
+			case 'z': if (!MakeDomainNameFromDNSNameString(&d->zone, optarg))
+				          {
+						  fprintf(stderr, "Bad zone %s", optarg);
+						  goto arg_error;
+						  }
+ 				      break;
+			default:  goto arg_error;				
+			}
+		}
+		
+	if (!d->zone.c[0]) goto arg_error;  // zone is the only required argument
+	if (d->AuthInfo) AssignDomainName(d->AuthInfo->zone, d->zone); // if we have a shared secret, use it for the entire zone
+	return 0;
+	
+	arg_error:
+	PrintUsage();
+	return -1;
+	}
+
+
+//
+// Initialization Routines
+//
+
+// Allocate memory, initialize locks and bookkeeping variables
+mDNSlocal int InitLeaseTable(DaemonInfo *d)
+	{
+	if (pthread_mutex_init(&d->tablelock, NULL)) { LogErr("InitLeaseTable", "pthread_mutex_init"); return -1; }
+	d->nbuckets = LEASETABLE_INIT_NBUCKETS;
+	d->nelems = 0;
+	d->table = malloc(sizeof(RRTableElem *) * LEASETABLE_INIT_NBUCKETS);
+	if (!d->table) { LogErr("InitLeaseTable", "malloc"); return -1; }
+	bzero(d->table, sizeof(RRTableElem *) * LEASETABLE_INIT_NBUCKETS);
+	return 0;
+	}
+mDNSlocal int SetupSockets(DaemonInfo *daemon)
+	{
+	struct sockaddr_in daddr;
+	int sockpair[2];
+	
+	// set up sockets on which we receive requests
+	bzero(&daddr, sizeof(daddr));
+	daddr.sin_family = AF_INET;
+	daddr.sin_addr.s_addr = htonl(INADDR_ANY);
+
+	if (daemon->port.NotAnInteger) daddr.sin_port = daemon->port.NotAnInteger;
+	else                           daddr.sin_port = htons(DAEMON_PORT);
+	
+	daemon->tcpsd = socket(AF_INET, SOCK_STREAM, 0);
+	if (!daemon->tcpsd) { LogErr("SetupSockets", "socket");  return -1; }
+	if (bind(daemon->tcpsd, (struct sockaddr *)&daddr, sizeof(daddr)) < 0) { LogErr("SetupSockets", "bind"); return -1; }
+	if (listen(daemon->tcpsd, LISTENQ) < 0) { LogErr("SetupSockets", "listen"); return -1; }
+
+	daemon->udpsd = socket(AF_INET, SOCK_DGRAM, 0);
+	if (!daemon->udpsd) { LogErr("SetupSockets", "socket");  return -1; }
+	if (bind(daemon->udpsd, (struct sockaddr *)&daddr, sizeof(daddr)) < 0) { LogErr("SetupSockets", "bind"); return -1; }
+
+	// set up Unix domain socket pair for LLQ polling thread to signal main thread that a change to the zone occurred
+	if (socketpair(AF_LOCAL, SOCK_STREAM, 0, sockpair) < 0) { LogErr("SetupSockets", "socketpair"); return -1; }
+	daemon->LLQEventListenSock = sockpair[0];
+	daemon->LLQServPollSock = sockpair[1];
+	return 0;
+	}
+
+//
+// periodic table updates
+//
+
+// Delete a resource record from the nameserver via a dynamic update
+mDNSlocal void DeleteRecord(DaemonInfo *d, CacheRecord *rr, domainname *zone)
+	{
+	int sd = -1;
+	mDNSOpaque16 id;
+	PktMsg pkt;
+	mDNSu8 *ptr = pkt.msg.data;
+	mDNSu8 *end = (mDNSu8 *)&pkt.msg + sizeof(DNSMessage);
+	mDNSu16 nAdditHBO;  // num additionas, in host byte order, required by message digest routine
+	char buf[80];
+	PktMsg *reply = NULL;
+	
+	VLog("Expiring record %s", GetRRDisplayString_rdb(&rr->resrec, &rr->resrec.rdata->u, buf));	
+	sd = ConnectToServer(d);
+	if (sd < 0) { Log("DeleteRecord: ConnectToServer failed"); goto end; }
+	
+	id.NotAnInteger = 0;
+	InitializeDNSMessage(&pkt.msg.h, id, UpdateReqFlags);
+	
+	ptr = putZone(&pkt.msg, ptr, end, zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass));
+	if (!ptr) goto end;
+	ptr = putDeletionRecord(&pkt.msg, ptr, &rr->resrec);
+	if (!ptr) goto end;
+
+	nAdditHBO = pkt.msg.h.numAdditionals;
+	HdrHToN(&pkt);
+
+	if (d->AuthInfo)
+		{
+		ptr = DNSDigest_SignMessage(&pkt.msg, &ptr, &nAdditHBO, d->AuthInfo);
+		if (!ptr) goto end;
+		}
+
+	pkt.len = ptr - (mDNSu8 *)&pkt.msg;
+	pkt.src.sin_addr.s_addr = htonl(INADDR_ANY); // address field set solely for verbose logging in subroutines
+	pkt.src.sin_family = AF_INET;
+	if (SendTCPMsg(sd, &pkt)) { Log("DeleteRecord: SendTCPMsg failed"); }
+	reply = ReadTCPMsg(sd, NULL);
+	if (!SuccessfulUpdateTransaction(&pkt, reply))
+		Log("Expiration update failed with rcode %d", reply->msg.h.flags.b[1] & kDNSFlag1_RC);
+					  
+	end:
+	if (!ptr) { Log("DeleteRecord: Error constructing lease expiration update"); }
+	if (sd >= 0) close(sd);	
+	if (reply) free(reply);
+	}
+
+// iterate over table, deleting expired records
+mDNSlocal void DeleteExpiredRecords(DaemonInfo *d)
+	{
+	int i;
+	RRTableElem *ptr, *prev, *fptr;	
+	struct timeval now;
+
+	if (gettimeofday(&now, NULL)) { LogErr("DeleteExpiredRecords ", "gettimeofday"); return; }
+	if (pthread_mutex_lock(&d->tablelock)) { LogErr("DeleteExpiredRecords", "pthread_mutex_lock"); return; }
+	for (i = 0; i < d->nbuckets; i++)
+		{
+		ptr = d->table[i];
+		prev = NULL;
+		while (ptr)
+			{
+			if (ptr->expire - now.tv_sec < 0)
+				{
+				// delete record from server
+				DeleteRecord(d, &ptr->rr, &ptr->zone);
+				if (prev) prev->next = ptr->next;
+				else d->table[i] = ptr->next;
+				fptr = ptr;
+				ptr = ptr->next;
+				free(fptr);
+				d->nelems--;
+				}
+			else
+				{
+				prev = ptr;
+				ptr = ptr->next;
+				}
+			}
+		}
+	pthread_mutex_unlock(&d->tablelock);
+	}
+
+//
+// main update request handling
+//
+
+// Add, delete, or refresh records in table based on contents of a successfully completed dynamic update
+mDNSlocal void UpdateLeaseTable(PktMsg *pkt, DaemonInfo *d, mDNSs32 lease)
+	{
+	RRTableElem *prev, *rptr, *new = NULL;
+	int i, bucket;
+	LargeCacheRecord lcr;
+	const mDNSu8 *ptr, *end;
+	struct timeval time;
+	DNSQuestion zone;
+	char buf[80];
+	
+	if (pthread_mutex_lock(&d->tablelock)) { LogErr("UpdateLeaseTable", "pthread_mutex_lock"); return; }
+	HdrNToH(pkt);
+	ptr = pkt->msg.data;
+	end = (mDNSu8 *)&pkt->msg + pkt->len;
+	ptr = getQuestion(&pkt->msg, ptr, end, 0, &zone);
+	if (!ptr) { Log("UpdateLeaseTable: cannot read zone");  goto cleanup; }
+	ptr = LocateAuthorities(&pkt->msg, end);
+	if (!ptr) { Log("UpdateLeaseTable: Format error");  goto cleanup; }
+	
+	for (i = 0; i < pkt->msg.h.mDNS_numUpdates; i++)
+		{
+		ptr = GetLargeResourceRecord(NULL, &pkt->msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr);
+		if (!ptr) { Log("UpdateLeaseTable: GetLargeResourceRecord returned NULL"); goto cleanup; }
+		//!!!KRS we should include rdata in hash here
+		bucket = lcr.r.resrec.namehash % d->nbuckets;
+		
+		// look for RR in table
+		prev = NULL;
+		rptr = d->table[bucket];
+		while (rptr)
+			{
+			if (SameResourceRecord(&rptr->rr.resrec, &lcr.r.resrec)) break;
+			prev = rptr;
+			rptr = rptr->next;
+			}
+		
+		if (rptr)
+			{
+			// Record is already in table
+			if (!lcr.r.resrec.rroriginalttl && lcr.r.resrec.rrclass == kDNSClass_NONE)
+				{
+				// deletion record				
+				VLog("Received deletion update for %s", GetRRDisplayString_rdb(&lcr.r.resrec, &lcr.r.resrec.rdata->u, buf));
+				if (prev) prev->next = rptr->next;
+				else d->table[bucket] = rptr->next;
+				free(rptr);
+				d->nelems--;
+				}
+			else
+				{
+				// refresh
+				if (lease < 0)
+					{
+					Log("Update for record %s already in lease table with no refresh lease specified",
+						GetRRDisplayString_rdb(&lcr.r.resrec, &lcr.r.resrec.rdata->u, buf));
+					}
+				else
+					{
+					if (gettimeofday(&time, NULL)) { LogErr("UpdateLeaseTable", "gettimeofday"); goto cleanup; }
+					rptr->expire = time.tv_sec + (unsigned)lease;
+					VLog("Refreshing lease for %s", GetRRDisplayString_rdb(&lcr.r.resrec, &lcr.r.resrec.rdata->u, buf));					
+					}
+				}
+			}
+		else if (lease > 0)
+			{
+			// New record - add to table
+			if (d->nelems > d->nbuckets) RehashTable(d);
+			if (gettimeofday(&time, NULL)) { LogErr("UpdateLeaseTable", "gettimeofday"); goto cleanup; }
+			new = malloc(sizeof(RRTableElem) + lcr.r.resrec.rdlength - InlineCacheRDSize);
+			if (!new) { LogErr("UpdateLeaseTable", "malloc"); goto cleanup; }
+			memcpy(&new->rr, &lcr.r, sizeof(CacheRecord) + lcr.r.resrec.rdlength - InlineCacheRDSize);
+			new->rr.resrec.rdata = (RData *)&new->rr.rdatastorage;
+			new->expire = time.tv_sec + (unsigned)lease;
+			new->cli.sin_addr = pkt->src.sin_addr;
+			strcpy(new->zone.c, zone.qname.c);
+			new->next = d->table[bucket];
+			d->table[bucket] = new;
+			d->nelems++;
+			VLog("Adding update for %s to lease table", GetRRDisplayString_rdb(&lcr.r.resrec, &lcr.r.resrec.rdata->u, buf));
+			}
+		}
+					
+	cleanup:
+	pthread_mutex_unlock(&d->tablelock);
+	HdrHToN(pkt);
+	}
+
+// Given a successful reply from a server, create a new reply that contains lease information
+// Replies are currently not signed !!!KRS change this
+mDNSlocal PktMsg *FormatLeaseReply(DaemonInfo *d, PktMsg *orig, mDNSu32 lease)
+	{
+	PktMsg *reply;
+	mDNSu8 *ptr, *end;
+	mDNSOpaque16 flags;
+
+	(void)d;  //unused
+	reply = malloc(sizeof(*reply));
+	if (!reply) { LogErr("FormatLeaseReply", "malloc"); return NULL; }
+	flags.b[0] = kDNSFlag0_QR_Response | kDNSFlag0_OP_Update;
+	flags.b[1] = 0;
+ 
+	InitializeDNSMessage(&reply->msg.h, orig->msg.h.id, flags);
+	reply->src.sin_addr.s_addr = htonl(INADDR_ANY);            // unused except for log messages
+	reply->src.sin_family = AF_INET;
+	ptr = reply->msg.data;
+	end = (mDNSu8 *)&reply->msg + sizeof(DNSMessage);
+	ptr = putUpdateLease(&reply->msg, ptr, lease);
+	if (!ptr) { Log("FormatLeaseReply: putUpdateLease failed"); free(reply); return NULL; }				   
+	reply->len = ptr - (mDNSu8 *)&reply->msg;
+	return reply;
+	}
+
+// pkt is thread-local, not requiring locking
+mDNSlocal PktMsg *HandleRequest(PktMsg *pkt, DaemonInfo *d)
+	{
+	int sd = -1;
+	PktMsg *reply = NULL, *LeaseReply;
+	mDNSs32 lease;
+	char buf[32];
+	
+	// send msg to server, read reply
+	sd = ConnectToServer(d);
+	if (sd < 0)
+		{ Log("Discarding request from %s due to connection errors", inet_ntop(AF_INET, &pkt->src.sin_addr, buf, 32)); goto cleanup; }
+	if (SendTCPMsg(sd, pkt) < 0)
+		{ Log("Couldn't relay message from %s to server.  Discarding.", inet_ntop(AF_INET, &pkt->src.sin_addr, buf, 32)); goto cleanup; }
+	reply = ReadTCPMsg(sd, NULL);
+	
+	// process reply
+	if (!SuccessfulUpdateTransaction(pkt, reply))
+		{ VLog("Message from %s not a successful update.", inet_ntop(AF_INET, &pkt->src.sin_addr, buf, 32));  goto cleanup; }	
+	lease = GetPktLease(pkt);
+	UpdateLeaseTable(pkt, d, lease);
+	if (lease > 0)
+		{
+		LeaseReply = FormatLeaseReply(d, reply, lease);
+		if (!LeaseReply) Log("HandleRequest - unable to format lease reply");
+		free(reply); 
+		reply = LeaseReply;
+		}
+	cleanup:
+	if (sd >= 0) close(sd);
+	return reply;
+	}
+
+
+//
+// LLQ Support Routines
+//
+
+// Set fields of an LLQ Opt Resource Record
+mDNSlocal void FormatLLQOpt(AuthRecord *opt, int opcode, mDNSu8 *id, mDNSs32 lease)
+	{
+	bzero(opt, sizeof(*opt));
+	opt->resrec.rdata = &opt->rdatastorage;
+	opt->resrec.RecordType = kDNSRecordTypeKnownUnique; // to suppress warnings from other layers
+	opt->resrec.rrtype = kDNSType_OPT;
+	opt->resrec.rdlength = LLQ_OPT_SIZE;
+	opt->resrec.rdestimate = LLQ_OPT_SIZE;
+	opt->resrec.rdata->u.opt.opt = kDNSOpt_LLQ;
+	opt->resrec.rdata->u.opt.optlen = sizeof(LLQOptData);
+	opt->resrec.rdata->u.opt.OptData.llq.vers = kLLQ_Vers;
+	opt->resrec.rdata->u.opt.OptData.llq.llqOp = opcode;
+	opt->resrec.rdata->u.opt.OptData.llq.err = LLQErr_NoError;
+	memcpy(opt->resrec.rdata->u.opt.OptData.llq.id, id, 8);
+	opt->resrec.rdata->u.opt.OptData.llq.lease = lease;
+	}
+
+// Calculate effective remaining lease of an LLQ
+mDNSlocal mDNSu32 LLQLease(LLQEntry *e)
+	{
+	struct timeval t;
+	
+	gettimeofday(&t, NULL);
+	if (e->expire < t.tv_sec) return 0;
+	else return e->expire - t.tv_sec;
+	}
+
+mDNSlocal void FreeKnownAnswers(LLQEntry *e)
+	{
+	CacheRecord *tmp;
+
+	while(e->KnownAnswers)
+		{
+		tmp = e->KnownAnswers;
+		e->KnownAnswers = e->KnownAnswers->next;
+		free(tmp);
+		}
+	}
+
+mDNSlocal void DeleteLLQ(DaemonInfo *d, LLQEntry *e)
+	{
+	int bucket = bucket = DomainNameHashValue(&e->qname) % LLQ_TABLESIZE;
+	LLQEntry *prev = NULL, *ptr = d->LLQTable[bucket];
+	char addr[32];
+	
+	inet_ntop(AF_INET, &e->cli.sin_addr, addr, 32);
+	VLog("Deleting LLQ table entry for %##s client %s", e->qname.c, addr);
+
+	FreeKnownAnswers(e);
+	while(ptr)
+		{
+		if (ptr == e)
+			{
+			if (prev) prev->next = ptr->next;
+			else d->LLQTable[bucket] = ptr->next;
+			free(e);
+			return;
+			}
+		prev = ptr;
+		ptr = ptr->next;
+		}
+	Log("Error: DeleteLLQ - LLQ not in table");
+	}
+
+mDNSlocal int SendLLQ(DaemonInfo *d, PktMsg *pkt, struct sockaddr_in dst)
+	{
+	char addr[32];
+	int err = -1;
+
+	HdrHToN(pkt);
+	if (sendto(d->udpsd, &pkt->msg, pkt->len, 0, (struct sockaddr *)&dst, sizeof(dst)) != (int)pkt->len)
+		{
+		LogErr("DaemonInfo", "sendto");
+		Log("Could not send response to client %s", inet_ntop(AF_INET, &dst.sin_addr, addr, 32));
+		}
+	else err = 0;
+	HdrNToH(pkt);
+	return err;
+	}
+
+// if non-negative, sd is a TCP socket connected to the nameserver
+// otherwise, this routine creates and closes its own socket
+mDNSlocal CacheRecord *AnswerQuestion(DaemonInfo *d, LLQEntry *e, int sd)
+	{
+	PktMsg q;
+	int i;
+	const mDNSu8 *ansptr;
+	mDNSu8 *end = q.msg.data;
+	mDNSOpaque16 id, flags = QueryFlags;
+	PktMsg *reply = NULL;
+	LargeCacheRecord lcr;
+	CacheRecord *AnswerList = NULL;
+	mDNSu8 rcode;
+	mDNSBool CloseSDOnExit = sd < 0;
+	
+	VLog("Querying server for %##s type %d", e->qname.c, e->qtype);
+	
+	flags.b[0] |= kDNSFlag0_RD;  // recursion desired
+	id.NotAnInteger = 0;
+	InitializeDNSMessage(&q.msg.h, id, flags);
+	
+	end = putQuestion(&q.msg, end, end + AbsoluteMaxDNSMessageData, &e->qname, e->qtype, kDNSClass_IN);
+	if (!end) { Log("Error: AnswerQuestion - putQuestion returned NULL"); goto end; }
+	q.len = (int)(end - (mDNSu8 *)&q.msg);
+	
+	if (sd < 0) sd = ConnectToServer(d);
+	if (sd < 0) { Log("AnswerQuestion: ConnectToServer failed"); goto end; }
+	if (SendTCPMsg(sd, &q)) { Log("AnswerQuestion: SendTCPMsg failed"); close(sd); goto end; }
+	reply = ReadTCPMsg(sd, NULL);
+
+	if ((reply->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask) != (kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery))
+		{ Log("AnswerQuestion: %##s type %d - Invalid response flags from server"); goto end; }
+	rcode = (mDNSu8)(reply->msg.h.flags.b[1] & kDNSFlag1_RC);
+	if (rcode && rcode != kDNSFlag1_RC_NXDomain) { Log("AnswerQuestion: %##s type %d - non-zero rcode %d from server", e->qname.c, e->qtype, rcode); goto end; }
+
+	end = (mDNSu8 *)&reply->msg + reply->len;
+	ansptr = LocateAnswers(&reply->msg, end);
+	if (!ansptr) { Log("Error: AnswerQuestion - LocateAnswers returned NULL"); goto end; }
+
+	for (i = 0; i < reply->msg.h.numAnswers; i++)
+		{
+		//rr = malloc(sizeof(*rr));
+		//if (!rr) { LogErr("AnswerQuestion", "malloc"); goto end; }
+		ansptr = GetLargeResourceRecord(NULL, &reply->msg, ansptr, end, 0, kDNSRecordTypePacketAns, &lcr);
+		if (!ansptr) { Log("AnswerQuestions: GetLargeResourceRecord returned NULL"); goto end; }
+		if (lcr.r.resrec.rrtype != e->qtype || lcr.r.resrec.rrclass != kDNSClass_IN || !SameDomainName(&lcr.r.resrec.name, &e->qname))
+			{
+			Log("AnswerQuestion: response %##s type #d does not answer question %##s type #d.  Discarding",
+				  lcr.r.resrec.name.c, lcr.r.resrec.rrtype, e->qname.c, e->qtype);
+			}
+		else
+			{
+			CacheRecord *cr = CopyCacheRecord(&lcr.r);
+			if (!cr) { Log("Error: AnswerQuestion - CopyCacheRecord returned NULL"); goto end; }						   
+			cr->next = AnswerList;
+			AnswerList = cr;
+			}
+		}
+	
+	end:
+	if (sd > -1 && CloseSDOnExit) close(sd);
+	if (reply) free(reply);
+	e->state = Established;
+	return AnswerList;
+	}
+
+mDNSlocal void UpdateAnswerList(DaemonInfo *d, LLQEntry *e, CacheRecord *answers)
+	{
+	CacheRecord *prev = NULL, *na, *ka; // "new answer", "known answer"
+	PktMsg  response;
+	mDNSu8 *end = (mDNSu8 *)&response.msg.data;
+	mDNSOpaque16 msgID;
+	char rrbuf[80], addrbuf[32];
+	AuthRecord opt;
+	
+	// first pass - mark all answers for deletion
+	for (ka = e->KnownAnswers; ka; ka = ka->next)
+		ka->resrec.rroriginalttl = -1; // -1 means delete
+
+	// second pass - mark answers pre-existent
+	for (ka = e->KnownAnswers; ka; ka = ka->next)
+		{
+		for (na = answers; na; na = na->next)
+			{
+			if (SameResourceRecord(&ka->resrec, &na->resrec))
+				{ ka->resrec.rroriginalttl = 0; break; } // 0 means no change
+			}
+		}
+
+	// third pass - add new records
+	for (na = answers; na; na = na->next)
+		{
+		for (ka = e->KnownAnswers; ka; ka = ka->next)
+			if (SameResourceRecord(&ka->resrec, &na->resrec)) break;
+		if (!ka)
+			{
+			// answer is not in KA list
+			CacheRecord *cr = CopyCacheRecord(na);
+			if (!cr) { Log("Error: UpdateAnswerList - CopyCacheRecord returned NULL"); return; }
+			cr->resrec.rroriginalttl = 1; // 1 means add
+			cr->next = e->KnownAnswers;
+			e->KnownAnswers = cr;
+			}
+		}
+
+	// now send the update
+	msgID.NotAnInteger = random();
+	InitializeDNSMessage(&response.msg.h, msgID, ResponseFlags);
+	end = putQuestion(&response.msg, end, end + AbsoluteMaxDNSMessageData, &e->qname, e->qtype, kDNSClass_IN);
+	if (!end) { Log("Error: UpdateAnswerList - putQuestion returned NULL"); return; }
+
+	if (verbose) inet_ntop(AF_INET, &e->cli.sin_addr, addrbuf, 32);
+	// put adds/removes in packet
+	for (ka = e->KnownAnswers; ka; ka = ka->next)
+		{
+		if (ka->resrec.rroriginalttl)
+			{
+			if (verbose) GetRRDisplayString_rdb(&ka->resrec, &ka->resrec.rdata->u, rrbuf);
+			VLog("%s (%s): %s", addrbuf, (mDNSs32)ka->resrec.rroriginalttl < 0 ? "Remove": "Add", rrbuf);				 
+			end = PutResourceRecordTTLJumbo(&response.msg, end, &response.msg.h.numAnswers, &ka->resrec, ka->resrec.rroriginalttl);
+			if (!end) { Log("Error: UpdateAnswerList - UpdateAnswerList returned NULL"); return; }
+			}
+		}
+
+	// delete removes from list
+	ka = e->KnownAnswers;
+	while (ka)
+		{
+		if ((mDNSs32)ka->resrec.rroriginalttl < 0)
+			{
+			CacheRecord *fptr = ka;
+			if (prev) prev->next = ka->next;
+			else e->KnownAnswers = ka->next;
+			ka = ka->next;
+			free(fptr);
+			}
+		else
+			{
+			prev = ka;
+			ka = ka->next;
+			}
+		}
+			   
+	FormatLLQOpt(&opt, kLLQOp_Event, e->id, LLQLease(e));
+	end = PutResourceRecordTTLJumbo(&response.msg, end, &response.msg.h.numAdditionals, &opt.resrec, 0);
+	if (!end) { Log("Error: PutResourceRecordTTLJumbo"); return; }
+
+	response.len = (int)(end - (mDNSu8 *)&response.msg);
+	if (response.msg.h.numAnswers)
+		if (SendLLQ(d, &response, e->cli) < 0) LogErr("UpdateAnswerList", "SendLLQ");		
+	}
+
+mDNSlocal void PrintLLQTable(DaemonInfo *d)
+	{
+	LLQEntry *e;
+	char addr[32];
+	int i;
+	
+	Log("Printing LLQ table contents");
+
+	for (i = 0; i < LLQ_TABLESIZE; i++)
+		{
+		e = d->LLQTable[i];
+		while(e)
+			{
+			inet_ntop(AF_INET, &e->cli.sin_addr, addr, 32);
+			Log("LLQ from %##s type %d lease %d (%d remaining)",
+				addr, e->qname.c, e->qtype, e->lease, LLQLease(e));
+			e = e->next;
+			}
+		}
+	}
+
+// Send events to clients as a result of a change in the zone
+mDNSlocal void GenLLQEvents(DaemonInfo *d)
+	{
+	LLQEntry *e, *tmp;
+	int i, sd;
+	struct timeval t;
+	char addr[32];
+	VLog("Generating LLQ Events");
+
+	gettimeofday(&t, NULL);
+	sd = ConnectToServer(d);
+	if (sd < 0) { Log("GenLLQEvents: ConnectToServer failed"); return; }
+	
+	for (i = 0; i < LLQ_TABLESIZE; i++)
+		{
+		e = d->LLQTable[i];
+		while(e)
+			{
+			if (e->expire < t.tv_sec)
+				{
+				inet_ntop(AF_INET, &e->cli.sin_addr, addr, 32);
+				VLog("Expiring LLQ %##s from %s", e->qname.c, addr);
+				tmp = e;
+				e = e->next;
+				DeleteLLQ(d, tmp);
+				}
+			else
+				{
+				CacheRecord *answers = AnswerQuestion(d, e, sd);
+				UpdateAnswerList(d, e, answers);
+				e = e->next;
+				}
+			}		
+		}
+	close(sd);
+	}
+
+// Monitor zone for changes that may produce LLQ events
+mDNSlocal void *LLQEventMonitor(void *DInfoPtr)
+	{
+	DaemonInfo *d = DInfoPtr;
+	PktMsg q;
+	mDNSu8 *end = q.msg.data;
+	const mDNSu8 *ptr;
+	mDNSOpaque16 id, flags = QueryFlags;
+	PktMsg reply;
+	mDNSs32 serial = 0;
+	mDNSBool SerialInitialized = mDNSfalse;
+	int sd;
+     LargeCacheRecord lcr;
+	ResourceRecord *rr = &lcr.r.resrec;
+	int i, sleeptime = 0;
+	domainname zone;
+	char pingmsg[4];
+	
+	// create question
+	id.NotAnInteger = 0;
+	InitializeDNSMessage(&q.msg.h, id, flags);
+	AssignDomainName(zone, d->zone);
+	end = putQuestion(&q.msg, end, end + AbsoluteMaxDNSMessageData, &zone, kDNSType_SOA, kDNSClass_IN);
+	if (!end) { Log("Error: LLQEventMonitor - putQuestion returned NULL"); return NULL; }
+	q.len = (int)(end - (mDNSu8 *)&q.msg);
+
+	sd = ConnectToServer(d);
+	if (sd < 0) { Log("LLQEventMonitor: ConnectToServer failed"); return NULL; }
+
+	while(1)
+		{
+		usleep(sleeptime);
+		sleeptime = LLQ_MONITOR_ERR_INTERVAL;  // if we bail on error below, rate limit retry
+		
+		// send message, receive response
+		if (SendTCPMsg(sd, &q)) { Log("LLQEventMonitor: SendTCPMsg failed"); continue; }
+		if (!ReadTCPMsg(sd, &reply)) { Log("LLQEventMonitor: ReadTCPMsg failed"); continue; }
+		end = (mDNSu8 *)&reply.msg + reply.len;
+		if (reply.msg.h.flags.b[1] & kDNSFlag1_RC) { Log("LLQEventMonitor - received non-zero rcode"); continue; }
+
+		// find answer
+		ptr = LocateAnswers(&reply.msg, end);
+		if (!ptr) { Log("Error: LLQEventMonitor - LocateAnswers returned NULL"); continue; }
+		for (i = 0; i < reply.msg.h.numAnswers; i++)
+			{
+			ptr = GetLargeResourceRecord(NULL, &reply.msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr);
+			if (!ptr) { Log("Error: LLQEventMonitor - GetLargeResourceRecord  returned NULL"); continue; }
+			if (rr->rrtype != kDNSType_SOA || rr->rrclass != kDNSClass_IN || !SameDomainName(&rr->name, &zone)) continue;
+			if (!SerialInitialized)
+				{
+				// first time through loop
+				SerialInitialized = mDNStrue;
+				serial = rr->rdata->u.soa.serial;
+				sleeptime = LLQ_MONITOR_INTERVAL;
+				break;
+				}
+			else if (rr->rdata->u.soa.serial != serial)
+				{
+				// update serial, wake main thread
+				serial = rr->rdata->u.soa.serial;
+				VLog("LLQEventMonitor: zone changed. Signaling main thread.");
+				if (send(d->LLQServPollSock, pingmsg, sizeof(pingmsg), 0) != sizeof(pingmsg))
+					{ LogErr("LLQEventMonitor", "send"); break; }
+				}
+			sleeptime = LLQ_MONITOR_INTERVAL;
+			break;			
+			}
+		if (!ptr) Log("LLQEventMonitor: response to query did not contain SOA");
+		}
+	}
+ 
+ // Allocate LLQ entry, insert into table
+mDNSlocal LLQEntry *NewLLQ(DaemonInfo *d, struct sockaddr_in cli, domainname *qname, mDNSu16 qtype, mDNSu32 lease)
+	{
+	char addr[32];
+	struct timeval t;
+	int bucket;
+	LLQEntry *e = malloc(sizeof(*e));
+	if (!e) { LogErr("NewLLQ", "malloc"); return NULL; }
+
+	inet_ntop(AF_INET, &cli.sin_addr, addr, 32);
+	VLog("Allocating LLQ entry for client %s question %##s type %d", addr, qname->c, qtype);
+	
+	// initialize structure
+	e->cli = cli;
+	AssignDomainName(e->qname, *qname);
+	e->qtype = qtype;
+	memset(e->id, 0, 8);
+	e->state = RequestReceived;
+	e->KnownAnswers = NULL;
+	
+	if (lease < LLQ_MIN_LEASE) lease = LLQ_MIN_LEASE;
+	else if (lease > LLQ_MAX_LEASE) lease = LLQ_MIN_LEASE;
+	gettimeofday(&t, NULL);
+	e->expire = t.tv_sec + (int)lease;
+	e->lease = lease;
+	
+	// add to table
+	bucket = DomainNameHashValue(qname) % LLQ_TABLESIZE;
+	e->next = d->LLQTable[bucket];
+	d->LLQTable[bucket] = e;
+	
+	return e;
+	}
+
+// Handle a refresh request from client
+mDNSlocal void LLQRefresh(DaemonInfo *d, LLQEntry *e, LLQOptData *llq, mDNSOpaque16 msgID)
+	{
+	AuthRecord opt;
+	PktMsg ack;
+	mDNSu8 *end = (mDNSu8 *)&ack.msg.data;
+	char addr[32];
+
+	inet_ntop(AF_INET, &e->cli.sin_addr, addr, 32);
+	VLog("%s LLQ for %##s from %s", llq->lease ? "Refreshing" : "Deleting", e->qname.c, addr);
+	
+	if (llq->lease)
+		{
+		if (llq->lease < LLQ_MIN_LEASE) llq->lease = LLQ_MIN_LEASE;
+		else if (llq->lease > LLQ_MAX_LEASE) llq->lease = LLQ_MIN_LEASE;
+		}
+	
+	ack.src.sin_addr.s_addr = 0; // unused 
+	InitializeDNSMessage(&ack.msg.h, msgID, ResponseFlags);
+	end = putQuestion(&ack.msg, end, end + AbsoluteMaxDNSMessageData, &e->qname, e->qtype, kDNSClass_IN);
+	if (!end) { Log("Error: putQuestion"); return; }
+
+	FormatLLQOpt(&opt, kLLQOp_Refresh, e->id, llq->lease ? LLQLease(e) : 0);
+	end = PutResourceRecordTTLJumbo(&ack.msg, end, &ack.msg.h.numAdditionals, &opt.resrec, 0);
+	if (!end) { Log("Error: PutResourceRecordTTLJumbo"); return; }
+
+	ack.len = (int)(end - (mDNSu8 *)&ack.msg);
+	if (SendLLQ(d, &ack, e->cli)) Log("Error: LLQRefresh"); 
+
+	if (llq->lease) e->state = Established;
+	else DeleteLLQ(d, e);	
+	}
+
+// Complete handshake with Ack an initial answers
+mDNSlocal void LLQCompleteHandshake(DaemonInfo *d, LLQEntry *e, LLQOptData *llq, mDNSOpaque16 msgID)
+	{
+	char addr[32];
+	CacheRecord *ptr;
+	AuthRecord opt;
+	PktMsg ack;
+	mDNSu8 *end = (mDNSu8 *)&ack.msg.data;
+	char rrbuf[80], addrbuf[32];
+	
+	inet_ntop(AF_INET, &e->cli.sin_addr, addr, 32);
+
+	if (memcmp(llq->id, e->id, 8)           ||
+		llq->vers  != kLLQ_Vers             ||
+		llq->llqOp != kLLQOp_Setup          ||
+		llq->err   != LLQErr_NoError        ||
+		llq->lease > e->lease + LLQ_LEASE_FUDGE ||
+		llq->lease < e->lease - LLQ_LEASE_FUDGE)
+		{ Log("Incorrect challenge response from %s", addr); return; }
+
+	if (e->state == Established) VLog("Retransmitting LLQ ack + answers for %##s", e->qname.c);
+	else                         VLog("Delivering LLQ ack + answers for %##s", e->qname.c);  
+	
+	// format ack + answers
+	ack.src.sin_addr.s_addr = 0; // unused 
+	InitializeDNSMessage(&ack.msg.h, msgID, ResponseFlags);
+	end = putQuestion(&ack.msg, end, end + AbsoluteMaxDNSMessageData, &e->qname, e->qtype, kDNSClass_IN);
+	if (!end) { Log("Error: putQuestion"); return; }
+	
+	if (e->state != Established) e->KnownAnswers = AnswerQuestion(d, e, -1);  // only fetch KA list the first time through
+	if (verbose) inet_ntop(AF_INET, &e->cli.sin_addr, addrbuf, 32);
+	for (ptr = e->KnownAnswers; ptr; ptr = ptr->next)
+		{
+		if (verbose) GetRRDisplayString_rdb(&ptr->resrec, &ptr->resrec.rdata->u, rrbuf);
+		VLog("%s Intitial Answer - %s", addr, rrbuf);
+		end = PutResourceRecordTTLJumbo(&ack.msg, end, &ack.msg.h.numAnswers, &ptr->resrec, 1);
+		if (!end) { Log("Error: PutResourceRecordTTLJumbo"); return; }
+		}
+
+	FormatLLQOpt(&opt, kLLQOp_Setup, e->id, LLQLease(e));
+	end = PutResourceRecordTTLJumbo(&ack.msg, end, &ack.msg.h.numAdditionals, &opt.resrec, 0);
+	if (!end) { Log("Error: PutResourceRecordTTLJumbo"); return; }
+
+	ack.len = (int)(end - (mDNSu8 *)&ack.msg);
+	if (SendLLQ(d, &ack, e->cli)) Log("Error: LLQCompleteHandshake");
+	}
+
+mDNSlocal void LLQSetupChallenge(DaemonInfo *d, LLQEntry *e, LLQOptData *llq, mDNSOpaque16 msgID)
+	{
+	struct timeval t;
+	mDNSu32 randval;
+	PktMsg challenge;
+	mDNSu8 *end = challenge.msg.data;
+	AuthRecord opt;
+
+	if (e->state == ChallengeSent) VLog("Retransmitting LLQ setup challenge for %##s", e->qname.c);
+	else                           VLog("Sending LLQ setup challenge for %##s", e->qname.c);
+	
+	if (!ZERO_LLQID(llq->id)) { Log("Error: LLQSetupChallenge - nonzero ID"); return; } // server bug
+	if (llq->llqOp != kLLQOp_Setup) { Log("LLQSetupChallenge - incorrrect operation from client"); return; } // client error
+	
+	if (ZERO_LLQID(e->id)) // don't regenerate random ID for retransmissions
+		{
+		// construct ID <time><random>
+		gettimeofday(&t, NULL);
+		randval = random();
+		memcpy(e->id, &t.tv_sec, sizeof(t.tv_sec));
+		memcpy(e->id + sizeof(t.tv_sec), &randval, sizeof(randval));			   
+		}
+
+	// format response (query + LLQ opt rr)
+	challenge.src.sin_addr.s_addr = 0; // unused 
+	InitializeDNSMessage(&challenge.msg.h, msgID, ResponseFlags);
+	end = putQuestion(&challenge.msg, end, end + AbsoluteMaxDNSMessageData, &e->qname, e->qtype, kDNSClass_IN);
+	if (!end) { Log("Error: putQuestion"); return; }	
+	FormatLLQOpt(&opt, kLLQOp_Setup, e->id, LLQLease(e));
+	end = PutResourceRecordTTLJumbo(&challenge.msg, end, &challenge.msg.h.numAdditionals, &opt.resrec, 0);
+	if (!end) { Log("Error: PutResourceRecordTTLJumbo"); return; }
+	challenge.len = (int)(end - (mDNSu8 *)&challenge.msg);
+	if (SendLLQ(d, &challenge, e->cli)) { Log("Error: LLQSetupChallenge"); return; }
+	e->state = ChallengeSent;
+	}
+
+// Take action on an LLQ message from client.  Entry must be initialized and in table
+mDNSlocal void UpdateLLQ(DaemonInfo *d, LLQEntry *e, LLQOptData *llq, mDNSOpaque16 msgID)
+	{
+	switch(e->state)
+		{
+		case RequestReceived:
+			LLQSetupChallenge(d, e, llq, msgID);
+			return;
+		case ChallengeSent:
+			if (ZERO_LLQID(llq->id)) LLQSetupChallenge(d, e, llq, msgID); // challenge sent and lost
+			else LLQCompleteHandshake(d, e, llq, msgID);
+			return;
+		case Established:
+			if (ZERO_LLQID(llq->id))
+				{
+				// client started over.  reset state.
+				LLQEntry *newe = NewLLQ(d, e->cli, &e->qname, e->qtype, llq->lease);
+				if (!newe) return;
+				DeleteLLQ(d, e);
+				LLQSetupChallenge(d, newe, llq, msgID);
+				return;
+				}
+			else if (llq->llqOp == kLLQOp_Setup)
+				{ LLQCompleteHandshake(d, e, llq, msgID); return; } // Ack lost				
+			else if (llq->llqOp == kLLQOp_Refresh)
+				{ LLQRefresh(d, e, llq, msgID); return; }
+			else { Log("Unhandled message for established LLQ"); return; }
+		}	
+	}
+
+mDNSlocal LLQEntry *LookupLLQ(DaemonInfo *d, struct sockaddr_in cli, domainname *qname, mDNSu16 qtype, mDNSu8 *id)
+	{	
+	int bucket = bucket = DomainNameHashValue(qname) % LLQ_TABLESIZE;
+	LLQEntry *ptr = d->LLQTable[bucket];
+
+	while(ptr)
+		{
+		if (((ptr->state == ChallengeSent && ZERO_LLQID(id)) || // zero-id due to packet loss OK in state ChallengeSent
+			 !memcmp(id, ptr->id, 8)) &&                        // id match
+			SAME_INADDR(cli, ptr->cli) && qtype == ptr->qtype && SameDomainName(&ptr->qname, qname)) // same source, type, qname
+			return ptr;
+		ptr = ptr->next;
+		}
+	return NULL;
+	}
+
+mDNSlocal int RecvLLQ(DaemonInfo *d, PktMsg *pkt)
+	{
+	DNSQuestion q;
+	LargeCacheRecord opt;
+	int i, err = -1;
+	char addr[32];
+	const mDNSu8 *qptr = pkt->msg.data;
+    const mDNSu8 *end = (mDNSu8 *)&pkt->msg + pkt->len;
+	const mDNSu8 *aptr = LocateAdditionals(&pkt->msg, end);
+	LLQOptData *llq = NULL;
+	LLQEntry *e = NULL;
+	
+	HdrNToH(pkt);	
+	inet_ntop(AF_INET, &pkt->src.sin_addr, addr, 32);
+
+	VLog("Received LLQ msg from %s", addr);
+	// sanity-check packet
+	if (!pkt->msg.h.numQuestions || !pkt->msg.h.numAdditionals)
+		{
+		Log("Malformatted LLQ from %s with %d questions, %d additionals", addr, pkt->msg.h.numQuestions, pkt->msg.h.numAdditionals);			
+		goto end;
+		}
+
+	// find the OPT RR - must be last in message
+	for (i = 0; i < pkt->msg.h.numAdditionals; i++)
+		{
+		aptr = GetLargeResourceRecord(NULL, &pkt->msg, aptr, end, 0, kDNSRecordTypePacketAdd, &opt); 
+		if (!aptr) { Log("Malformatted LLQ from %s: could not get Additional record %d", addr, i); goto end; }
+		}
+
+	// validate OPT
+	if (opt.r.resrec.rrtype != kDNSType_OPT) { Log("Malformatted LLQ from %s: last Additional not an Opt RR", addr); goto end; }
+	if (opt.r.resrec.rdlength < pkt->msg.h.numQuestions * LLQ_OPT_SIZE) { Log("Malformatted LLQ from %s: Opt RR to small (%d bytes for %d questions)", addr, opt.r.resrec.rdlength, pkt->msg.h.numQuestions); }
+	
+	// dispatch each question
+	for (i = 0; i < pkt->msg.h.numQuestions; i++)
+		{
+		qptr = getQuestion(&pkt->msg, qptr, end, 0, &q);
+		if (!qptr) { Log("Malformatted LLQ from %s: cannot read question %d", addr, i); goto end; }
+		llq = (LLQOptData *)&opt.r.resrec.rdata->u.opt.OptData.llq + i; // point into OptData at index i
+		if (llq->vers != kLLQ_Vers) { Log("LLQ from %s contains bad version %d (expected %d)", addr, llq->vers, kLLQ_Vers); goto end; }
+		
+		e = LookupLLQ(d, pkt->src, &q.qname, q.qtype, llq->id);
+		if (!e)
+			{
+			// no entry - if zero ID, create new
+			e = NewLLQ(d, pkt->src, &q.qname, q.qtype, llq->lease);
+			if (!e) goto end;
+			}
+		UpdateLLQ(d, e, llq, pkt->msg.h.id);
+		}
+	err = 0;
+	
+	end:
+	HdrHToN(pkt);
+	return err;
+	}
+
+mDNSlocal mDNSBool IsLLQRequest(PktMsg *pkt)
+	{
+	const mDNSu8 *ptr = NULL, *end = (mDNSu8 *)&pkt->msg + pkt->len;
+	LargeCacheRecord lcr;
+	int i;
+	mDNSBool result = mDNSfalse;
+	
+	HdrNToH(pkt);		
+	if ((mDNSu8)(pkt->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask) != (mDNSu8)(kDNSFlag0_QR_Query | kDNSFlag0_OP_StdQuery)) goto end;
+
+	if (!pkt->msg.h.numAdditionals) goto end;
+	ptr = LocateAdditionals(&pkt->msg, end);
+	if (!ptr) goto end;
+
+	// find last Additional
+	for (i = 0; i < pkt->msg.h.numAdditionals; i++)
+		{
+		ptr = GetLargeResourceRecord(NULL, &pkt->msg, ptr, end, 0, kDNSRecordTypePacketAdd, &lcr);
+		if (!ptr) { Log("Unable to read additional record"); goto end; }
+		}
+	
+	if (lcr.r.resrec.rrtype == kDNSType_OPT &&
+		lcr.r.resrec.rdlength >= LLQ_OPT_SIZE &&
+		lcr.r.resrec.rdata->u.opt.opt == kDNSOpt_LLQ)
+		{ result = mDNStrue; goto end; }
+
+	end:
+	HdrHToN(pkt);
+	return result;
+	}
+
+// !!!KRS implement properly
+mDNSlocal mDNSBool IsLLQAck(PktMsg *pkt)
+	{
+	if (pkt->msg.h.flags.NotAnInteger == ResponseFlags.NotAnInteger &&
+		pkt->msg.h.numQuestions && !pkt->msg.h.numAnswers && !pkt->msg.h.numAuthorities) return mDNStrue;
+	return mDNSfalse;
+	}
+
+
+// request handler wrappers for TCP and UDP requests
+// (read message off socket, fork thread that invokes main processing routine and handles cleanup)
+mDNSlocal void *UDPUpdateRequestForkFn(void *vptr)
+	{
+	char buf[32];
+	UDPRequestArgs *req = vptr;
+	PktMsg *reply = NULL;
+	
+	VLog("Received UDP request: %d bytes from %s", req->pkt.len, inet_ntop(AF_INET, &req->pkt.src.sin_addr, buf, 32));  
+	//!!!KRS strictly speaking, we shouldn't use TCP for a UDP request because the server may give us a long answer that would require truncation for UDP delivery to client
+	reply = HandleRequest(&req->pkt, req->d);
+	if (reply)
+		{
+		if (sendto(req->d->udpsd, &reply->msg, reply->len, 0, (struct sockaddr *)&req->pkt.src, sizeof(req->pkt.src)) != (int)reply->len)
+			LogErr("UDPUpdateRequestForkFn", "sendto");		
+		}
+
+	if (reply) free(reply);		
+	free(req);
+	return NULL;
+	}
+
+//!!!KRS this needs to be changed to use non-blocking sockets
+mDNSlocal int RecvUDPRequest(int sd, DaemonInfo *d)
+	{
+	UDPRequestArgs *req;
+	pthread_t tid;
+	int clisize = sizeof(req->cliaddr);
+	
+	req = malloc(sizeof(UDPRequestArgs));
+	if (!req) { LogErr("RecvUDPRequest", "malloc"); return -1; }
+	bzero(req, sizeof(*req));
+	req->d = d;
+	req->pkt.len = recvfrom(sd, &req->pkt.msg, sizeof(req->pkt.msg), 0, (struct sockaddr *)&req->cliaddr, &clisize);
+	if ((int)req->pkt.len < 0) { LogErr("RecvUDPRequest", "recvfrom"); free(req); return -1; }
+	if (clisize != sizeof(req->cliaddr)) { Log("Client address of unknown size %d", clisize); free(req); return -1; }
+	req->pkt.src = req->cliaddr;
+
+	if (IsLLQRequest(&req->pkt))
+		{
+		// LLQ messages handled by main thread
+		int err = RecvLLQ(d, &req->pkt);
+		free(req);
+		return err;
+		}
+
+	if (IsLLQAck(&req->pkt)) return 0; // !!!KRS need to do acks + retrans
+	
+	if (pthread_create(&tid, NULL, UDPUpdateRequestForkFn, req)) { LogErr("RecvUDPRequest", "pthread_create"); free(req); return -1; }
+	return 0;
+	}
+
+mDNSlocal void *TCPRequestForkFn(void *vptr)
+	{
+	TCPRequestArgs *req = vptr;
+	PktMsg *in = NULL, *out = NULL;
+	char buf[32];
+	
+    //!!!KRS if this read blocks indefinitely, we can run out of threads
+	// read the request
+	in = ReadTCPMsg(req->sd, NULL);
+	if (!in)
+		{
+		LogMsg("TCPRequestForkFn: Could not read message from %s", inet_ntop(AF_INET, &req->cliaddr.sin_addr, buf, 32));
+		goto cleanup;
+		}
+
+	VLog("Received TCP request: %d bytes from %s", in->len, inet_ntop(AF_INET, &req->cliaddr.sin_addr, buf, 32));  	
+	// create the reply
+	out = HandleRequest(in, req->d);
+	if (!out)
+		{
+		LogMsg("TCPRequestForkFn: No reply for client %s", inet_ntop(AF_INET, &req->cliaddr.sin_addr, buf, 32));
+		goto cleanup;
+		}
+
+	// deliver reply to client
+	if (SendTCPMsg(req->sd, out) < 0) 
+		{
+		LogMsg("TCPRequestForkFn: Unable to send reply to client %s", inet_ntop(AF_INET, &req->cliaddr.sin_addr, buf, 32));
+		goto cleanup;
+		}
+		
+	cleanup:
+	free(req);
+	if (in) free(in);
+	if (out) free(out);
+	return NULL;	
+	}
+
+mDNSlocal int RecvTCPRequest(int sd, DaemonInfo *d)
+	{
+	TCPRequestArgs *req;
+	pthread_t tid;
+	int clilen = sizeof(req->cliaddr);
+	
+	req = malloc(sizeof(TCPRequestArgs));
+	if (!req) { LogErr("RecvTCPRequest", "malloc"); return -1; }
+	bzero(req, sizeof(*req));
+	req->d = d;
+	req->sd = accept(sd, (struct sockaddr *)&req->cliaddr, &clilen);
+	if (req->sd < 0) { LogErr("RecvTCPRequest", "accept"); return -1; }	
+	if (clilen != sizeof(req->cliaddr)) { Log("Client address of unknown size %d", clilen); free(req); return -1; }
+	if (pthread_create(&tid, NULL, TCPRequestForkFn, req)) { LogErr("RecvTCPRequest", "pthread_create"); free(req); return -1; }
+	return 0;
+	}
+
+// main event loop
+// listen for incoming requests, periodically check table for expired records, respond to signals
+mDNSlocal int ListenForUpdates(DaemonInfo *d)
+	{
+	int err;
+	int maxfdp1;
+	fd_set rset;
+	struct timeval timenow, timeout = { 0, 0 };
+	long NextTableCheck = 0;
+	
+   	VLog("Listening for requests...");
+
+	FD_ZERO(&rset);
+	maxfdp1 = d->tcpsd + 1;
+	if (d->udpsd + 1 > maxfdp1) maxfdp1 = d->udpsd + 1;
+	if (d->LLQEventListenSock + 1 > maxfdp1) maxfdp1 = d->LLQEventListenSock + 1;
+	
+	while(1)
+		{
+		// expire records if necessary, set timeout
+		if (gettimeofday(&timenow, NULL)) { LogErr("ListenForUpdates", "gettimeofday"); return -1; }
+		if (timenow.tv_sec >= NextTableCheck)
+			{
+			DeleteExpiredRecords(d);
+			NextTableCheck = timenow.tv_sec + EXPIRATION_INTERVAL;
+			}
+		timeout.tv_sec = NextTableCheck - timenow.tv_sec;
+		
+		FD_SET(d->tcpsd, &rset);
+		FD_SET(d->udpsd, &rset);
+		FD_SET(d->LLQEventListenSock, &rset);
+		
+		err = select(maxfdp1, &rset, NULL, NULL, &timeout);		
+		if (err < 0)
+			{
+			if (errno == EINTR)
+				{
+				if (terminate) { DeleteExpiredRecords(d); return 0; }
+				else if (dumptable) { PrintLeaseTable(d); PrintLLQTable(d); dumptable = 0; }
+				else Log("Received unhandled signal - continuing"); 
+				}
+			else { LogErr("ListenForUpdates", "select"); return -1; }
+			}
+		else
+			{
+			if (FD_ISSET(d->tcpsd, &rset)) RecvTCPRequest(d->tcpsd, d);
+			if (FD_ISSET(d->udpsd, &rset)) RecvUDPRequest(d->udpsd, d); 
+			if (FD_ISSET(d->LLQEventListenSock, &rset))
+				{
+				// clear signalling data off socket
+				char buf[32];
+				recv(d->LLQEventListenSock, buf, 32, 0);
+				GenLLQEvents(d);
+				}
+			}
+		}
+	return 0;
+	}
+
+// signal handler sets global variables, which are inspected by main event loop
+// (select automatically returns due to the handled signal)
+mDNSlocal void HndlSignal(int sig)
+	{
+	if (sig == SIGTERM || sig == SIGINT ) { terminate = 1; return; }
+	if (sig == INFO_SIGNAL)               { dumptable = 1; return; }
+	}
+
+int main(int argc, char *argv[])
+	{
+	pthread_t LLQtid;
+	DaemonInfo d;
+	bzero(&d, sizeof(DaemonInfo));
+	
+	if (signal(SIGTERM,     HndlSignal) == SIG_ERR) perror("Can't catch SIGTERM");
+	if (signal(INFO_SIGNAL, HndlSignal) == SIG_ERR) perror("Can't catch SIGINFO");
+	if (signal(SIGINT,      HndlSignal) == SIG_ERR) perror("Can't catch SIGINT");
+	
+	if (ProcessArgs(argc, argv, &d) < 0) exit(1);
+
+	if (!foreground)
+		{
+		if (daemon(0,0))
+			{
+			LogErr("main", "daemon");
+			fprintf(stderr, "Could not daemonize process, running in foreground");
+			foreground = 1;
+			}	
+		}
+
+	if (InitLeaseTable(&d) < 0) exit(1);
+	if (SetupSockets(&d) < 0) exit(1); 
+	if (SetUpdateSRV(&d) < 0) exit(1);
+	
+	if (pthread_create(&LLQtid, NULL, LLQEventMonitor, &d)) { LogErr("main", "pthread_create"); }
+	else ListenForUpdates(&d);              
+		
+	if (ClearUpdateSRV(&d) < 0) exit(1);  // clear update srv's even if ListenForUpdates or pthread_create returns an error
+	exit(0);
+	}
+
diff --git a/mDNSPosix/libnss_mdns.8 b/mDNSPosix/libnss_mdns.8
new file mode 100755
index 0000000..94d9e17
--- /dev/null
+++ b/mDNSPosix/libnss_mdns.8
@@ -0,0 +1,149 @@
+.\"	$Id: libnss_mdns.8,v 1.1 2004/06/29 03:34:28 cheshire Exp $
+.\"
+.\" See section LICENSE for license information.
+.\"
+.Dd June 15, 2004
+.Dt LIBNSS_MDNS 8
+.Os
+.Sh NAME
+.Nm libnss_mdns
+.Nd name service switch module to support Apple mdnsd
+.Sh DESCRIPTION
+The
+.Nm
+shared library implements a name service switch module to interface with Apple
+mdnsd.  It is enabled by adding
+.Ql mdns
+to the
+.Ql hosts:
+line of
+.Xr nsswitch.conf 5 .
+This will cause calls to
+.Xr gethostbyname 3 ,
+.Xr gethostbyname2 3
+and
+.Xr gethostbyaddr 3
+to include mdnsd in their lookup path.
+.Pp
+The
+.Nm
+shared library should be installed in the system library paths, typically in
+.Pa /lib .
+.Sh FILES
+.Bl -tag -width Pa -compact
+.It Pa /etc/nss_mdns.conf
+configuration options
+.El
+.Sh EXAMPLES
+In
+.Pa /etc/nsswitch.conf :
+.Dl hosts: files mdns dns
+.Pp
+This will cause the name service switch to lookup hostnames first using
+.Pa /etc/hosts ,
+then mdns and finally via DNS.
+.Sh DIAGNOSTICS
+.Nm
+dumps status information via
+.Xr syslog 3 .
+.Sh SEE ALSO
+.\" Cross-references should be ordered by section (low to high), then in
+.\"     alphabetical order.
+.Xr nsswitch.conf 5 ,
+.Xr nss_mdns.conf 5 ,
+.Xr ldconfig 8
+.Pp
+.Li info libc Qq Name Service Switch
+.\" .Sh STANDARDS
+.Sh HISTORY
+.Nm
+was originally written for
+.An NICTA Bq http://www.nicta.com.au/ .
+.Sh AUTHORS
+.An "Andrew White" Bq Andrew.White@nicta.com.au
+.Sh BUGS
+Return values for obscure error conditions may not match those expected by nsswitch code.
+.Pp
+Version 0.62 of mdnsd does not support an option to force link-local multicast lookups.
+.Ql PTR
+reverse lookups for non-link-local domains will not function correctly.
+.Sh LICENSE
+This software is licensed under the NICTA Public Source License version 1.0
+.Ss NICTA Public Software Licence
+Version 1.0
+.Pp
+Copyright 2004 National ICT Australia Ltd
+.Pp
+All rights reserved.
+.Pp
+By this licence, National ICT Australia Ltd (NICTA) grants permission,
+free of charge, to any person who obtains a copy of this software
+and any associated documentation files ("the Software") to use and
+deal with the Software in source code and binary forms without
+restriction, with or without modification, and to permit persons
+to whom the Software is furnished to do so, provided that the
+following conditions are met:
+.Bl -bullet
+.It
+Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimers.
+.It
+Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimers in
+the documentation and/or other materials provided with the
+distribution.
+.It
+The name of NICTA may not be used to endorse or promote products
+derived from this Software without specific prior written permission.
+.El
+.Pp
+EXCEPT AS EXPRESSLY STATED IN THIS LICENCE AND TO THE FULL EXTENT
+PERMITTED BY APPLICABLE LAW, THE SOFTWARE IS PROVIDED "AS-IS" AND
+NICTA MAKES NO REPRESENTATIONS, WARRANTIES OR CONDITIONS OF ANY
+KIND, EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION, ANY
+REPRESENTATIONS, WARRANTIES OR CONDITIONS REGARDING THE CONTENTS
+OR ACCURACY OF THE SOFTWARE, OR OF TITLE, MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, THE ABSENCE OF LATENT
+OR OTHER DEFECTS, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR
+NOT DISCOVERABLE.
+.Pp
+TO THE FULL EXTENT PERMITTED BY APPLICABLE LAW, IN NO EVENT WILL
+NICTA BE LIABLE ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
+NEGLIGENCE) FOR ANY LOSS OR DAMAGE WHATSOEVER, INCLUDING (WITHOUT
+LIMITATION) LOSS OF PRODUCTION OR OPERATION TIME, LOSS, DAMAGE OR
+CORRUPTION OF DATA OR RECORDS; OR LOSS OF ANTICIPATED SAVINGS,
+OPPORTUNITY, REVENUE, PROFIT OR GOODWILL, OR OTHER ECONOMIC LOSS;
+OR ANY SPECIAL, INCIDENTAL, INDIRECT, CONSEQUENTIAL, PUNITIVE OR
+EXEMPLARY DAMAGES ARISING OUT OF OR IN CONNECTION WITH THIS LICENCE,
+THE SOFTWARE OR THE USE OF THE SOFTWARE, EVEN IF NICTA HAS BEEN
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+.Pp
+If applicable legislation implies warranties or conditions, or
+imposes obligations or liability on NICTA in respect of the Software
+that cannot be wholly or partly excluded, restricted or modified,
+NICTA's liability is limited, to the full extent permitted by the
+applicable legislation, at its option, to:
+.Pp
+.Bl -tag -width "a." -compact
+.It a.
+in the case of goods, any one or more of the following:
+.Bl -tag -width "iii." -compact
+.It i.
+the replacement of the goods or the supply of equivalent goods;
+.It ii.
+the repair of the goods;
+.It iii.
+the payment of the cost of replacing the goods or of acquiring
+equivalent goods;
+.It iv.
+the payment of the cost of having the goods repaired; or
+.El
+.It b.
+in the case of services:
+.Bl -tag -width "iii." -compact
+.It i.
+the supplying of the services again; or 
+.It ii.
+the payment of the cost of having the services supplied again.
+.El
+.El
diff --git a/mDNSPosix/mDNSPosix.c b/mDNSPosix/mDNSPosix.c
index d9426ab..5aca8fa 100755
--- a/mDNSPosix/mDNSPosix.c
+++ b/mDNSPosix/mDNSPosix.c
@@ -1,10 +1,9 @@
-/*
- * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * 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
@@ -38,12 +37,81 @@
 	Change History (most recent first):
 
 $Log: mDNSPosix.c,v $
+Revision 1.66  2004/12/01 04:27:28  cheshire
+<rdar://problem/3872803> Darwin patches for Solaris and Suse
+Don't use uint32_t, etc. -- they require stdint.h, which doesn't exist on FreeBSD 4.x, Solaris, etc.
+
+Revision 1.65  2004/11/30 22:37:01  cheshire
+Update copyright dates and add "Mode: C; tab-width: 4" headers
+
+Revision 1.64  2004/11/23 03:39:47  cheshire
+Let interface name/index mapping capability live directly in JNISupport.c,
+instead of having to call through to the daemon via IPC to get this information.
+
+Revision 1.63  2004/11/12 03:16:43  rpantos
+rdar://problem/3809541 Add mDNSPlatformGetInterfaceByName, mDNSPlatformGetInterfaceName
+
+Revision 1.62  2004/10/28 03:24:42  cheshire
+Rename m->CanReceiveUnicastOn as m->CanReceiveUnicastOn5353
+
+Revision 1.61  2004/10/16 00:17:01  cheshire
+<rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check
+
+Revision 1.60  2004/09/26 23:20:36  ksekar
+<rdar://problem/3813108> Allow default registrations in multiple wide-area domains
+
+Revision 1.59  2004/09/21 21:02:55  cheshire
+Set up ifname before calling mDNS_RegisterInterface()
+
+Revision 1.58  2004/09/17 01:08:54  cheshire
+Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
+  The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
+  declared in that file are ONLY appropriate to single-address-space embedded applications.
+  For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
+
+Revision 1.57  2004/09/17 00:19:11  cheshire
+For consistency with AllDNSLinkGroupv6, rename AllDNSLinkGroup to AllDNSLinkGroupv4
+
+Revision 1.56  2004/09/17 00:15:56  cheshire
+Rename mDNSPlatformInit_ReceiveUnicast to mDNSPlatformInit_CanReceiveUnicast
+
+Revision 1.55  2004/09/16 00:24:49  cheshire
+<rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
+
+Revision 1.54  2004/09/15 23:55:00  ksekar
+<rdar://problem/3800597> mDNSPosix should #include stdint.h
+
+Revision 1.53  2004/09/14 23:42:36  cheshire
+<rdar://problem/3801296> Need to seed random number generator from platform-layer data
+
+Revision 1.52  2004/08/25 16:42:13  ksekar
+Fix Posix build - change mDNS_SetFQDNs to mDNS_SetFQDN, remove unicast
+hostname parameter.
+
+Revision 1.51  2004/08/14 03:22:42  cheshire
+<rdar://problem/3762579> Dynamic DNS UI <-> mDNSResponder glue
+Add GetUserSpecifiedDDNSName() routine
+Convert ServiceRegDomain to domainname instead of C string
+Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs
+
+Revision 1.50  2004/08/11 01:20:20  cheshire
+Declare private local functions using "mDNSlocal"
+
+Revision 1.49  2004/07/26 22:49:31  ksekar
+<rdar://problem/3651409>: Feature #9516: Need support for NATPMP in client
+
+Revision 1.48  2004/07/20 01:47:36  rpantos
+NOT_HAVE_SA_LEN applies to v6, too. And use more-portable s6_addr.
+
+Revision 1.47  2004/06/25 00:26:27  rpantos
+Changes to fix the Posix build on Solaris.
+
 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"
+from mDNSMacOSX.h to mDNSEmbeddedAPI.h), impelemted to return "local"
 only on non-OSX platforms.  Changed call to return a copy of the list
 to avoid shared memory issues.  Added a routine to free the list.
 
@@ -103,13 +171,13 @@ 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.
+Best solution is just to combine mDNSEmbeddedAPI.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
 
 Revision 1.24  2003/08/18 23:12:23  cheshire
-<rdar://problem/3382647> mDNSResponder divide by zero in mDNSPlatformTimeNow()
+<rdar://problem/3382647> mDNSResponder divide by zero in mDNSPlatformRawTime()
 
 Revision 1.23  2003/08/12 19:56:26  cheshire
 Update to APSL 2.0
@@ -187,7 +255,7 @@ Revision 1.1  2002/09/17 06:24:34  cheshire
 First checkin
 */
 
-#include "mDNSClientAPI.h"           // Defines the interface provided to the client layer above
+#include "mDNSEmbeddedAPI.h"           // Defines the interface provided to the client layer above
 #include "mDNSPosix.h"				 // Defines the specific types needed to run mDNS on this platform
 
 #include <assert.h>
@@ -261,7 +329,7 @@ int gMDNSPlatformPosixVerboseLevel = 0;
 
 #define PosixErrorToStatus(errNum) ((errNum) == 0 ? mStatus_NoError : mStatus_UnknownErr)
 
-static void SockAddrTomDNSAddr(const struct sockaddr *const sa, mDNSAddr *ipAddr, mDNSIPPort *ipPort)
+mDNSlocal void SockAddrTomDNSAddr(const struct sockaddr *const sa, mDNSAddr *ipAddr, mDNSIPPort *ipPort)
 	{
 	switch (sa->sa_family)
 		{
@@ -278,7 +346,9 @@ static void SockAddrTomDNSAddr(const struct sockaddr *const sa, mDNSAddr *ipAddr
 		case AF_INET6:
 			{
 			struct sockaddr_in6* sin6        = (struct sockaddr_in6*)sa;
+#ifndef NOT_HAVE_SA_LEN
 			assert(sin6->sin6_len == sizeof(*sin6));
+#endif
 			ipAddr->type                     = mDNSAddrType_IPv6;
 			ipAddr->ip.v6                    = *(mDNSv6Addr*)&sin6->sin6_addr;
 			if (ipPort) ipPort->NotAnInteger = sin6->sin6_port;
@@ -299,7 +369,7 @@ static void SockAddrTomDNSAddr(const struct sockaddr *const sa, mDNSAddr *ipAddr
 #endif
 
 // 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,
+mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const msg, const mDNSu8 *const end,
 	mDNSInterfaceID InterfaceID, const mDNSAddr *dst, mDNSIPPort dstPort)
 	{
 	int                     err = 0;
@@ -330,7 +400,9 @@ mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const DNSMessage *co
 		{
 		struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&to;
 		mDNSPlatformMemZero(sin6, sizeof(*sin6));
+#ifndef NOT_HAVE_SA_LEN
 		sin6->sin6_len            = sizeof(*sin6);
+#endif
 		sin6->sin6_family         = AF_INET6;
 		sin6->sin6_port           = dstPort.NotAnInteger;
 		sin6->sin6_addr           = *(struct in6_addr*)&dst->ip.v6;
@@ -355,7 +427,7 @@ mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const DNSMessage *co
 	}
 
 // This routine is called when the main loop detects that data is available on a socket.
-static void SocketDataReady(mDNS *const m, PosixNetworkInterface *intf, int skt)
+mDNSlocal void SocketDataReady(mDNS *const m, PosixNetworkInterface *intf, int skt)
 	{
 	mDNSAddr   senderAddr, destAddr;
 	mDNSIPPort senderPort;
@@ -400,7 +472,7 @@ static void SocketDataReady(mDNS *const m, PosixNetworkInterface *intf, int skt)
 			if ( (destAddr.NotAnInteger == 0) && (flags & MSG_MCAST) )
 				{
 				destAddr.type = senderAddr.type;
-				if      (senderAddr.type == mDNSAddrType_IPv4) destAddr.ip.v4 = AllDNSLinkGroup;
+				if      (senderAddr.type == mDNSAddrType_IPv4) destAddr.ip.v4 = AllDNSLinkGroupv4;
 				else if (senderAddr.type == mDNSAddrType_IPv6) destAddr.ip.v6 = AllDNSLinkGroupv6;
 				}
 		#endif
@@ -444,15 +516,9 @@ static void SocketDataReady(mDNS *const m, PosixNetworkInterface *intf, int skt)
 			}
 		}
 
-	if (packetLen >= 0 && packetLen < (ssize_t)sizeof(DNSMessageHeader))
-		{
-		debugf("SocketDataReady packet length (%d) too short", packetLen);
-		packetLen = -1;
-		}
-
 	if (packetLen >= 0)
 		mDNSCoreReceive(m, &packet, (mDNSu8 *)&packet + packetLen,
-			&senderAddr, senderPort, &destAddr, MulticastDNSPort, InterfaceID, ttl);
+			&senderAddr, senderPort, &destAddr, MulticastDNSPort, InterfaceID);
 	}
 
 mDNSexport mStatus mDNSPlatformTCPConnect(const mDNSAddr *dst, mDNSOpaque16 dstport, mDNSInterfaceID InterfaceID,
@@ -506,6 +572,11 @@ mDNSexport DNameListElem *mDNSPlatformGetSearchDomainList(void)
 	return mDNS_CopyDNameList(&tmp);
 	}
 
+mDNSexport DNameListElem *mDNSPlatformGetRegDomainList(void)
+	{
+	return NULL;
+	}
+
 #if COMPILER_LIKES_PRAGMA_MARK
 #pragma mark ***** Init and Term
 #endif
@@ -530,7 +601,7 @@ mDNSlocal void GetUserSpecifiedFriendlyComputerName(domainlabel *const 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)
+mDNSlocal PosixNetworkInterface *SearchForInterfaceByName(mDNS *const m, const char *intfName)
 	{
 	PosixNetworkInterface *intf;
 
@@ -550,7 +621,7 @@ extern mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(const mDNS *con
 
 	assert(m != NULL);
 
-	if (index == (uint32_t)~0) return(mDNSInterface_LocalOnly);
+	if (index == (mDNSu32)~0) return(mDNSInterface_LocalOnly);
 
 	intf = (PosixNetworkInterface*)(m->HostInterfaces);
 	while ( (intf != NULL) && (mDNSu32) intf->index != index) 
@@ -576,7 +647,7 @@ mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(const mDNS *const m
 
 // Frees the specified PosixNetworkInterface structure. The underlying
 // interface must have already been deregistered with the mDNS core.
-static void FreePosixNetworkInterface(PosixNetworkInterface *intf)
+mDNSlocal void FreePosixNetworkInterface(PosixNetworkInterface *intf)
 	{
 	assert(intf != NULL);
 	if (intf->intfName != NULL)        free((void *)intf->intfName);
@@ -588,7 +659,7 @@ static void FreePosixNetworkInterface(PosixNetworkInterface *intf)
 	}
 
 // Grab the first interface, deregister it, free it, and repeat until done.
-static void ClearInterfaceList(mDNS *const m)
+mDNSlocal void ClearInterfaceList(mDNS *const m)
 	{
 	assert(m != NULL);
 
@@ -607,7 +678,7 @@ static void ClearInterfaceList(mDNS *const m)
 // 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)
+mDNSlocal int SetupSocket(struct sockaddr *intfAddr, mDNSIPPort port, int interfaceIndex, int *sktPtr)
 	{
 	int err = 0;
 	static const int kOn = 1;
@@ -678,7 +749,7 @@ static int SetupSocket(struct sockaddr *intfAddr, mDNSIPPort port, int interface
 		// Add multicast group membership on this interface
 		if (err == 0 && port.NotAnInteger)
 			{
-			imr.imr_multiaddr.s_addr = AllDNSLinkGroup.NotAnInteger;
+			imr.imr_multiaddr.s_addr = AllDNSLinkGroupv4.NotAnInteger;
 			imr.imr_interface        = ((struct sockaddr_in*)intfAddr)->sin_addr;
 			err = setsockopt(*sktPtr, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(imr));
 			if (err < 0) { err = errno; perror("setsockopt - IP_ADD_MEMBERSHIP"); }
@@ -792,7 +863,9 @@ static int SetupSocket(struct sockaddr *intfAddr, mDNSIPPort port, int interface
 		if (err == 0)
 			{
 			mDNSPlatformMemZero(&bindAddr6, sizeof(bindAddr6));
+#ifndef NOT_HAVE_SA_LEN
 			bindAddr6.sin6_len         = sizeof(bindAddr6);
+#endif
 			bindAddr6.sin6_family      = AF_INET6;
 			bindAddr6.sin6_port        = port.NotAnInteger;
 			bindAddr6.sin6_flowinfo    = 0;
@@ -824,7 +897,7 @@ static int SetupSocket(struct sockaddr *intfAddr, mDNSIPPort port, int interface
 
 // Creates a PosixNetworkInterface for the interface whose IP address is
 // intfAddr and whose name is intfName and registers it with mDNS core.
-static int SetupOneInterface(mDNS *const m, struct sockaddr *intfAddr, const char *intfName)
+mDNSlocal int SetupOneInterface(mDNS *const m, struct sockaddr *intfAddr, struct sockaddr *intfMask, const char *intfName, int intfIndex)
 	{
 	int err = 0;
 	PosixNetworkInterface *intf;
@@ -833,6 +906,7 @@ static int SetupOneInterface(mDNS *const m, struct sockaddr *intfAddr, const cha
 	assert(m != NULL);
 	assert(intfAddr != NULL);
 	assert(intfName != NULL);
+	assert(intfMask != NULL);
 
 	// Allocate the interface structure itself.
 	intf = (PosixNetworkInterface*)malloc(sizeof(*intf));
@@ -849,12 +923,16 @@ 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);
+		SockAddrTomDNSAddr(intfMask, &intf->coreIntf.mask, NULL);
+		//LogMsg("SetupOneInterface: %#a %#a",  &intf->coreIntf.ip,  &intf->coreIntf.mask);
+		strncpy(intf->coreIntf.ifname, intfName, sizeof(intf->coreIntf.ifname));
+		intf->coreIntf.ifname[sizeof(intf->coreIntf.ifname)-1] = 0;
 		intf->coreIntf.Advertise = m->AdvertiseLocalAddresses;
 		intf->coreIntf.McastTxRx = mDNStrue;
 
 		// Set up the extra fields in PosixNetworkInterface.
 		assert(intf->intfName != NULL);         // intf->intfName already set up above
-		intf->index                = if_nametoindex(intf->intfName);
+		intf->index                = intfIndex;
 		intf->multicastSocket4     = -1;
 #if HAVE_IPV6
 		intf->multicastSocket6     = -1;
@@ -903,7 +981,7 @@ static int SetupOneInterface(mDNS *const m, struct sockaddr *intfAddr, const cha
 	}
 
 // Call get_ifi_info() to obtain a list of active interfaces and call SetupOneInterface() on each one.
-static int SetupInterfaceList(mDNS *const m)
+mDNSlocal int SetupInterfaceList(mDNS *const m)
 	{
 	mDNSBool        foundav4       = mDNSfalse;
 	int             err            = 0;
@@ -942,7 +1020,7 @@ static int SetupInterfaceList(mDNS *const m)
 					}
 				else
 					{
-					if (SetupOneInterface(m, i->ifi_addr, i->ifi_name) == 0)
+					if (SetupOneInterface(m, i->ifi_addr, i->ifi_netmask, i->ifi_name, i->ifi_index) == 0)
 						if (i->ifi_addr->sa_family == AF_INET)
 							foundav4 = mDNStrue;
 					}
@@ -956,7 +1034,7 @@ static int SetupInterfaceList(mDNS *const m)
 		// In the interim, we skip loopback interface only if we found at least one v4 interface to use
 		// if ( (m->HostInterfaces == NULL) && (firstLoopback != NULL) )
 		if ( !foundav4 && firstLoopback )
-			(void) SetupOneInterface(m, firstLoopback->ifi_addr, firstLoopback->ifi_name);
+			(void) SetupOneInterface(m, firstLoopback->ifi_addr, firstLoopback->ifi_netmask, firstLoopback->ifi_name, firstLoopback->ifi_index);
 		}
 
 	// Clean up.
@@ -969,7 +1047,7 @@ static int SetupInterfaceList(mDNS *const m)
 // See <http://www.faqs.org/rfcs/rfc3549.html> for a description of NetLink
 
 // Open a socket that will receive interface change notifications
-mStatus		OpenIfNotifySocket( int *pFD)
+mDNSlocal mStatus OpenIfNotifySocket( int *pFD)
 	{
 	mStatus					err = mStatus_NoError;
 	struct sockaddr_nl		snl;
@@ -997,7 +1075,7 @@ mStatus		OpenIfNotifySocket( int *pFD)
 	}
 
 #if MDNS_DEBUGMSGS
-static void		PrintNetLinkMsg( const struct nlmsghdr *pNLMsg)
+mDNSlocal void		PrintNetLinkMsg( const struct nlmsghdr *pNLMsg)
 	{
 	const char *kNLMsgTypes[] = { "", "NLMSG_NOOP", "NLMSG_ERROR", "NLMSG_DONE", "NLMSG_OVERRUN" };
 	const char *kNLRtMsgTypes[] = { "RTM_NEWLINK", "RTM_DELLINK", "RTM_GETLINK", "RTM_NEWADDR", "RTM_DELADDR", "RTM_GETADDR" };
@@ -1023,14 +1101,14 @@ static void		PrintNetLinkMsg( const struct nlmsghdr *pNLMsg)
 	}
 #endif
 
-static uint32_t		ProcessRoutingNotification( int sd)
+mDNSlocal mDNSu32		ProcessRoutingNotification( int sd)
 // Read through the messages on sd and if any indicate that any interface records should
 // be torn down and rebuilt, return affected indices as a bitmask. Otherwise return 0.
 	{
 	ssize_t					readCount;
 	char					buff[ 4096];	
 	struct nlmsghdr			*pNLMsg = (struct nlmsghdr*) buff;
-	uint32_t				result = 0;
+	mDNSu32				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
@@ -1086,7 +1164,7 @@ static uint32_t		ProcessRoutingNotification( int sd)
 #else // USES_NETLINK
 
 // Open a socket that will receive interface change notifications
-mStatus		OpenIfNotifySocket( int *pFD)
+mDNSlocal mStatus OpenIfNotifySocket( int *pFD)
 	{
 	*pFD = socket( AF_ROUTE, SOCK_RAW, 0);
 
@@ -1100,7 +1178,7 @@ mStatus		OpenIfNotifySocket( int *pFD)
 	}
 
 #if MDNS_DEBUGMSGS
-static void		PrintRoutingSocketMsg( const struct ifa_msghdr *pRSMsg)
+mDNSlocal void		PrintRoutingSocketMsg( const struct ifa_msghdr *pRSMsg)
 	{
 	const char *kRSMsgTypes[] = { "", "RTM_ADD", "RTM_DELETE", "RTM_CHANGE", "RTM_GET", "RTM_LOSING",
 					"RTM_REDIRECT", "RTM_MISS", "RTM_LOCK", "RTM_OLDADD", "RTM_OLDDEL", "RTM_RESOLVE", 
@@ -1112,14 +1190,14 @@ static void		PrintRoutingSocketMsg( const struct ifa_msghdr *pRSMsg)
 	}
 #endif
 
-static uint32_t		ProcessRoutingNotification( int sd)
+mDNSlocal mDNSu32		ProcessRoutingNotification( int sd)
 // Read through the messages on sd and if any indicate that any interface records should
 // be torn down and rebuilt, return affected indices as a bitmask. Otherwise return 0.
 	{
 	ssize_t					readCount;
 	char					buff[ 4096];	
 	struct ifa_msghdr		*pRSMsg = (struct ifa_msghdr*) buff;
-	uint32_t				result = 0;
+	mDNSu32				result = 0;
 
 	readCount = read( sd, buff, sizeof buff);
 	if ( readCount < (ssize_t) sizeof( struct ifa_msghdr))
@@ -1145,11 +1223,11 @@ static uint32_t		ProcessRoutingNotification( int sd)
 #endif // USES_NETLINK
 
 // Called when data appears on interface change notification socket
-static void InterfaceChangeCallback( void *context)
+mDNSlocal void InterfaceChangeCallback( void *context)
 	{
 	IfChangeRec		*pChgRec = (IfChangeRec*) context;
 	fd_set			readFDs;
-	uint32_t		changedInterfaces = 0;
+	mDNSu32		changedInterfaces = 0;
 	struct timeval	zeroTimeout = { 0, 0 };
 	
 	FD_ZERO( &readFDs);
@@ -1169,7 +1247,7 @@ static void InterfaceChangeCallback( void *context)
 	}
 
 // Register with either a Routing Socket or RtNetLink to listen for interface changes.
-static mStatus WatchForInterfaceChange(mDNS *const m)
+mDNSlocal mStatus WatchForInterfaceChange(mDNS *const m)
 	{
 	mStatus		err;
 	IfChangeRec	*pChgRec;
@@ -1189,7 +1267,7 @@ static mStatus WatchForInterfaceChange(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)
+mDNSlocal mDNSBool mDNSPlatformInit_CanReceiveUnicast(void)
 	{
 	int err;
 	int s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
@@ -1211,7 +1289,7 @@ mDNSexport mStatus mDNSPlatformInit(mDNS *const m)
 	struct sockaddr sa;
 	assert(m != NULL);
 
-	if (mDNSPlatformInit_ReceiveUnicast()) m->CanReceiveUnicast = mDNStrue;
+	if (mDNSPlatformInit_CanReceiveUnicast()) m->CanReceiveUnicastOn5353 = mDNStrue;
 
 	// Tell mDNS core the names of this machine.
 
@@ -1225,7 +1303,7 @@ mDNSexport mStatus mDNSPlatformInit(mDNS *const m)
 	GetUserSpecifiedRFC1034ComputerName(&m->hostlabel);
 	if (m->hostlabel.c[0] == 0) MakeDomainLabelFromLiteralString(&m->hostlabel, "Macintosh");
 
-	mDNS_GenerateFQDN(m);
+	mDNS_SetFQDN(m);
 
 	sa.sa_family = AF_INET;
 	m->p->unicastSocket4 = -1;
@@ -1342,18 +1420,24 @@ mDNSexport void    mDNSPlatformMemZero(                       void *dst, mDNSu32
 mDNSexport void *  mDNSPlatformMemAllocate(mDNSu32 len) { return(malloc(len)); }
 mDNSexport void    mDNSPlatformMemFree    (void *mem)   { free(mem); }
 
+mDNSexport mDNSu32 mDNSPlatformRandomSeed(void)
+	{
+	struct timeval tv;
+	gettimeofday(&tv, NULL);
+	return(tv.tv_usec);
+	}
+
 mDNSexport mDNSs32  mDNSPlatformOneSecond = 1024;
 
-mDNSexport mStatus mDNSPlatformTimeInit(mDNSs32 *timenow)
+mDNSexport mStatus mDNSPlatformTimeInit(void)
 	{
 	// No special setup is required on Posix -- we just use gettimeofday();
 	// This is not really safe, because gettimeofday can go backwards if the user manually changes the date or time
 	// We should find a better way to do this
-	*timenow = mDNSPlatformTimeNow();
 	return(mStatus_NoError);
 	}
 
-mDNSexport mDNSs32  mDNSPlatformTimeNow()
+mDNSexport mDNSs32  mDNSPlatformRawTime()
 	{
 	struct timeval tv;
 	gettimeofday(&tv, NULL);
@@ -1401,7 +1485,7 @@ mDNSexport void mDNSPosixGetFDSet(mDNS *m, int *nfds, fd_set *readfds, struct ti
 		}
 
 	// 3. Calculate the time remaining to the next scheduled event (in struct timeval format)
-	ticks = nextevent - mDNSPlatformTimeNow();
+	ticks = nextevent - mDNS_TimeNow(m);
 	if (ticks < 1) ticks = 1;
 	interval.tv_sec  = ticks >> 10;						// The high 22 bits are seconds
 	interval.tv_usec = ((ticks & 0x3FF) * 15625) / 16;	// The low 10 bits are 1024ths
@@ -1451,7 +1535,7 @@ mDNSexport void mDNSPosixProcessFDSet(mDNS *const m, fd_set *readfds)
 	}
 
 // update gMaxFD
-static void	DetermineMaxEventFD( void )
+mDNSlocal void	DetermineMaxEventFD( void )
 	{
 	PosixEventSource	*iSource;
 	
@@ -1510,7 +1594,7 @@ mStatus mDNSPosixRemoveFDFromEventLoop( int fd)
 	}
 
 // Simply note the received signal in gEventSignals.
-static void	NoteSignal( int signum)
+mDNSlocal void	NoteSignal( int signum)
 	{
 	sigaddset( &gEventSignals, signum);
 	}
diff --git a/mDNSPosix/mDNSPosix.h b/mDNSPosix/mDNSPosix.h
index d6ffbd6..0ee54dd 100755
--- a/mDNSPosix/mDNSPosix.h
+++ b/mDNSPosix/mDNSPosix.h
@@ -1,10 +1,9 @@
-/*
- * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * 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
@@ -25,6 +24,9 @@
     Change History (most recent first):
 
 $Log: mDNSPosix.h,v $
+Revision 1.16  2004/11/30 22:37:01  cheshire
+Update copyright dates and add "Mode: C; tab-width: 4" headers
+
 Revision 1.15  2004/02/06 01:19:51  cheshire
 Conditionally exclude IPv6 code unless HAVE_IPV6 is set
 
diff --git a/mDNSPosix/mDNSUNP.c b/mDNSPosix/mDNSUNP.c
index 8e60808..32a016c 100755
--- a/mDNSPosix/mDNSUNP.c
+++ b/mDNSPosix/mDNSUNP.c
@@ -1,10 +1,9 @@
-/*
- * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * 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
@@ -25,6 +24,27 @@
     Change History (most recent first):
 
 $Log: mDNSUNP.c,v $
+Revision 1.23  2004/12/01 04:25:05  cheshire
+<rdar://problem/3872803> Darwin patches for Solaris and Suse
+Provide daemon() for platforms that don't have it
+
+Revision 1.22  2004/11/30 22:37:01  cheshire
+Update copyright dates and add "Mode: C; tab-width: 4" headers
+
+Revision 1.21  2004/11/08 22:13:59  rpantos
+Create sockf6 lazily when v6 interface found.
+
+Revision 1.20  2004/10/16 00:17:01  cheshire
+<rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check
+
+Revision 1.19  2004/07/20 01:47:36  rpantos
+NOT_HAVE_SA_LEN applies to v6, too. And use more-portable s6_addr.
+
+Revision 1.18  2004/07/08 21:30:21  rpantos
+
+Revision 1.17  2004/06/25 00:26:27  rpantos
+Changes to fix the Posix build on Solaris.
+
 Revision 1.16  2004/03/20 05:37:09  cheshire
 Fix contributed by Terry Lambert & Alfred Perlstein:
 Don't use uint8_t -- it requires stdint.h, which doesn't exist on FreeBSD 4.x
@@ -109,12 +129,18 @@ First checkin
     #include <net/if_dl.h>
 #endif
 
+#if defined(AF_INET6) && HAVE_IPV6
+#include <netinet6/in6_var.h>
+#endif
 
 struct ifi_info *get_ifi_info(int family, int doaliases)
 {
     int                 junk;
     struct ifi_info     *ifi, *ifihead, **ifipnext;
-    int                 sockfd, len, lastlen, flags, myflags;
+    int                 sockfd, sockf6, len, lastlen, flags, myflags;
+#ifdef NOT_HAVE_IF_NAMETOINDEX
+    int                 index = 200;
+#endif
     char                *ptr, *buf, lastname[IFNAMSIZ], *cptr;
     struct ifconf       ifc;
     struct ifreq        *ifr, ifrcopy;
@@ -125,6 +151,7 @@ struct ifi_info *get_ifi_info(int family, int doaliases)
 #endif
 
     sockfd = -1;
+    sockf6 = -1;
     buf = NULL;
     ifihead = NULL;
     
@@ -199,7 +226,15 @@ struct ifi_info *get_ifi_info(int family, int doaliases)
 
         ifi->ifi_flags = flags;     /* IFF_xxx values */
         ifi->ifi_myflags = myflags; /* IFI_xxx values */
+#ifndef NOT_HAVE_IF_NAMETOINDEX
         ifi->ifi_index = if_nametoindex(ifr->ifr_name);
+#else
+        ifrcopy = *ifr;
+		if ( 0 >= ioctl(sockfd, SIOCGIFINDEX, &ifrcopy))
+            ifi->ifi_index = ifrcopy.ifr_index;
+        else
+            ifi->ifi_index = index++;	/* SIOCGIFINDEX is broken on Solaris 2.5ish, so fake it */
+#endif
         memcpy(ifi->ifi_name, ifr->ifr_name, IFI_NAME);
         ifi->ifi_name[IFI_NAME-1] = '\0';
 /* end get_ifi_info2 */
@@ -214,6 +249,14 @@ struct ifi_info *get_ifi_info(int family, int doaliases)
                 }
                 memcpy(ifi->ifi_addr, sinptr, sizeof(struct sockaddr_in));
 
+#ifdef  SIOCGIFNETMASK
+				if (ioctl(sockfd, SIOCGIFNETMASK, &ifrcopy) < 0) goto gotError;
+				ifi->ifi_netmask = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
+				if (ifi->ifi_netmask == NULL) goto gotError;
+				sinptr = (struct sockaddr_in *) &ifrcopy.ifr_addr;
+				memcpy(ifi->ifi_netmask, sinptr, sizeof(struct sockaddr_in));
+#endif
+
 #ifdef  SIOCGIFBRDADDR
                 if (flags & IFF_BROADCAST) {
                     if (ioctl(sockfd, SIOCGIFBRDADDR, &ifrcopy) < 0) {
@@ -256,8 +299,24 @@ struct ifi_info *get_ifi_info(int family, int doaliases)
                 /* Some platforms (*BSD) inject the prefix in IPv6LL addresses */
                 /* We need to strip that out */
                 if (IN6_IS_ADDR_LINKLOCAL(&sinptr6->sin6_addr))
-                	sinptr6->sin6_addr.__u6_addr.__u6_addr16[1] = 0;
+                	sinptr6->sin6_addr.s6_addr[2] = sinptr6->sin6_addr.s6_addr[3] = 0;
                 memcpy(ifi->ifi_addr, sinptr6, sizeof(struct sockaddr_in6));
+
+#ifdef  SIOCGIFNETMASK_IN6
+				{
+				struct in6_ifreq ifr6;
+				if (sockf6 == -1)
+					sockf6 = socket(AF_INET6, SOCK_DGRAM, 0);
+				bzero(&ifr6, sizeof(ifr6));
+				memcpy(&ifr6.ifr_name,           &ifr->ifr_name, sizeof(ifr6.ifr_name          ));
+				memcpy(&ifr6.ifr_ifru.ifru_addr, &ifr->ifr_addr, sizeof(ifr6.ifr_ifru.ifru_addr));
+				if (ioctl(sockf6, SIOCGIFNETMASK_IN6, &ifr6) < 0) goto gotError;
+				ifi->ifi_netmask = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in6));
+				if (ifi->ifi_netmask == NULL) goto gotError;
+				sinptr6 = (struct sockaddr_in6 *) &ifr6.ifr_ifru.ifru_addr;
+				memcpy(ifi->ifi_netmask, sinptr6, sizeof(struct sockaddr_in6));
+				}
+#endif
             }
             break;
 #endif
@@ -282,6 +341,10 @@ done:
         junk = close(sockfd);
         assert(junk == 0);
     }
+    if (sockf6 != -1) {
+        junk = close(sockf6);
+        assert(junk == 0);
+    }
     return(ifihead);    /* pointer to first structure in linked list */
 }
 /* end get_ifi_info3 */
@@ -407,11 +470,11 @@ struct in_pktinfo
         if (cmptr->cmsg_level == IPPROTO_IP &&
             cmptr->cmsg_type == IP_RECVIF) {
             struct sockaddr_dl  *sdl = (struct sockaddr_dl *) CMSG_DATA(cmptr);
-            int nameLen = (sdl->sdl_nlen < IFI_NAME - 1) ? sdl->sdl_nlen : (IFI_NAME - 1);
-            pktp->ipi_ifindex = sdl->sdl_index;
 #ifndef HAVE_BROKEN_RECVIF_NAME
+            int nameLen = (sdl->sdl_nlen < IFI_NAME - 1) ? sdl->sdl_nlen : (IFI_NAME - 1);
             strncpy(pktp->ipi_ifname, sdl->sdl_data, nameLen);
 #endif
+            pktp->ipi_ifindex = sdl->sdl_index;
             assert(pktp->ipi_ifname[IFI_NAME - 1] == 0);
             // null terminated because of memset above
             continue;
@@ -438,7 +501,9 @@ struct in_pktinfo
 			struct in6_pktinfo *ip6_info = (struct in6_pktinfo*)CMSG_DATA(cmptr);
 			
             sin6->sin6_family   = AF_INET6;
+#ifndef NOT_HAVE_SA_LEN
             sin6->sin6_len      = sizeof(*sin6);
+#endif
             sin6->sin6_addr     = ip6_info->ipi6_addr;
             sin6->sin6_flowinfo = 0;
             sin6->sin6_scope_id = 0;
@@ -460,3 +525,51 @@ struct in_pktinfo
     return(n);
 #endif /* CMSG_FIRSTHDR */
 }
+
+// **********************************************************************************************
+
+// daemonize the process. Adapted from "Unix Network Programming" vol 1 by Stevens, section 12.4.
+// Returns 0 on success, -1 on failure.
+
+#ifdef NOT_HAVE_DAEMON
+#include <fcntl.h>
+#include <sys/stat.h>
+int daemon(int nochdir, int noclose)
+    {
+	switch (fork())
+		{
+		case -1: return (-1);	// Fork failed
+		case 0:  break;			// Child -- continue
+		default: _exit(0);		// Parent -- exit
+		}
+
+	if (setsid() == -1) return(-1);
+
+	signal(SIGHUP, SIG_IGN);
+
+	switch (fork())				// Fork again, primarily for reasons of Unix trivia
+		{
+		case -1: return (-1);	// Fork failed
+		case 0:  break;			// Child -- continue
+		default: _exit(0);		// Parent -- exit
+		}
+
+	if (!nochdir) (void)chdir("/");
+	umask(0);
+
+	if (!noclose)
+		{
+		int fd = open("/dev/null", O_RDWR, 0);
+		if (fd != -1)
+			{
+			// Avoid unnecessarily duplicating a file descriptor to itself
+			if (fd != STDIN_FILENO) (void)dup2(fd, STDIN_FILENO);
+			if (fd != STDOUT_FILENO) (void)dup2(fd, STDOUT_FILENO);
+			if (fd != STDERR_FILENO) (void)dup2(fd, STDERR_FILENO);
+			if (fd != STDIN_FILENO && fd != STDOUT_FILENO && fd != STDERR_FILENO) 
+				(void)close (fd);
+			}
+		}
+	return (0);
+    }
+#endif /* NOT_HAVE_DAEMON */
diff --git a/mDNSPosix/mDNSUNP.h b/mDNSPosix/mDNSUNP.h
index 0d78baa..45d9235 100755
--- a/mDNSPosix/mDNSUNP.h
+++ b/mDNSPosix/mDNSUNP.h
@@ -1,10 +1,9 @@
-/*
- * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * 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
@@ -25,6 +24,16 @@
     Change History (most recent first):
 
 $Log: mDNSUNP.h,v $
+Revision 1.16  2004/12/01 04:25:05  cheshire
+<rdar://problem/3872803> Darwin patches for Solaris and Suse
+Provide daemon() for platforms that don't have it
+
+Revision 1.15  2004/11/30 22:37:01  cheshire
+Update copyright dates and add "Mode: C; tab-width: 4" headers
+
+Revision 1.14  2004/10/16 00:17:01  cheshire
+<rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check
+
 Revision 1.13  2004/03/20 05:37:09  cheshire
 Fix contributed by Terry Lambert & Alfred Perlstein:
 Don't use uint8_t -- it requires stdint.h, which doesn't exist on FreeBSD 4.x
@@ -128,6 +137,7 @@ struct ifi_info {
   short   ifi_myflags;          /* our own IFI_xxx flags */
   int     ifi_index;            /* interface index */
   struct sockaddr  *ifi_addr;   /* primary address */
+  struct sockaddr  *ifi_netmask;
   struct sockaddr  *ifi_brdaddr;/* broadcast address */
   struct sockaddr  *ifi_dstaddr;/* destination address */
   struct ifi_info  *ifi_next;   /* next of these structures */
@@ -145,6 +155,10 @@ extern struct ifi_info  *get_ifi_info(int family, int doaliases);
 /* returned by get_ifi_info and frees all the dynamic memory.' */
 extern void             free_ifi_info(struct ifi_info *);
 
+#ifdef NOT_HAVE_DAEMON
+extern int daemon(int nochdir, int noclose)
+#endif
+
 #ifdef  __cplusplus
     }
 #endif
diff --git a/mDNSPosix/mdnsd.sh b/mDNSPosix/mdnsd.sh
index 92be941..ad06e01 100644
--- a/mDNSPosix/mdnsd.sh
+++ b/mDNSPosix/mdnsd.sh
@@ -23,10 +23,15 @@
 # @APPLE_LICENSE_HEADER_END@
 #
 # $Log: mdnsd.sh,v $
+# Revision 1.6  2004/12/07 20:30:45  cheshire
+# Fix start-stop-daemon for Suse Linux (don't use -s TERM)
+#
+# Revision 1.5  2004/06/29 22:13:45  cheshire
+# Fix from Andrew White at NICTA
+#
 # Revision 1.4  2004/02/05 20:23:10  cheshire
 # Fix mdnsd.sh to work on *BSD distributions
 #
-#
 # Revision 1.3  2004/01/19 22:47:17  cheshire
 # Define killprocterm() to do "killproc $1 -TERM" for Linux
 #
@@ -51,8 +56,11 @@ 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
+	START="start-stop-daemon --start --quiet --exec"
+	# Suse Linux doesn't work with symbolic signal names, but we really don't need
+	# to specify "-s TERM" since SIGTERM (15) is the default stop signal anway
+	# STOP="start-stop-daemon --stop -s TERM --quiet --oknodo --exec"
+	STOP="start-stop-daemon --stop --quiet --oknodo --exec"
 else
 	killmdnsd() {
 		kill -TERM `cat /var/run/mdnsd.pid`
diff --git a/mDNSPosix/nss_ReadMe.txt b/mDNSPosix/nss_ReadMe.txt
new file mode 100755
index 0000000..2e3023c
--- /dev/null
+++ b/mDNSPosix/nss_ReadMe.txt
@@ -0,0 +1,125 @@
+# Readme for libnss_mdns
+
+Andrew White <Andrew.White@nicta.com.au>
+June 2004
+
+Before using this software, see "Licensing" at bottom of this file.
+
+
+# Introduction
+
+This code implements a module for the Name Service Switch to perform
+hostname lookups using the Darwin mDNSResponder / mdnsd.  This code has
+been tested on Debian and Redhat Linux.  It may work on other platforms. 
+It *will not* work on Darwin or Mac OS X - the necessary functionality is
+already built into the operation system.
+
+
+# Building and Installing:
+
+See "ReadMe.txt" for instructions on building and installing.
+
+When you run "make install" as described in that file:
+o libnss_mdns-0.2.so and libnss_mdns.so.2 are installed in /lib,
+o manual pages libnss_mdns(8) and nss_mdns.conf(5) are installed,
+o nss_mdns.conf is installed in /etc, and
+o /etc/nsswitch.conf is modified to add "mdns" on the "hosts:" line
+
+This will cause dns lookups to be passed via mdnsd before trying the dns.
+
+
+# Testing
+
+For most purposes, 'ping myhostname.local' will tell you if mdns is
+working.  If MDNS_VERBOSE was set in nss_mdns.c during compilation then
+lots of chatty debug messages will be dumped to LOG_DEBUG in syslog. 
+Otherwise, nss_mdns will only log if something isn't behaving quite right.
+
+
+# Implementation details
+
+libnss_mdns provides alternative back-end implementations of the libc
+functions gethostbyname, gethostbyname2 and gethostbyaddr, using the Name
+Service Switch mechanism.  More information on writing nsswitch modules
+can be found via 'info libc "Name Service Switch"', if installed.
+
+
+# Licensing
+
+This software is licensed under the NICTA Public Software License, version
+1.0, printed below:
+
+NICTA Public Software Licence
+Version 1.0
+
+Copyright Â© 2004 National ICT Australia Ltd
+
+All rights reserved.
+
+By this licence, National ICT Australia Ltd (NICTA) grants permission,
+free of charge, to any person who obtains a copy of this software
+and any associated documentation files ("the Software") to use and
+deal with the Software in source code and binary forms without
+restriction, with or without modification, and to permit persons
+to whom the Software is furnished to do so, provided that the
+following conditions are met:
+
+- Redistributions of source code must retain the above copyright
+  notice, this list of conditions and the following disclaimers.
+- Redistributions in binary form must reproduce the above copyright
+  notice, this list of conditions and the following disclaimers in
+  the documentation and/or other materials provided with the
+  distribution.
+- The name of NICTA may not be used to endorse or promote products
+  derived from this Software without specific prior written permission.
+
+EXCEPT AS EXPRESSLY STATED IN THIS LICENCE AND TO THE FULL EXTENT
+PERMITTED BY APPLICABLE LAW, THE SOFTWARE IS PROVIDED "AS-IS" AND
+NICTA MAKES NO REPRESENTATIONS, WARRANTIES OR CONDITIONS OF ANY
+KIND, EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION, ANY
+REPRESENTATIONS, WARRANTIES OR CONDITIONS REGARDING THE CONTENTS
+OR ACCURACY OF THE SOFTWARE, OR OF TITLE, MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, THE ABSENCE OF LATENT
+OR OTHER DEFECTS, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR
+NOT DISCOVERABLE.
+
+TO THE FULL EXTENT PERMITTED BY APPLICABLE LAW, IN NO EVENT WILL
+NICTA BE LIABLE ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
+NEGLIGENCE) FOR ANY LOSS OR DAMAGE WHATSOEVER, INCLUDING (WITHOUT
+LIMITATION) LOSS OF PRODUCTION OR OPERATION TIME, LOSS, DAMAGE OR
+CORRUPTION OF DATA OR RECORDS; OR LOSS OF ANTICIPATED SAVINGS,
+OPPORTUNITY, REVENUE, PROFIT OR GOODWILL, OR OTHER ECONOMIC LOSS;
+OR ANY SPECIAL, INCIDENTAL, INDIRECT, CONSEQUENTIAL, PUNITIVE OR
+EXEMPLARY DAMAGES ARISING OUT OF OR IN CONNECTION WITH THIS LICENCE,
+THE SOFTWARE OR THE USE OF THE SOFTWARE, EVEN IF NICTA HAS BEEN
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+If applicable legislation implies warranties or conditions, or
+imposes obligations or liability on NICTA in respect of the Software
+that cannot be wholly or partly excluded, restricted or modified,
+NICTA's liability is limited, to the full extent permitted by the
+applicable legislation, at its option, to:
+
+a. in the case of goods, any one or more of the following:
+  i.   the replacement of the goods or the supply of equivalent goods;
+  ii.  the repair of the goods;
+  iii. the payment of the cost of replacing the goods or of acquiring
+       equivalent goods;
+  iv.  the payment of the cost of having the goods repaired; or
+b. in the case of services:
+  i.   the supplying of the services again; or 
+  ii.  the payment of the cost of having the services supplied
+       again.
+
+
+# Links:
+
+NICTA
+	http://www.nicta.com.au/
+Darwin
+	http://developer.apple.com/darwin/
+DNS service discovery and link-local
+	http://http://zeroconf.org/
+	http://http://multicastdns.org/
+	http://http://dns-sd.org/
+	http://http://dotlocal.org/
diff --git a/mDNSPosix/nss_mdns.c b/mDNSPosix/nss_mdns.c
new file mode 100755
index 0000000..6baecca
--- /dev/null
+++ b/mDNSPosix/nss_mdns.c
@@ -0,0 +1,2732 @@
+/*
+NICTA Public Software Licence
+Version 1.0
+
+Copyright Â© 2004 National ICT Australia Ltd
+
+All rights reserved.
+
+By this licence, National ICT Australia Ltd (NICTA) grants permission,
+free of charge, to any person who obtains a copy of this software
+and any associated documentation files ("the Software") to use and
+deal with the Software in source code and binary forms without
+restriction, with or without modification, and to permit persons
+to whom the Software is furnished to do so, provided that the
+following conditions are met:
+
+- Redistributions of source code must retain the above copyright
+  notice, this list of conditions and the following disclaimers.
+- Redistributions in binary form must reproduce the above copyright
+  notice, this list of conditions and the following disclaimers in
+  the documentation and/or other materials provided with the
+  distribution.
+- The name of NICTA may not be used to endorse or promote products
+  derived from this Software without specific prior written permission.
+
+EXCEPT AS EXPRESSLY STATED IN THIS LICENCE AND TO THE FULL EXTENT
+PERMITTED BY APPLICABLE LAW, THE SOFTWARE IS PROVIDED "AS-IS" AND
+NICTA MAKES NO REPRESENTATIONS, WARRANTIES OR CONDITIONS OF ANY
+KIND, EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION, ANY
+REPRESENTATIONS, WARRANTIES OR CONDITIONS REGARDING THE CONTENTS
+OR ACCURACY OF THE SOFTWARE, OR OF TITLE, MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, THE ABSENCE OF LATENT
+OR OTHER DEFECTS, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR
+NOT DISCOVERABLE.
+
+TO THE FULL EXTENT PERMITTED BY APPLICABLE LAW, IN NO EVENT WILL
+NICTA BE LIABLE ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
+NEGLIGENCE) FOR ANY LOSS OR DAMAGE WHATSOEVER, INCLUDING (WITHOUT
+LIMITATION) LOSS OF PRODUCTION OR OPERATION TIME, LOSS, DAMAGE OR
+CORRUPTION OF DATA OR RECORDS; OR LOSS OF ANTICIPATED SAVINGS,
+OPPORTUNITY, REVENUE, PROFIT OR GOODWILL, OR OTHER ECONOMIC LOSS;
+OR ANY SPECIAL, INCIDENTAL, INDIRECT, CONSEQUENTIAL, PUNITIVE OR
+EXEMPLARY DAMAGES ARISING OUT OF OR IN CONNECTION WITH THIS LICENCE,
+THE SOFTWARE OR THE USE OF THE SOFTWARE, EVEN IF NICTA HAS BEEN
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+If applicable legislation implies warranties or conditions, or
+imposes obligations or liability on NICTA in respect of the Software
+that cannot be wholly or partly excluded, restricted or modified,
+NICTA's liability is limited, to the full extent permitted by the
+applicable legislation, at its option, to:
+
+a. in the case of goods, any one or more of the following:
+  i.   the replacement of the goods or the supply of equivalent goods;
+  ii.  the repair of the goods;
+  iii. the payment of the cost of replacing the goods or of acquiring
+       equivalent goods;
+  iv.  the payment of the cost of having the goods repaired; or
+b. in the case of services:
+  i.   the supplying of the services again; or 
+  ii.  the payment of the cost of having the services supplied
+       again.
+ */
+
+/*
+	NSSwitch Implementation of mDNS interface.
+	
+	Andrew White (Andrew.White@nicta.com.au)
+	May 2004
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <syslog.h>
+#include <pthread.h>
+#include <ctype.h>
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+
+#include <arpa/inet.h>
+#define BIND_8_COMPAT 1
+#include <arpa/nameser.h>
+
+#include <dns_sd.h>
+
+
+//----------
+// Public functions
+
+/*
+	Count the number of dots in a name string.
+ */
+int
+count_dots (const char * name);
+
+
+/*
+	Test whether a domain name is local.
+
+	Returns
+		1 if name ends with ".local" or ".local."
+		0 otherwise
+ */
+int
+islocal (const char * name);
+
+
+/*
+	Format an address structure as a string appropriate for DNS reverse (PTR)
+	lookup, based on address type.
+	
+	Parameters
+		prefixlen
+			Prefix length, in bits.  When formatting, this will be rounded up
+			to the nearest appropriate size.  If -1, assume maximum.
+		buf
+			Output buffer.  Must be long enough to hold largest possible
+			output.
+	Returns
+		Pointer to (first character of) output buffer,
+		or NULL on error.
+ */
+char *
+format_reverse_addr (int af, const void * addr, int prefixlen, char * buf);
+
+
+/*
+	Format an address structure as a string appropriate for DNS reverse (PTR)
+	lookup for AF_INET.  Output is in .in-addr.arpa domain.
+	
+	Parameters
+		prefixlen
+			Prefix length, in bits.  When formatting, this will be rounded up
+			to the nearest byte (8).  If -1, assume 32.
+		buf
+			Output buffer.  Must be long enough to hold largest possible
+			output.  For AF_INET, this is 29 characters (including null).
+	Returns
+		Pointer to (first character of) output buffer,
+		or NULL on error.
+ */
+char *
+format_reverse_addr_in (
+	const struct in_addr * addr,
+	int prefixlen,
+	char * buf
+);
+#define DNS_PTR_AF_INET_SIZE 29
+
+/*
+	Format an address structure as a string appropriate for DNS reverse (PTR)
+	lookup for AF_INET6.  Output is in .ip6.int domain.
+	
+	Parameters
+		prefixlen
+			Prefix length, in bits.  When formatting, this will be rounded up
+			to the nearest nibble (4).  If -1, assume 128.
+		buf
+			Output buffer.  Must be long enough to hold largest possible
+			output.  For AF_INET6, this is 72 characters (including null).
+	Returns
+		Pointer to (first character of) output buffer,
+		or NULL on error.
+ */
+char *
+format_reverse_addr_in6 (
+	const struct in6_addr * addr,
+	int prefixlen,
+	char * buf
+);
+#define DNS_PTR_AF_INET6_SIZE 72
+
+
+/*
+	Compare whether the given dns name has the given domain suffix.
+	A single leading '.' on the name or leading or trailing '.' on the
+	domain is ignored for the purposes of the comparison.
+	Multiple leading or trailing '.'s are an error.  Other DNS syntax
+	errors are not checked for.  The comparison is case insensitive.
+	
+	Returns
+		1 on success (match)
+		0 on failure (no match)
+		< 0 on error
+ */
+int
+cmp_dns_suffix (const char * name, const char * domain);
+enum
+{
+	CMP_DNS_SUFFIX_SUCCESS = 1,
+	CMP_DNS_SUFFIX_FAILURE = 0,
+	CMP_DNS_SUFFIX_BAD_NAME = 1,
+	CMP_DNS_SUFFIX_BAD_DOMAIN = -2
+};
+
+typedef int ns_type_t;
+typedef int ns_class_t;
+
+/*
+	Convert a DNS resource record (RR) code to an address family (AF) code.
+	
+	Parameters
+		rrtype
+			resource record type (from nameser.h)
+
+	Returns
+		Appropriate AF code (from socket.h), or AF_UNSPEC if an appropriate
+		mapping couldn't be determined
+ */
+int
+rr_to_af (ns_type_t rrtype);
+
+
+/*
+	Convert an address family (AF) code to a DNS resource record (RR) code.
+	
+	Parameters
+		int
+			address family code (from socket.h)
+	Returns
+		Appropriate RR code (from nameser.h), or ns_t_invalid if an appropriate
+		mapping couldn't be determined
+ */
+ns_type_t
+af_to_rr (int af);
+
+
+/*
+	Convert a string to an address family (case insensitive).
+
+	Returns
+		Matching AF code, or AF_UNSPEC if no match found.
+ */
+int
+str_to_af (const char * str);
+
+
+/*
+	Convert a string to an ns_class_t (case insensitive).
+
+	Returns
+		Matching ns_class_t, or ns_c_invalid if no match found.
+ */
+ns_class_t
+str_to_ns_class (const char * str);
+
+
+/*
+	Convert a string to an ns_type_t (case insensitive).
+
+	Returns
+		Matching ns_type_t, or ns_t_invalid if no match found.
+ */
+ns_type_t
+str_to_ns_type (const char * str);
+
+
+/*
+	Convert an address family code to a string.
+
+	Returns
+		String representation of AF,
+		or NULL if address family unrecognised or invalid.
+ */
+const char *
+af_to_str (int in);
+
+
+/*
+	Convert an ns_class_t code to a string.
+
+	Returns
+		String representation of ns_class_t,
+		or NULL if ns_class_t unrecognised or invalid.
+ */
+const char *
+ns_class_to_str (ns_class_t in);
+
+
+/*
+	Convert an ns_type_t code to a string.
+
+	Returns
+		String representation of ns_type_t,
+		or NULL if ns_type_t unrecognised or invalid.
+ */
+const char *
+ns_type_to_str (ns_type_t in);
+
+
+/*
+	Convert DNS rdata in label format (RFC1034, RFC1035) to a name.
+	
+	On error, partial data is written to name (as much as was successfully
+	processed) and an error code is returned.  Errors include a name too
+	long for the buffer and a pointer in the label (which cannot be
+	resolved).
+	
+	Parameters
+		rdata
+			Rdata formatted as series of labels.
+		rdlen
+			Length of rdata buffer.
+		name
+			Buffer to store fully qualified result in.
+			By RFC1034 section 3.1, a 255 character buffer (256 characters
+			including null) is long enough for any legal name.
+		name_len
+			Number of characters available in name buffer, not including
+			trailing null.
+	
+	Returns
+		Length of name buffer (not including trailing null).
+		< 0 on error.
+		A return of 0 implies the empty domain.
+ */
+int
+dns_rdata_to_name (const char * rdata, int rdlen, char * name, int name_len);
+enum
+{
+	DNS_RDATA_TO_NAME_BAD_FORMAT = -1,
+		// Format is broken.  Usually because we ran out of data
+		// (according to rdata) before the labels said we should.
+	DNS_RDATA_TO_NAME_TOO_LONG = -2,
+		// The converted rdata is longer than the name buffer.
+	DNS_RDATA_TO_NAME_PTR = -3,
+		// The rdata contains a pointer.
+};
+
+#define DNS_LABEL_MAXLEN 63
+	// Maximum length of a single DNS label
+#define DNS_NAME_MAXLEN 255
+	// Maximum length of a DNS name
+
+//----------
+// Public types
+
+typedef int errcode_t;
+	// Used for 0 = success, non-zero = error code functions
+
+
+//----------
+// Public functions
+
+/*
+	Test whether a domain name is in a domain covered by nss_mdns.
+	The name is assumed to be fully qualified (trailing dot optional);
+	unqualified names will be processed but may return unusual results
+	if the unqualified prefix happens to match a domain suffix.
+	
+	Returns
+		 1 success
+		 0 failure
+		-1 error, check errno
+ */
+int
+config_is_mdns_suffix (const char * name);
+
+
+/*
+	Loads all relevant data from configuration file.  Other code should
+	rarely need to call this function, since all other public configuration
+	functions do so implicitly.  Once loaded, configuration info doesn't
+	change.
+	
+	Returns
+		0 configuration ready
+		non-zero configuration error code
+ */
+errcode_t
+init_config ();
+
+#define ENTNAME  hostent
+#define DATABASE "hosts"
+
+#include <nss.h>
+	// For nss_status
+#include <netdb.h>
+	// For hostent
+#include <sys/types.h>
+	// For size_t
+
+typedef enum nss_status nss_status;
+typedef struct hostent hostent;
+
+/*
+gethostbyname implementation
+
+	name:
+		name to look up
+	result_buf:
+		resulting entry
+	buf:
+		auxillary buffer
+	buflen:
+		length of auxillary buffer
+	errnop:
+		pointer to errno
+	h_errnop:
+		pointer to h_errno
+ */
+nss_status
+_nss_mdns_gethostbyname_r (
+	const char *name,
+	hostent * result_buf,
+	char *buf,
+	size_t buflen,
+	int *errnop,
+	int *h_errnop
+);
+
+
+/*
+gethostbyname2 implementation
+
+	name:
+		name to look up
+	af:
+		address family
+	result_buf:
+		resulting entry
+	buf:
+		auxillary buffer
+	buflen:
+		length of auxillary buffer
+	errnop:
+		pointer to errno
+	h_errnop:
+		pointer to h_errno
+ */
+nss_status
+_nss_mdns_gethostbyname2_r (
+	const char *name,
+	int af,
+	hostent * result_buf,
+	char *buf,
+	size_t buflen,
+	int *errnop,
+	int *h_errnop
+);
+
+
+/*
+gethostbyaddr implementation
+
+	addr:
+		address structure to look up
+	len:
+		length of address structure
+	af:
+		address family
+	result_buf:
+		resulting entry
+	buf:
+		auxillary buffer
+	buflen:
+		length of auxillary buffer
+	errnop:
+		pointer to errno
+	h_errnop:
+		pointer to h_errno
+ */
+nss_status
+_nss_mdns_gethostbyaddr_r (
+	const void *addr,
+	socklen_t len,
+	int af,
+	hostent * result_buf,
+	char *buf,
+	size_t buflen,
+	int *errnop,
+	int *h_errnop
+);
+
+
+//----------
+// Types and Constants
+
+const int MDNS_VERBOSE = 0;
+	// This enables verbose syslog messages
+	// If zero, only "imporant" messages will appear in syslog
+
+#define k_hostname_maxlen 255
+	// As per RFC1034 and RFC1035
+#define k_aliases_max 15
+#define k_addrs_max 15
+
+const int k_mdnsd_intfs_local = 0;
+	// Tell mdnsd to perform lookups only using link-local interfaces.
+	/*
+		Currently, this feature is buggy.  0 will actually cause mdnsd to
+		do what it thinks is best.  Unfortunately, this is to lookup 'local'
+		addresses locally and remote addresses via the DNS.  Thus, lookups
+		for non-"local" addresses via mdns will not work correctly.
+		
+		Apple is currently modifying mdnsd to allow a special interface id
+		(expected value -2) to mean "always lookup locally".  This constant
+		should be changed once the change is made.
+		
+		AW - 16 June 2004
+	 */
+
+
+typedef struct buf_header
+{
+	char hostname [k_hostname_maxlen + 1];
+	char * aliases [k_aliases_max + 1];
+	char * addrs [k_addrs_max + 1];
+} buf_header_t;
+
+typedef struct result_map
+{
+	int done;
+	nss_status status;
+	hostent * hostent;
+	buf_header_t * header;
+	int aliases_count;
+	int addrs_count;
+	char * buffer;
+	int addr_idx;
+		// Index for addresses - grow from low end
+		// Index points to first empty space
+	int alias_idx;
+		// Index for aliases - grow from high end
+		// Index points to lowest entry
+	int r_errno;
+	int r_h_errno;
+} result_map_t;
+
+static const struct timeval
+	k_select_time = { 0, 500000 };
+		// 0 seconds, 500 milliseconds
+
+//----------
+// Local prototypes
+
+static nss_status
+mdns_gethostbyname2 (
+	const char *name,
+	int af,
+	hostent * result_buf,
+	char *buf,
+	size_t buflen,
+	int *errnop,
+	int *h_errnop
+);
+
+
+/*
+	Lookup name using mDNS server
+ */
+static nss_status
+mdns_lookup_name (
+	const char * fullname,
+	int af,
+	result_map_t * result
+);
+
+/*
+	Lookup address using mDNS server
+ */
+static nss_status
+mdns_lookup_addr (
+	const void * addr,
+	socklen_t len,
+	int af,
+	const char * addr_str,
+	result_map_t * result
+);
+
+
+/*
+	Handle incoming MDNS events
+ */
+static nss_status
+handle_events (DNSServiceRef sdref, result_map_t * result, const char * str);
+
+
+// Callback for mdns_lookup operations
+//DNSServiceQueryRecordReply mdns_lookup_callback;
+typedef void
+mdns_lookup_callback_t
+(
+	DNSServiceRef		sdref,
+	DNSServiceFlags		flags,
+	uint32_t			interface_index,
+	DNSServiceErrorType	error_code,
+	const char			*fullname,	  
+	uint16_t			rrtype,
+	uint16_t			rrclass,
+	uint16_t			rdlen,
+	const void			*rdata,
+	uint32_t			ttl,
+	void				*context
+);
+
+mdns_lookup_callback_t mdns_lookup_callback;
+
+
+static int
+init_result (
+	result_map_t * result,
+	hostent * result_buf,
+	char * buf,
+	size_t buflen
+);
+
+static int
+callback_body_ptr (
+	const char * fullname,
+	result_map_t * result,
+	int rdlen,
+	const void * rdata
+);
+
+static void *
+add_address_to_buffer (result_map_t * result, const void * data, int len);
+static char *
+add_alias_to_buffer (result_map_t * result, const char * data, int len);
+static char *
+add_hostname_len (result_map_t * result, const char * fullname, int len);
+static char *
+add_hostname_or_alias (result_map_t * result, const char * data, int len);
+
+static void *
+contains_address (result_map_t * result, const void * data, int len);
+static char *
+contains_alias (result_map_t * result, const char * data);
+
+
+static const char *
+is_applicable_name (
+	result_map_t * result,
+	const char * name,
+	char * lookup_name
+);
+
+static const char *
+is_applicable_addr (
+	result_map_t * result,
+	const void * addr,
+	int af,
+	char * addr_str
+);
+
+
+// Error code functions
+
+static nss_status
+set_err (result_map_t * result, nss_status status, int err, int herr);
+
+static nss_status set_err_notfound (result_map_t * result);
+static nss_status set_err_bad_hostname (result_map_t * result);
+static nss_status set_err_buf_too_small (result_map_t * result);
+static nss_status set_err_internal_resource_full (result_map_t * result);
+static nss_status set_err_system (result_map_t * result);
+static nss_status set_err_mdns_failed (result_map_t * result);
+static nss_status set_err_success (result_map_t * result);
+
+
+//----------
+// Global variables
+
+
+//----------
+// NSS functions
+
+nss_status
+_nss_mdns_gethostbyname_r (
+	const char *name,
+	hostent * result_buf,
+	char *buf,
+	size_t buflen,
+	int *errnop,
+	int *h_errnop
+)
+{
+	if (MDNS_VERBOSE)
+		syslog (LOG_DEBUG,
+			"mdns: Called nss_mdns_gethostbyname with %s",
+			name
+		);
+
+	return
+		mdns_gethostbyname2 (
+			name, AF_INET, result_buf, buf, buflen, errnop, h_errnop
+		);
+}
+
+
+nss_status
+_nss_mdns_gethostbyname2_r (
+	const char *name,
+	int af,
+	hostent * result_buf,
+	char *buf,
+	size_t buflen,
+	int *errnop,
+	int *h_errnop
+)
+{
+	if (MDNS_VERBOSE)
+		syslog (LOG_DEBUG,
+			"mdns: Called nss_mdns_gethostbyname2 with %s",
+			name
+		);
+
+	return
+		mdns_gethostbyname2 (
+			name, af, result_buf, buf, buflen, errnop, h_errnop
+		);
+}
+
+
+nss_status
+_nss_mdns_gethostbyaddr_r (
+	const void *addr,
+	socklen_t len,
+	int af,
+	hostent * result_buf,
+	char *buf,
+	size_t buflen,
+	int *errnop,
+	int *h_errnop
+)
+{
+	char addr_str [NI_MAXHOST + 1];
+	result_map_t result;
+	int err_status;
+	
+	if (inet_ntop (af, addr, addr_str, NI_MAXHOST) == NULL)
+	{
+		const char * family = af_to_str (af);
+		if (family == NULL)
+		{
+			family = "Unknown";
+		}
+
+		syslog (LOG_WARNING,
+			"mdns: Couldn't covert address, family %d (%s) in nss_mdns_gethostbyaddr: %s",
+			af,
+			family,
+			strerror (errno)
+		);
+
+		// This address family never applicable to us, so return NOT_FOUND
+
+		*errnop = ENOENT;
+		*h_errnop = HOST_NOT_FOUND;
+		return NSS_STATUS_NOTFOUND;
+	}
+	if (MDNS_VERBOSE)
+	{
+		syslog (LOG_DEBUG,
+			"mdns: Called nss_mdns_gethostbyaddr with %s",
+			addr_str
+		);
+	}
+
+	// Initialise result
+	err_status = init_result (&result, result_buf, buf, buflen);
+	if (err_status)
+	{
+		*errnop = err_status;
+		*h_errnop = NETDB_INTERNAL;
+		return NSS_STATUS_TRYAGAIN;
+	}
+		
+	if (is_applicable_addr (&result, addr, af, addr_str))
+	{
+		nss_status rv;
+
+		rv = mdns_lookup_addr (addr, len, af, addr_str, &result);
+		if (rv == NSS_STATUS_SUCCESS)
+		{
+			return rv;
+		}
+	}
+
+	// Return current error status (defaults to NOT_FOUND)
+	
+	*errnop = result.r_errno;
+	*h_errnop = result.r_h_errno;
+	return result.status;
+}
+
+
+//----------
+// Local functions
+
+nss_status
+mdns_gethostbyname2 (
+	const char *name,
+	int af,
+	hostent * result_buf,
+	char *buf,
+	size_t buflen,
+	int *errnop,
+	int *h_errnop
+)
+{
+	char lookup_name [k_hostname_maxlen + 1];
+	result_map_t result;
+	int err_status;
+	
+	// Initialise result
+	err_status = init_result (&result, result_buf, buf, buflen);
+	if (err_status)
+	{
+		*errnop = err_status;
+		*h_errnop = NETDB_INTERNAL;
+		return NSS_STATUS_TRYAGAIN;
+	}
+		
+	if (is_applicable_name (&result, name, lookup_name))
+	{
+		// Try using mdns
+		nss_status rv;
+
+		if (MDNS_VERBOSE)
+			syslog (LOG_DEBUG,
+				"mdns: Local name: %s",
+				name
+			);
+
+		rv = mdns_lookup_name (name, af, &result);
+		if (rv == NSS_STATUS_SUCCESS)
+		{
+			return rv;
+		}
+	}
+
+	// Return current error status (defaults to NOT_FOUND)
+	
+	*errnop = result.r_errno;
+	*h_errnop = result.r_h_errno;
+	return result.status;
+}
+
+
+/*
+	Lookup a fully qualified hostname using the default record type
+	for the specified address family.
+	
+	Parameters
+		fullname
+			Fully qualified hostname.  If not fully qualified the code will
+			still 'work', but the lookup is unlikely to succeed.
+		af
+			Either AF_INET or AF_INET6.  Other families are not supported.
+		result
+			Initialised 'result' data structure.
+ */
+static nss_status
+mdns_lookup_name (
+	const char * fullname,
+	int af,
+	result_map_t * result
+)
+{
+	// Lookup using mDNS.
+	DNSServiceErrorType errcode;
+	DNSServiceRef sdref;
+	ns_type_t rrtype;
+	
+	if (MDNS_VERBOSE)
+		syslog (LOG_DEBUG,
+			"mdns: Attempting lookup of %s",
+			fullname
+		);
+	
+	switch (af)
+	{
+	  case AF_INET:
+		rrtype = T_A;
+		result->hostent->h_length = 4;
+			// Length of an A record
+		break;
+	
+	  case AF_INET6:
+		rrtype = T_AAAA;
+		result->hostent->h_length = 16;
+			// Length of an AAAA record
+		break;
+	
+	  default:
+		syslog (LOG_WARNING,
+			"mdns: Unsupported address family %d",
+			af
+		);
+		return set_err_bad_hostname (result);
+	}
+	result->hostent->h_addrtype = af;
+	
+	errcode =
+		DNSServiceQueryRecord (
+			&sdref,
+			0,		// reserved flags field
+			k_mdnsd_intfs_local,	// all local interfaces
+			fullname,	// full name to query for
+			rrtype,		// resource record type
+			C_IN,	// internet class records
+			mdns_lookup_callback,	// callback
+			result		// Context - result buffer
+		);
+	
+	if (errcode)
+	{
+		syslog (LOG_WARNING,
+			"mdns: Failed to initialise lookup, error %d",
+			errcode
+		);
+		return set_err_mdns_failed (result);
+	}
+
+	return handle_events (sdref, result, fullname);
+}
+
+
+/*
+	Reverse (PTR) lookup for the specified address.
+	
+	Parameters
+		addr
+			Either a struct in_addr or a struct in6_addr
+		addr_len
+			size of the address
+		af
+			Either AF_INET or AF_INET6.  Other families are not supported.
+			Must match addr
+		addr_str
+			Address in format suitable for PTR lookup.
+			AF_INET: a.b.c.d -> d.c.b.a.in-addr.arpa
+			AF_INET6: reverse nibble format, x.x.x...x.ip6.arpa
+		result
+			Initialised 'result' data structure.
+ */
+static nss_status
+mdns_lookup_addr (
+	const void * addr,
+	socklen_t addr_len,
+	int af,
+	const char * addr_str,
+	result_map_t * result
+)
+{
+	DNSServiceErrorType errcode;
+	DNSServiceRef sdref;
+	
+	if (MDNS_VERBOSE)
+		syslog (LOG_DEBUG,
+			"mdns: Attempting lookup of %s",
+			addr_str
+		);
+		
+	result->hostent->h_addrtype = af;
+	result->hostent->h_length = addr_len;
+
+	// Query address becomes "address" in result.
+	if (! add_address_to_buffer (result, addr, addr_len))
+	{
+		return result->status;
+	}
+	
+	result->hostent->h_name [0] = 0;
+	
+	errcode =
+		DNSServiceQueryRecord (
+			&sdref,
+			0,		// reserved flags field
+			k_mdnsd_intfs_local,	// all local interfaces
+			addr_str,	// address string to query for
+			T_PTR,	// pointer RRs
+			C_IN,	// internet class records
+			mdns_lookup_callback,	// callback
+			result		// Context - result buffer
+		);
+	
+	if (errcode)
+	{
+		syslog (LOG_WARNING,
+			"mdns: Failed to initialise mdns lookup, error %d",
+			errcode
+		);
+		return set_err_mdns_failed (result);
+	}
+
+	return handle_events (sdref, result, addr_str);
+}
+
+
+/*
+	Wait on result of callback, and process it when it arrives.
+	
+	Parameters
+		sdref
+			dns-sd reference
+		result
+			Initialised 'result' data structure.
+		str
+			lookup string, used for status/error reporting.
+ */
+static nss_status
+handle_events (DNSServiceRef sdref, result_map_t * result, const char * str)
+{
+	int dns_sd_fd = DNSServiceRefSockFD(sdref);
+	int nfds = dns_sd_fd + 1;
+	fd_set readfds;
+	struct timeval tv;
+	int select_result;
+
+	while (! result->done)
+	{
+		FD_ZERO(&readfds);
+		FD_SET(dns_sd_fd, &readfds);
+
+		tv = k_select_time;
+		
+		select_result =
+			select (nfds, &readfds, (fd_set*)NULL, (fd_set*)NULL, &tv);
+		if (select_result > 0)
+		{
+			if (FD_ISSET(dns_sd_fd, &readfds))
+			{
+				if (MDNS_VERBOSE)
+					syslog (LOG_DEBUG,
+						"mdns: Reply received for %s",
+						str
+					);
+				DNSServiceProcessResult(sdref);
+			}
+			else
+			{
+				syslog (LOG_WARNING,
+					"mdns: Unexpected return from select on lookup of %s",
+					str
+				);
+			}
+		}
+		else
+		{
+			// Terminate loop due to timer expiry
+			if (MDNS_VERBOSE)
+				syslog (LOG_DEBUG,
+					"mdns: %s not found - timer expired",
+					str
+				);
+			set_err_notfound (result);
+			break;
+		}
+	}
+	
+	return result->status;
+}
+
+
+/*
+	Examine incoming data and add to relevant fields in result structure.
+	This routine is called from DNSServiceProcessResult where appropriate.
+ */
+void
+mdns_lookup_callback
+(
+	DNSServiceRef		sdref,
+	DNSServiceFlags		flags,
+	uint32_t			interface_index,
+	DNSServiceErrorType	error_code,
+	const char			*fullname,	  
+	uint16_t			rrtype,
+	uint16_t			rrclass,
+	uint16_t			rdlen,
+	const void			*rdata,
+	uint32_t			ttl,
+	void				*context
+)
+{
+	// A single record is received
+
+	result_map_t * result = (result_map_t *) context;
+
+	(void)sdref; // Unused
+	(void)interface_index; // Unused
+	(void)ttl; // Unused
+	
+	if (! (flags & kDNSServiceFlagsMoreComing) )
+	{
+		result->done = 1;
+	}
+
+	if (error_code == kDNSServiceErr_NoError)
+	{
+		ns_type_t expected_rr_type =
+			af_to_rr (result->hostent->h_addrtype);
+
+		// Idiot check class
+		if (rrclass != C_IN)
+		{
+			syslog (LOG_WARNING,
+				"mdns: Received bad RR class: expected %d (%s),"
+				" got %d (%s), RR type %d (%s)",
+				C_IN,
+				ns_class_to_str (C_IN),
+				rrclass,
+				ns_class_to_str (rrclass),
+				rrtype,
+				ns_type_to_str (rrtype)
+			);
+			return;
+		}
+		
+		// If a PTR
+		if (rrtype == T_PTR)
+		{
+			if (callback_body_ptr (fullname, result, rdlen, rdata) < 0)
+				return;
+		}
+		else if (rrtype == expected_rr_type)
+		{
+			if (!
+				add_hostname_or_alias (
+					result,
+					fullname,
+					strlen (fullname)
+				)
+			)
+			{
+				result->done = 1;
+				return;
+					// Abort on error
+			}
+
+			if (! add_address_to_buffer (result, rdata, rdlen) )
+			{
+				result->done = 1;
+				return;
+					// Abort on error
+			}
+		}
+		else
+		{
+			syslog (LOG_WARNING,
+				"mdns: Received bad RR type: expected %d (%s),"
+				" got %d (%s)",
+				expected_rr_type,
+				ns_type_to_str (expected_rr_type),
+				rrtype,
+				ns_type_to_str (rrtype)
+			);
+			return;
+		}
+		
+		if (result->status != NSS_STATUS_SUCCESS)
+			set_err_success (result);
+	}
+	else
+	{
+		// For now, dump message to syslog and continue
+		syslog (LOG_WARNING,
+			"mdns: callback returned error %d",
+			error_code
+		);
+	}
+}
+
+static int
+callback_body_ptr (
+	const char * fullname,
+	result_map_t * result,
+	int rdlen,
+	const void * rdata
+)
+{
+	char result_name [k_hostname_maxlen + 1];
+	int rv;
+	
+	// Fullname should be .in-addr.arpa or equivalent, which we're
+	// not interested in.  Ignore it.
+	
+	rv = dns_rdata_to_name (rdata, rdlen, result_name, k_hostname_maxlen);
+	if (rv < 0)
+	{
+		const char * errmsg;
+		
+		switch (rv)
+		{
+		  case DNS_RDATA_TO_NAME_BAD_FORMAT:
+			errmsg = "mdns: PTR '%s' result badly formatted ('%s...')";
+			break;
+		
+		  case DNS_RDATA_TO_NAME_TOO_LONG:
+			errmsg = "mdns: PTR '%s' result too long ('%s...')";
+			break;
+		
+		  case DNS_RDATA_TO_NAME_PTR:
+			errmsg = "mdns: PTR '%s' result contained pointer ('%s...')";
+			break;
+		
+		  default:
+			errmsg = "mdns: PTR '%s' result conversion failed ('%s...')";
+		}
+
+		syslog (LOG_WARNING,
+			errmsg,
+			fullname,
+			result_name
+		);
+		
+		return -1;
+	}
+	
+	if (MDNS_VERBOSE)
+	{
+		syslog (LOG_DEBUG,
+			"mdns: PTR '%s' resolved to '%s'",
+			fullname,
+			result_name
+		);
+	}
+	
+	// Data should be a hostname
+	if (!
+		add_hostname_or_alias (
+			result,
+			result_name,
+			rv
+		)
+	)
+	{
+		result->done = 1;
+		return -1;
+	}
+	
+	return 0;
+}
+
+
+/*
+	Add an address to the buffer.
+	
+	Parameter
+		result
+			Result structure to write to
+		data
+			Incoming address data buffer
+			Must be 'int' aligned
+		len
+			Length of data buffer (in bytes)
+			Must match data alignment
+	
+	Result
+		Pointer to start of newly written data,
+		or NULL on error.
+		If address already exists in buffer, returns pointer to that instead.
+ */
+static void *
+add_address_to_buffer (result_map_t * result, const void * data, int len)
+{
+	int new_addr;
+	void * start;
+	void * temp;
+	
+	if ((temp = contains_address (result, data, len)))
+	{
+		return temp;
+	}
+	
+	if (result->addrs_count >= k_addrs_max)
+	{
+		// Not enough addr slots
+		set_err_internal_resource_full (result);
+		syslog (LOG_ERR,
+			"mdns: Internal address buffer full; increase size"
+		);
+		return NULL;
+	}
+	
+	// Idiot check
+	if (len != result->hostent->h_length)
+	{
+		syslog (LOG_WARNING,
+			"mdns: Unexpected rdata length for address.  Expected %d, got %d",
+			result->hostent->h_length,
+			len
+		);
+		// XXX And continue for now.
+	}
+
+	new_addr = result->addr_idx + len;
+	
+	if (new_addr > result->alias_idx)
+	{
+		// Not enough room
+		set_err_buf_too_small (result);
+		if (MDNS_VERBOSE)
+			syslog (LOG_DEBUG,
+				"mdns: Ran out of buffer when adding address %d",
+				result->addrs_count + 1
+			);
+		return NULL;
+	}
+
+	start = result->buffer + result->addr_idx;
+	memcpy (start, data, len);
+	result->addr_idx = new_addr;
+	result->header->addrs [result->addrs_count] = start;
+	result->addrs_count ++;
+	result->header->addrs [result->addrs_count] = NULL;
+
+	return start;
+}
+
+
+static void *
+contains_address (result_map_t * result, const void * data, int len)
+{
+	int i;
+	
+	// Idiot check
+	if (len != result->hostent->h_length)
+	{
+		syslog (LOG_WARNING,
+			"mdns: Unexpected rdata length for address.  Expected %d, got %d",
+			result->hostent->h_length,
+			len
+		);
+		// XXX And continue for now.
+	}
+
+	for (i = 0; result->header->addrs [i]; i++)
+	{
+		if (memcmp (result->header->addrs [i], data, len) == 0)
+		{
+			return result->header->addrs [i];
+		}
+	}
+	
+	return NULL;
+}
+
+
+/*
+	Add an alias to the buffer.
+	
+	Parameter
+		result
+			Result structure to write to
+		data
+			Incoming alias (null terminated)
+		len
+			Length of data buffer (in bytes), including trailing null
+	
+	Result
+		Pointer to start of newly written data,
+		or NULL on error
+		If alias already exists in buffer, returns pointer to that instead.
+ */
+static char *
+add_alias_to_buffer (result_map_t * result, const char * data, int len)
+{
+	int new_alias;
+	char * start;
+	char * temp;
+	
+	if ((temp = contains_alias (result, data)))
+	{
+		return temp;
+	}
+	
+	if (result->aliases_count >= k_aliases_max)
+	{
+		// Not enough alias slots
+		set_err_internal_resource_full (result);
+		syslog (LOG_ERR,
+			"mdns: Internal alias buffer full; increase size"
+		);
+		return NULL;
+	}
+
+	new_alias = result->alias_idx - len;
+	
+	if (new_alias < result->addr_idx)
+	{
+		// Not enough room
+		set_err_buf_too_small (result);
+		if (MDNS_VERBOSE)
+			syslog (LOG_DEBUG,
+				"mdns: Ran out of buffer when adding alias %d",
+				result->aliases_count + 1
+			);
+		return NULL;
+	}
+
+	start = result->buffer + new_alias;
+	memcpy (start, data, len);
+	result->alias_idx = new_alias;
+	result->header->aliases [result->aliases_count] = start;
+	result->aliases_count ++;
+	result->header->aliases [result->aliases_count] = NULL;
+
+	return start;
+}
+
+
+static char *
+contains_alias (result_map_t * result, const char * alias)
+{
+	int i;
+	
+	for (i = 0; result->header->aliases [i]; i++)
+	{
+		if (strcmp (result->header->aliases [i], alias) == 0)
+		{
+			return result->header->aliases [i];
+		}
+	}
+	
+	return NULL;
+}
+
+
+/*
+	Add fully qualified hostname to result.
+	
+	Parameter
+		result
+			Result structure to write to
+		fullname
+			Fully qualified hostname
+	
+	Result
+		Pointer to start of hostname buffer,
+		or NULL on error (usually hostname too long)
+ */
+
+static char *
+add_hostname_len (result_map_t * result, const char * fullname, int len)
+{
+	if (len >= k_hostname_maxlen)
+	{
+		set_err_bad_hostname (result);
+		syslog (LOG_WARNING,
+			"mdns: Hostname too long '%.*s': len %d, max %d",
+			len,
+			fullname,
+			len,
+			k_hostname_maxlen
+		);
+		return NULL;
+	}
+	
+	result->hostent->h_name =
+		strcpy (result->header->hostname, fullname);
+	
+	return result->header->hostname;
+}
+
+
+/*
+	Add fully qualified name as hostname or alias.
+	
+	If hostname is not fully qualified this is not an error, but the data
+	returned may be not what the application wanted.
+
+	Parameter
+		result
+			Result structure to write to
+		data
+			Incoming alias (null terminated)
+		len
+			Length of data buffer (in bytes), including trailing null
+	
+	Result
+		Pointer to start of newly written data,
+		or NULL on error
+		If alias or hostname already exists, returns pointer to that instead.
+ */
+static char *
+add_hostname_or_alias (result_map_t * result, const char * data, int len)
+{
+	char * hostname = result->hostent->h_name;
+
+	if (*hostname)
+	{
+		if (strcmp (hostname, data) == 0)
+		{
+			return hostname;
+		}
+		else
+		{
+			return add_alias_to_buffer (result, data, len);
+		}
+	}
+	else
+	{
+		return add_hostname_len (result, data, len);
+	}
+}
+
+
+static int
+init_result (
+	result_map_t * result,
+	hostent * result_buf,
+	char * buf,
+	size_t buflen
+)
+{
+	if (buflen < sizeof (buf_header_t))
+	{
+		return ERANGE;
+	}
+
+	result->hostent = result_buf;
+	result->header = (buf_header_t *) buf;
+	result->header->hostname[0] = 0;
+	result->aliases_count = 0;
+	result->header->aliases[0] = NULL;
+	result->addrs_count = 0;
+	result->header->addrs[0] = NULL;
+	result->buffer = buf + sizeof (buf_header_t);
+	result->addr_idx = 0;
+	result->alias_idx = buflen - sizeof (buf_header_t);
+	result->done = 0;
+	set_err_notfound (result);
+
+	// Point hostent to the right buffers
+	result->hostent->h_name = result->header->hostname;
+	result->hostent->h_aliases = result->header->aliases;
+	result->hostent->h_addr_list = result->header->addrs;
+	
+	return 0;
+}
+
+/*
+	Set the status in the result.
+	
+	Parameters
+		result
+			Result structure to update
+		status
+			New nss_status value
+		err
+			New errno value
+		herr
+			New h_errno value
+	
+	Returns
+		New status value
+ */
+static nss_status
+set_err (result_map_t * result, nss_status status, int err, int herr)
+{
+	result->status = status;
+	result->r_errno = err;
+	result->r_h_errno = herr;
+	
+	return status;
+}
+
+static nss_status
+set_err_notfound (result_map_t * result)
+{
+	return set_err (result, NSS_STATUS_NOTFOUND, ENOENT, HOST_NOT_FOUND);
+}
+
+static nss_status
+set_err_bad_hostname (result_map_t * result)
+{
+	return set_err (result, NSS_STATUS_TRYAGAIN, ENOENT, NO_RECOVERY);
+}
+
+static nss_status
+set_err_buf_too_small (result_map_t * result)
+{
+	return set_err (result, NSS_STATUS_TRYAGAIN, ERANGE, NETDB_INTERNAL);
+}
+
+static nss_status
+set_err_internal_resource_full (result_map_t * result)
+{
+	return set_err (result, NSS_STATUS_RETURN, ERANGE, NO_RECOVERY);
+}
+
+static nss_status
+set_err_system (result_map_t * result)
+{
+	return set_err (result, NSS_STATUS_UNAVAIL, errno, NETDB_INTERNAL);
+}
+
+static nss_status
+set_err_mdns_failed (result_map_t * result)
+{
+	return set_err (result, NSS_STATUS_TRYAGAIN, EAGAIN, TRY_AGAIN);
+}
+
+static nss_status
+set_err_success (result_map_t * result)
+{
+	result->status = NSS_STATUS_SUCCESS;
+	return result->status;
+}
+
+
+/*
+	Test whether name is applicable for mdns to process, and if so copy into
+	lookup_name buffer (if non-NULL).
+	
+	Returns
+		Pointer to name to lookup up, if applicable, or NULL otherwise.
+ */
+static const char *
+is_applicable_name (
+	result_map_t * result,
+	const char * name,
+	char * lookup_name
+)
+{
+	int match = config_is_mdns_suffix (name);
+	if (match > 0)
+	{
+		if (lookup_name)
+		{
+			strncpy (lookup_name, name, k_hostname_maxlen + 1);
+			return lookup_name;
+		}
+		else
+		{
+			return name;
+		}
+	}
+	else
+	{
+		if (match < 0)
+		{
+			set_err_system (result);
+		}
+		return NULL;
+	}
+}
+
+/*
+	Test whether address is applicable for mdns to process, and if so copy into
+	addr_str buffer as an address suitable for ptr lookup.
+	
+	Returns
+		Pointer to name to lookup up, if applicable, or NULL otherwise.
+ */
+static const char *
+is_applicable_addr (
+	result_map_t * result,
+	const void * addr,
+	int af,
+	char * addr_str
+)
+{
+	int match;
+	
+	if (! format_reverse_addr (af, addr, -1, addr_str))
+	{
+		if (MDNS_VERBOSE)
+			syslog (LOG_DEBUG,
+				"mdns: Failed to create reverse address"
+			);
+		return NULL;
+	}
+
+	if (MDNS_VERBOSE)
+		syslog (LOG_DEBUG,
+			"mdns: Reverse address: %s",
+			addr_str
+		);
+
+	match = config_is_mdns_suffix (addr_str);
+	if (match > 0)
+	{
+		return addr_str;
+	}
+	else
+	{
+		if (match < 0)
+		{
+			set_err_system (result);
+		}
+		return NULL;
+	}
+}
+
+//----------
+// Types and Constants
+
+const char * k_conf_file = "/etc/nss_mdns.conf";
+#define CONF_LINE_SIZE 1024
+
+const char k_comment_char = '#';
+
+const char * k_keyword_domain = "domain";
+
+const char * k_default_domains [] =
+	{
+		"local",
+		"254.169.in-addr.arpa",
+		"0.8.e.f.ip6.int",
+		"0.8.e.f.ip6.arpa",
+		NULL
+			// Always null terminated
+	};
+
+// Linked list of domains
+typedef struct domain_entry
+{
+	char * domain;
+	struct domain_entry * next;
+} domain_entry_t;
+
+
+// Config
+typedef struct
+{
+	domain_entry_t * domains;
+} config_t;
+
+const config_t k_empty_config =
+	{
+		NULL
+	};
+
+
+// Context - tracks position in config file, used for error reporting
+typedef struct
+{
+	const char * filename;
+	int linenum;
+} config_file_context_t;
+
+
+//----------
+// Local prototypes
+
+static errcode_t
+load_config (config_t * conf);
+
+static errcode_t
+process_config_line (
+	config_t * conf,
+	char * line,
+	config_file_context_t * context
+);
+
+static char *
+get_next_word (char * input, char **next);
+
+static errcode_t
+default_config (config_t * conf);
+
+static errcode_t
+add_domain (config_t * conf, const char * domain);
+
+static int
+contains_domain (const config_t * conf, const char * domain);
+
+static int
+contains_domain_suffix (const config_t * conf, const char * addr);
+
+
+//----------
+// Global variables
+
+static config_t * g_config = NULL;
+	// Configuration info
+
+pthread_mutex_t g_config_mutex =
+#ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
+	PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;
+#else
+	PTHREAD_MUTEX_INITIALIZER;
+#endif
+
+
+//----------
+// Configuration functions
+
+
+/*
+	Initialise the configuration from the config file.
+	
+	Returns
+		0 success
+		non-zero error code on failure
+ */
+errcode_t
+init_config ()
+{
+	if (g_config)
+	{
+		/*
+			Safe to test outside mutex.
+			If non-zero, initialisation is complete and g_config can be
+			safely used read-only.  If zero, then we do proper mutex
+			testing before initialisation.
+		 */
+		return 0;
+	}
+	else
+	{
+		int errcode = -1;
+		int presult;
+		config_t * temp_config;
+		
+		// Acquire mutex
+		presult = pthread_mutex_lock (&g_config_mutex);
+		if (presult)
+		{
+			syslog (LOG_ERR,
+				"mdns: Fatal mutex lock error in nss_mdns:init_config, %s:%d: %d: %s",
+				__FILE__, __LINE__, presult, strerror (presult)
+			);
+			return presult;
+		}
+		
+		// Test again now we have mutex, in case initialisation occurred while
+		// we were waiting
+		if (! g_config)
+		{
+			temp_config = (config_t *) malloc (sizeof (config_t));
+			if (temp_config)
+			{
+				// NOTE: This code will leak memory if initialisation fails
+				// repeatedly.  This should only happen in the case of a memory
+				// error, so I'm not sure if it's a meaningful problem. - AW
+				*temp_config = k_empty_config;
+				errcode = load_config (temp_config);
+	
+				if (! errcode)
+				{
+					g_config = temp_config;
+				}
+			}
+			else
+			{
+				syslog (LOG_ERR,
+					"mdns: Can't allocate memory in nss_mdns:init_config, %s:%d",
+					__FILE__, __LINE__
+				);
+				errcode = errno;
+			}
+		}
+		
+		presult = pthread_mutex_unlock (&g_config_mutex);
+		if (presult)
+		{
+			syslog (LOG_ERR,
+				"mdns: Fatal mutex unlock error in nss_mdns:init_config, %s:%d: %d: %s",
+				__FILE__, __LINE__, presult, strerror (presult)
+			);
+			errcode = presult;
+		}
+
+		return errcode;
+	}
+}
+
+
+int
+config_is_mdns_suffix (const char * name)
+{
+	int errcode = init_config ();
+	if (! errcode)
+	{
+		return contains_domain_suffix (g_config, name);
+	}
+	else
+	{
+		errno = errcode;
+		return -1;
+	}
+}
+
+
+//----------
+// Local functions
+
+static errcode_t
+load_config (config_t * conf)
+{
+	FILE * cf;
+	char line [CONF_LINE_SIZE];
+	config_file_context_t context;
+
+	context.filename = k_conf_file;
+	context.linenum = 0;
+	
+	
+	cf = fopen (context.filename, "r");
+	if (! cf)
+	{
+		syslog (LOG_INFO,
+			"mdns: Couldn't open nss_mdns configuration file %s, using default.",
+			context.filename
+		);
+		return default_config (conf);
+	}
+	
+	while (fgets (line, CONF_LINE_SIZE, cf))
+	{
+		int errcode;
+		context.linenum++;
+		errcode = process_config_line (conf, line, &context);
+		if (errcode)
+		{
+			// Critical error, give up
+			return errcode;
+		}
+	}
+	
+	return 0;
+}
+
+
+/*
+	Parse a line of the configuration file.
+	For each keyword recognised, perform appropriate handling.
+	If the keyword is not recognised, print a message to syslog
+	and continue.
+	
+	Returns
+		0 success, or recoverable config file error
+		non-zero serious system error, processing aborted
+ */
+static errcode_t
+process_config_line (
+	config_t * conf,
+	char * line,
+	config_file_context_t * context
+)
+{
+	char * curr = line;
+	char * word;
+	
+	word = get_next_word (curr, &curr);
+	if (! word || word [0] == k_comment_char)
+	{
+		// Nothing interesting on this line
+		return 0;
+	}
+	
+	if (strcmp (word, k_keyword_domain) == 0)
+	{
+		word = get_next_word (curr, &curr);
+		if (word)
+		{
+			int errcode = add_domain (conf, word);
+			if (errcode)
+			{
+				// something badly wrong, bail
+				return errcode;
+			}
+			
+			if (get_next_word (curr, NULL))
+			{
+				syslog (LOG_WARNING,
+					"%s, line %d: ignored extra text found after domain",
+					context->filename,
+					context->linenum
+				);
+			}
+		}
+		else
+		{
+			syslog (LOG_WARNING,
+				"%s, line %d: no domain specified",
+				context->filename,
+				context->linenum
+			);
+		}
+	}
+	else
+	{
+		syslog (LOG_WARNING,
+			"%s, line %d: unknown keyword %s - skipping",
+			context->filename,
+			context->linenum,
+			word
+		);
+	}
+	
+	return 0;
+}
+
+
+/*
+	Get next word (whitespace separated) from input string.
+	A null character is written into the first whitespace character following
+	the word.
+	
+	Parameters
+		input
+			Input string.  This string is modified by get_next_word.
+		next
+			If non-NULL and the result is non-NULL, a pointer to the
+			character following the end of the word (after the null)
+			is written to 'next'.
+			If no word is found, the original value is unchanged.
+			If the word extended to the end of the string, 'next' points
+			to the trailling NULL.
+			It is safe to pass 'str' as 'input' and '&str' as 'next'.
+	Returns
+		Pointer to the first non-whitespace character (and thus word) found.
+		if no word is found, returns NULL.
+ */
+static char *
+get_next_word (char * input, char **next)
+{
+	char * curr = input;
+	char * result;
+	
+	while (isspace (*curr))
+	{
+		curr ++;
+	}
+	
+	if (*curr == 0)
+	{
+		return NULL;
+	}
+	
+	result = curr;
+	while (*curr && ! isspace (*curr))
+	{
+		curr++;
+	}
+	if (*curr)
+	{
+		*curr = 0;
+		if (next)
+		{
+			*next = curr+1;
+		}
+	}
+	else
+	{
+		if (next)
+		{
+			*next = curr;
+		}
+	}
+	
+	return result;
+}
+
+
+static errcode_t
+default_config (config_t * conf)
+{
+	int i;
+	for (i = 0; k_default_domains [i]; i++)
+	{
+		int errcode =
+			add_domain (conf, k_default_domains [i]);
+		if (errcode)
+		{
+			// Something has gone (badly) wrong - let's bail
+			return errcode;
+		}
+	}
+	
+	return 0;
+}
+
+
+static errcode_t
+add_domain (config_t * conf, const char * domain)
+{
+	if (! contains_domain (conf, domain))
+	{
+		domain_entry_t * d =
+			(domain_entry_t *) malloc (sizeof (domain_entry_t));
+		if (! d)
+		{
+			syslog (LOG_ERR,
+				"mdns: Can't allocate memory in nss_mdns:init_config, %s:%d",
+				__FILE__, __LINE__
+			);
+			return ENOMEM;
+		}
+
+		d->domain = strdup (domain);
+		if (! d->domain)
+		{
+			syslog (LOG_ERR,
+				"mdns: Can't allocate memory in nss_mdns:init_config, %s:%d",
+				__FILE__, __LINE__
+			);
+			free (d);
+			return ENOMEM;
+		}
+		d->next = conf->domains;
+		conf->domains = d;
+	}
+	
+	return 0;
+}
+
+
+static int
+contains_domain (const config_t * conf, const char * domain)
+{
+	const domain_entry_t * curr = conf->domains;
+	
+	while (curr != NULL)
+	{
+		if (strcasecmp (curr->domain, domain) == 0)
+		{
+			return 1;
+		}
+		
+		curr = curr->next;
+	}
+	
+	return 0;
+}
+
+
+static int
+contains_domain_suffix (const config_t * conf, const char * addr)
+{
+	const domain_entry_t * curr = conf->domains;
+	
+	while (curr != NULL)
+	{
+		if (cmp_dns_suffix (addr, curr->domain) > 0)
+		{
+			return 1;
+		}
+		
+		curr = curr->next;
+	}
+	
+	return 0;
+}
+
+//----------
+// Types and Constants
+
+static const char * k_local_suffix = "local";
+static const char k_dns_separator = '.';
+
+static const int k_label_maxlen = DNS_LABEL_MAXLEN;
+	// Label entries longer than this are actually pointers.
+
+typedef struct
+{
+	int value;
+	const char * name;
+	const char * comment;
+} table_entry_t;
+
+static const table_entry_t k_table_af [] =
+	{
+		{ AF_UNSPEC, NULL, NULL },
+		{ AF_LOCAL, "LOCAL", NULL },
+		{ AF_UNIX, "UNIX", NULL },
+		{ AF_INET, "INET", NULL },
+		{ AF_INET6, "INET6", NULL }
+	};
+static const int k_table_af_size =
+	sizeof (k_table_af) / sizeof (* k_table_af);
+
+static const char * k_table_ns_class [] =
+	{
+		NULL,
+		"IN"
+	};
+static const int k_table_ns_class_size =
+	sizeof (k_table_ns_class) / sizeof (* k_table_ns_class);
+
+static const char * k_table_ns_type [] =
+	{
+		NULL,
+		"A",
+		"NS",
+		"MD",
+		"MF",
+		"CNAME",
+		"SOA",
+		"MB",
+		"MG",
+		"MR",
+		"NULL",
+		"WKS",
+		"PTR",
+		"HINFO",
+		"MINFO",
+		"MX",
+		"TXT",
+		"RP",
+		"AFSDB",
+		"X25",
+		"ISDN",
+		"RT",
+		"NSAP",
+		NULL,
+		"SIG",
+		"KEY",
+		"PX",
+		"GPOS",
+		"AAAA",
+		"LOC",
+		"NXT",
+		"EID",
+		"NIMLOC",
+		"SRV",
+		"ATMA",
+		"NAPTR",
+		"KX",
+		"CERT",
+		"A6",
+		"DNAME",
+		"SINK",
+		"OPT"
+	};
+static const int k_table_ns_type_size =
+	sizeof (k_table_ns_type) / sizeof (* k_table_ns_type);
+
+
+//----------
+// Local prototypes
+
+static int
+simple_table_index (const char * table [], int size, const char * str);
+
+static int
+table_index_name (const table_entry_t table [], int size, const char * str);
+
+static int
+table_index_value (const table_entry_t table [], int size, int n);
+
+
+//----------
+// Global variables
+
+
+//----------
+// Util functions
+
+int
+count_dots (const char * name)
+{
+	int count = 0;
+	int i;
+	for (i = 0; name[i]; i++)
+	{
+		if (name [i] == k_dns_separator)
+			count++;
+	}
+	
+	return count;
+}
+
+
+int
+islocal (const char * name)
+{
+	return cmp_dns_suffix (name, k_local_suffix) > 0;
+}
+
+
+int
+rr_to_af (ns_type_t rrtype)
+{
+	switch (rrtype)
+	{
+	  case T_A:
+		return AF_INET;
+	
+	  case T_AAAA:
+		return AF_INET6;
+	
+	  default:
+		return AF_UNSPEC;
+	}
+}
+
+
+ns_type_t
+af_to_rr (int af)
+{
+	switch (af)
+	{
+	  case AF_INET:
+		return T_A;
+	
+	  case AF_INET6:
+		return T_AAAA;
+	
+	  default:
+		//return ns_t_invalid;
+		return 0;
+	}
+}
+
+
+int
+str_to_af (const char * str)
+{
+	int result =
+		table_index_name (k_table_af, k_table_af_size, str);
+	if (result < 0)
+		result = 0;
+
+	return k_table_af [result].value;
+}
+
+
+ns_class_t
+str_to_ns_class (const char * str)
+{
+	return (ns_class_t)
+		simple_table_index (k_table_ns_class, k_table_ns_class_size, str);
+}
+
+
+ns_type_t
+str_to_ns_type (const char * str)
+{
+	return (ns_type_t)
+		simple_table_index (k_table_ns_type, k_table_ns_type_size, str);
+}
+
+
+const char *
+af_to_str (int in)
+{
+	int result =
+		table_index_value (k_table_af, k_table_af_size, in);
+	if (result < 0)
+		result = 0;
+
+	return k_table_af [result].name;
+}
+
+
+const char *
+ns_class_to_str (ns_class_t in)
+{
+	if (in < k_table_ns_class_size)
+		return k_table_ns_class [in];
+	else
+		return NULL;
+}
+
+
+const char *
+ns_type_to_str (ns_type_t in)
+{
+	if (in < k_table_ns_type_size)
+		return k_table_ns_type [in];
+	else
+		return NULL;
+}
+
+
+char *
+format_reverse_addr_in (
+	const struct in_addr * addr,
+	int prefixlen,
+	char * buf
+)
+{
+	char * curr = buf;
+	int i;
+	
+	const uint8_t * in_addr_a = (uint8_t *) addr;
+	
+	if (prefixlen > 32)
+		return NULL;
+	if (prefixlen < 0)
+		prefixlen = 32;
+
+	i = (prefixlen + 7) / 8;
+		// divide prefixlen into bytes, rounding up
+	
+	while (i > 0)
+	{
+		i--;
+		curr += sprintf (curr, "%d.", in_addr_a [i]);
+	}
+	sprintf (curr, "in-addr.arpa");
+	
+	return buf;
+}
+
+
+char *
+format_reverse_addr_in6 (
+	const struct in6_addr * addr,
+	int prefixlen,
+	char * buf
+)
+{
+	char * curr = buf;
+	int i;
+
+	const uint8_t * in_addr_a = (uint8_t *) addr;
+
+	if (prefixlen > 128)
+		return NULL;
+	if (prefixlen < 0)
+		prefixlen = 128;
+	
+	i = (prefixlen + 3) / 4;
+		// divide prefixlen into nibbles, rounding up
+
+	// Special handling for first
+	if (i / 2)
+	{
+		curr += sprintf (curr, "%d.", (in_addr_a [i] >> 4) & 0x0F);
+	}
+	i >>= 1;
+		// Convert i to bytes (divide by 2)
+	
+	while (i > 0)
+	{
+		uint8_t val;
+		
+		i--;
+		val = in_addr_a [i];
+		curr += sprintf (curr, "%x.%x.", val & 0x0F, (val >> 4) & 0x0F);
+	}
+	sprintf (curr, "ip6.arpa");
+	
+	return buf;
+}
+
+
+char *
+format_reverse_addr (
+	int af,
+	const void * addr,
+	int prefixlen,
+	char * buf
+)
+{
+	switch (af)
+	{
+	  case AF_INET:
+		return
+			format_reverse_addr_in (
+				(struct in_addr *) addr, prefixlen, buf
+			);
+		break;
+	
+	  case AF_INET6:
+		return
+			format_reverse_addr_in6 (
+				(struct in6_addr *) addr, prefixlen, buf
+			);
+		break;
+	
+	  default:
+		return NULL;
+	}
+}
+
+
+int
+cmp_dns_suffix (const char * name, const char * domain)
+{
+	const char * nametail;
+	const char * domaintail;
+
+	// Idiot checks
+	if (*name == 0 || *name == k_dns_separator)
+	{
+		// Name can't be empty or start with separator
+		return CMP_DNS_SUFFIX_BAD_NAME;
+	}
+	
+	if (*domain == 0)
+	{
+		return CMP_DNS_SUFFIX_SUCCESS;
+			// trivially true
+	}
+	
+	if (*domain == k_dns_separator)
+	{
+		// drop leading separator from domain
+		domain++;
+		if (*domain == k_dns_separator)
+		{
+			return CMP_DNS_SUFFIX_BAD_DOMAIN;
+		}
+	}
+
+	// Find ends of strings
+	for (nametail = name; *nametail; nametail++)
+		;
+	for (domaintail = domain; *domaintail; domaintail++)
+		;
+	
+	// Shuffle back to last real character, and drop any trailing '.'
+	// while we're at it.
+	nametail --;
+	if (*nametail == k_dns_separator)
+	{
+		nametail --;
+		if (*nametail == k_dns_separator)
+		{
+			return CMP_DNS_SUFFIX_BAD_NAME;
+		}
+	}
+	domaintail --;
+	if (*domaintail == k_dns_separator)
+	{
+		domaintail --;
+		if (*domaintail == k_dns_separator)
+		{
+			return CMP_DNS_SUFFIX_BAD_DOMAIN;
+		}
+	}
+	
+	// Compare.
+	while (
+		nametail >= name
+		&& domaintail >= domain
+		&& tolower(*nametail) == tolower(*domaintail))
+	{
+		nametail--;
+		domaintail--;
+	}
+	
+	/* A successful finish will be one of the following:
+		(leading and trailing . ignored)
+		
+		name  :  domain2.domain1
+		domain:  domain2.domain1
+		        ^
+		
+		name  : domain3.domain2.domain1
+		domain:         domain2.domain1
+		               ^
+	 */
+	if (
+		domaintail < domain
+		&& (nametail < name || *nametail == k_dns_separator)
+	)
+	{
+		return CMP_DNS_SUFFIX_SUCCESS;
+	}
+	else
+	{
+		return CMP_DNS_SUFFIX_FAILURE;
+	}
+}
+
+
+int
+dns_rdata_to_name (const char * rdata, int rdlen, char * name, int name_len)
+{
+	int i = 0;
+		// Index into 'name'
+	const char * rdata_curr = rdata;
+	
+	// drop any leading whitespace rubbish
+	while (isspace (*rdata_curr))
+	{
+		rdata_curr ++;
+		if (rdata_curr > rdata + rdlen)
+		{
+			return DNS_RDATA_TO_NAME_BAD_FORMAT;
+		}
+	}
+	
+	/*
+		In RDATA, a DNS name is stored as a series of labels.
+		Each label consists of a length octet (max value 63)
+		followed by the data for that label.
+		The series is terminated with a length 0 octet.
+		A length octet beginning with bits 11 is a pointer to
+		somewhere else in the payload, but we don't support these
+		since we don't have access to the entire payload.
+	
+		See RFC1034 section 3.1 and RFC1035 section 3.1.
+	 */
+	while (1)
+	{
+		int term_len = *rdata_curr;
+		rdata_curr++;
+
+		if (term_len == 0)
+		{
+			break;
+				// 0 length record terminates label
+		}
+		else if (term_len > k_label_maxlen)
+		{
+			name [i] = 0;
+			return DNS_RDATA_TO_NAME_PTR;
+		}
+		else if (rdata_curr + term_len > rdata + rdlen)
+		{
+			name [i] = 0;
+			return DNS_RDATA_TO_NAME_BAD_FORMAT;
+		}
+		
+		if (name_len < i + term_len + 1)
+			// +1 is separator
+		{
+			name [i] = 0;
+			return DNS_RDATA_TO_NAME_TOO_LONG;
+		}
+		
+		memcpy (name + i, rdata_curr, term_len);
+		
+		i += term_len;
+		rdata_curr += term_len;
+		
+		name [i] = k_dns_separator;
+		i++;
+	}
+	
+	name [i] = 0;
+	return i;
+}
+
+
+//----------
+// Local functions
+
+/*
+	Find the index of an string entry in a table.  A case insenitive match
+	is performed.  If no entry is found, 0 is returned.
+	
+	Parameters
+		table
+			Lookup table
+			Table entries may be NULL.  NULL entries will never match.
+		size
+			number of entries in table
+		str
+			lookup string
+
+	Result
+		index of first matching entry, or 0 if no matches
+ */
+static int
+simple_table_index (const char * table [], int size, const char * str)
+{
+	int i;
+	for (i = 0; i < size; i++)
+	{
+		if (
+			table [i]
+			&& (strcasecmp (table [i], str) == 0)
+		)
+		{
+			return i;
+		}
+	}
+	
+	return 0;
+}
+
+
+/*
+	Find the index of a name in a table.
+	
+	Parameters
+		table
+			array of table_entry_t records.  The name field is compared
+			(ignoring case) to the input string.
+		size
+			number of entries in table
+		str
+			lookup string
+
+	Result
+		index of first matching entry, or -1 if no matches
+ */
+static int
+table_index_name (const table_entry_t table [], int size, const char * str)
+{
+	int i;
+	for (i = 0; i < size; i++)
+	{
+		if (
+			table [i].name
+			&& (strcasecmp (table [i].name, str) == 0)
+		)
+		{
+			return i;
+		}
+	}
+	
+	return -1;
+}
+
+
+/*
+	Find the index of a value a table.
+	
+	Parameters
+		table
+			array of table_entry_t records.  The value field is compared to
+			the input value
+		size
+			number of entries in table
+		n
+			lookup value
+
+	Result
+		index of first matching entry, or -1 if no matches
+ */
+static int
+table_index_value (const table_entry_t table [], int size, int n)
+{
+	int i;
+	for (i = 0; i < size; i++)
+	{
+		if (table [i].value == n)
+		{
+			return i;
+		}
+	}
+	
+	return -1;
+}
diff --git a/mDNSPosix/nss_mdns.conf b/mDNSPosix/nss_mdns.conf
new file mode 100755
index 0000000..8f9b309
--- /dev/null
+++ b/mDNSPosix/nss_mdns.conf
@@ -0,0 +1,7 @@
+# Defaut configuration file for nss_mdns
+
+# Applicable domains
+domain local
+domain 0.8.e.f.ip6.int
+domain 0.8.e.f.ip6.arpa
+domain 254.169.in-addr.arpa
diff --git a/mDNSPosix/nss_mdns.conf.5 b/mDNSPosix/nss_mdns.conf.5
new file mode 100755
index 0000000..42dd995
--- /dev/null
+++ b/mDNSPosix/nss_mdns.conf.5
@@ -0,0 +1,136 @@
+.\"	$Id: nss_mdns.conf.5,v 1.1 2004/06/29 03:34:28 cheshire Exp $
+.\"
+.\" See section LICENSE for license information.
+.\"
+.Dd June 15, 2004
+.Dt NSS_MDNS.CONF 5
+.Os
+.Sh NAME
+.Nm nss_mdns.conf
+.Nd configuration file for
+.Xr libnss_mdns 8 .
+.Sh DESCRIPTION
+This file describes the domains that
+.Xr libnss_mdns 8
+is to support.  If a lookup domain is not in this list, then
+.Li NSS_STATUS_NOTFOUND
+will be returned to libc and processing will continue according to
+.Xr nsswitch.conf 5 .
+.Ss Configuration file format
+Lines containing only whitespace or lines whose first non-whitespace character is
+.Ql #
+are ignored.  No single line may be greater than 1023 characters plus end-of-line.
+.Pp
+.D1 Ic domain Ar x.y.z
+.Pp
+Enable use of
+.Xr libnss_mdns 8
+to lookup DNS entries in the
+.Ql x.y.z
+domain.  Leading and trailing dots are dropped.
+.Pp
+Reverse (PTR) lookups are enabled using their DNS names.  IPv6 names use
+.Qq nibble format .
+.Pp
+.Dl domain 254.169.in-addr.arpa
+.Dl domain 0.8.e.f.ip6.arpa
+.Ss Default configuration
+If the configuration file cannot be found then the following is assumed.
+.Bd -literal -offset indent
+domain local
+domain 0.8.e.f.ip6.int
+domain 0.8.e.f.ip6.arpa
+domain 254.169.in-addr.arpa
+.Ed
+.Sh SEE ALSO
+.\" Cross-references should be ordered by section (low to high), then in
+.\"     alphabetical order.
+.Xr nsswitch.conf 5 ,
+.Xr libnss_mdns 8
+.\" .Sh STANDARDS
+.Sh HISTORY
+.Xr libnss_mdns 8
+was originally written for
+.An NICTA Bq http://www.nicta.com.au/ .
+.Sh AUTHORS
+.An "Andrew White" Bq Andrew.White@nicta.com.au
+.Sh LICENSE
+This software is licensed under the NICTA Public Source License version 1.0
+.Ss NICTA Public Software Licence
+Version 1.0
+.Pp
+Copyright 2004 National ICT Australia Ltd
+.Pp
+All rights reserved.
+.Pp
+By this licence, National ICT Australia Ltd (NICTA) grants permission,
+free of charge, to any person who obtains a copy of this software
+and any associated documentation files ("the Software") to use and
+deal with the Software in source code and binary forms without
+restriction, with or without modification, and to permit persons
+to whom the Software is furnished to do so, provided that the
+following conditions are met:
+.Bl -bullet
+.It
+Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimers.
+.It
+Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimers in
+the documentation and/or other materials provided with the
+distribution.
+.It
+The name of NICTA may not be used to endorse or promote products
+derived from this Software without specific prior written permission.
+.El
+.Pp
+EXCEPT AS EXPRESSLY STATED IN THIS LICENCE AND TO THE FULL EXTENT
+PERMITTED BY APPLICABLE LAW, THE SOFTWARE IS PROVIDED "AS-IS" AND
+NICTA MAKES NO REPRESENTATIONS, WARRANTIES OR CONDITIONS OF ANY
+KIND, EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION, ANY
+REPRESENTATIONS, WARRANTIES OR CONDITIONS REGARDING THE CONTENTS
+OR ACCURACY OF THE SOFTWARE, OR OF TITLE, MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, THE ABSENCE OF LATENT
+OR OTHER DEFECTS, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR
+NOT DISCOVERABLE.
+.Pp
+TO THE FULL EXTENT PERMITTED BY APPLICABLE LAW, IN NO EVENT WILL
+NICTA BE LIABLE ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
+NEGLIGENCE) FOR ANY LOSS OR DAMAGE WHATSOEVER, INCLUDING (WITHOUT
+LIMITATION) LOSS OF PRODUCTION OR OPERATION TIME, LOSS, DAMAGE OR
+CORRUPTION OF DATA OR RECORDS; OR LOSS OF ANTICIPATED SAVINGS,
+OPPORTUNITY, REVENUE, PROFIT OR GOODWILL, OR OTHER ECONOMIC LOSS;
+OR ANY SPECIAL, INCIDENTAL, INDIRECT, CONSEQUENTIAL, PUNITIVE OR
+EXEMPLARY DAMAGES ARISING OUT OF OR IN CONNECTION WITH THIS LICENCE,
+THE SOFTWARE OR THE USE OF THE SOFTWARE, EVEN IF NICTA HAS BEEN
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+.Pp
+If applicable legislation implies warranties or conditions, or
+imposes obligations or liability on NICTA in respect of the Software
+that cannot be wholly or partly excluded, restricted or modified,
+NICTA's liability is limited, to the full extent permitted by the
+applicable legislation, at its option, to:
+.Pp
+.Bl -tag -width "a." -compact
+.It a.
+in the case of goods, any one or more of the following:
+.Bl -tag -width "iii." -compact
+.It i.
+the replacement of the goods or the supply of equivalent goods;
+.It ii.
+the repair of the goods;
+.It iii.
+the payment of the cost of replacing the goods or of acquiring
+equivalent goods;
+.It iv.
+the payment of the cost of having the goods repaired; or
+.El
+.It b.
+in the case of services:
+.Bl -tag -width "iii." -compact
+.It i.
+the supplying of the services again; or 
+.It ii.
+the payment of the cost of having the services supplied again.
+.El
+.El
diff --git a/mDNSShared/GenLinkedList.c b/mDNSShared/GenLinkedList.c
index 04a1581..1d231f2 100755
--- a/mDNSShared/GenLinkedList.c
+++ b/mDNSShared/GenLinkedList.c
@@ -3,8 +3,6 @@
  *
  * @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/GenLinkedList.h b/mDNSShared/GenLinkedList.h
index 46cbb23..5a7de91 100755
--- a/mDNSShared/GenLinkedList.h
+++ b/mDNSShared/GenLinkedList.h
@@ -3,8 +3,6 @@
  *
  * @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/Java/BaseListener.java b/mDNSShared/Java/BaseListener.java
index f4f298b..665263d 100644
--- a/mDNSShared/Java/BaseListener.java
+++ b/mDNSShared/Java/BaseListener.java
@@ -3,8 +3,6 @@
  *
  * @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/Java/BrowseListener.java b/mDNSShared/Java/BrowseListener.java
index 2664e84..5bda3ae 100644
--- a/mDNSShared/Java/BrowseListener.java
+++ b/mDNSShared/Java/BrowseListener.java
@@ -3,8 +3,6 @@
  *
  * @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/Java/DNSRecord.java b/mDNSShared/Java/DNSRecord.java
index d82ebd5..73e1626 100644
--- a/mDNSShared/Java/DNSRecord.java
+++ b/mDNSShared/Java/DNSRecord.java
@@ -3,8 +3,6 @@
  *
  * @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
@@ -25,6 +23,9 @@
     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.
 
@@ -42,7 +43,27 @@ package	com.apple.dnssd;
 	they are shared between concurrent threads.
 */
 
-abstract public class	DNSRecord
+public interface	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;
 }
 
diff --git a/mDNSShared/Java/DNSSD.java b/mDNSShared/Java/DNSSD.java
index 79cb5c7..831b4b4 100644
--- a/mDNSShared/Java/DNSSD.java
+++ b/mDNSShared/Java/DNSSD.java
@@ -3,8 +3,6 @@
  *
  * @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
@@ -25,6 +23,12 @@
     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
 
@@ -599,12 +603,12 @@ class	AppleDNSSD extends DNSSD
 
 	protected String			_getNameForIfIndex( int ifIndex)
 	{
-		return null;		// â¢â¢Fix me - RNP
+		return GetNameForIfIndex( ifIndex);
 	}
 
 	protected int				_getIfIndexForName( String ifName)
 	{
-		return 0;		// â¢â¢Fix me - RNP
+		return GetIfIndexForName( ifName);
 	}
 
 
@@ -613,6 +617,10 @@ 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);
 }
 
@@ -715,9 +723,38 @@ class	AppleResolver extends AppleService
 }
 
 // An AppleDNSRecord is a simple wrapper around a dns_sd DNSRecord.
-class	AppleDNSRecord extends DNSRecord
+class	AppleDNSRecord implements DNSRecord
 {
-	public int		fRecord;		// Really a DNSRecord; sizeof(int) == sizeof(void*) ?
+	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();
 }
 
 class	AppleRegistration extends AppleService implements DNSSDRegistration
@@ -735,23 +772,17 @@ class	AppleRegistration extends AppleService implements DNSSDRegistration
 	public DNSRecord	addRecord( int flags, int rrType, byte[] rData, int ttl)
 	throws DNSSDException
 	{
-		AppleDNSRecord	newRecord = new AppleDNSRecord();
+		AppleDNSRecord	newRecord = new AppleDNSRecord( this);
 
 		this.ThrowOnErr( this.AddRecord( flags, rrType, rData, ttl, newRecord));
 
 		return newRecord;
 	}
 
-	public void			updateRecord( DNSRecord record, int flags, byte[] rData, int ttl)
+	public DNSRecord	getTXTRecord()
 	throws DNSSDException
 	{
-		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));
+		return new AppleDNSRecord( this);	// A record with ref 0 is understood to be primary TXT record
 	}
 
 	// Sets fNativeContext. Returns non-zero on error.
@@ -761,10 +792,6 @@ 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;
 }
 
diff --git a/mDNSShared/Java/DNSSDException.java b/mDNSShared/Java/DNSSDException.java
index f3ccbcb..595e405 100644
--- a/mDNSShared/Java/DNSSDException.java
+++ b/mDNSShared/Java/DNSSDException.java
@@ -3,8 +3,6 @@
  *
  * @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/Java/DNSSDRegistration.java b/mDNSShared/Java/DNSSDRegistration.java
index 7be186d..4a4942f 100644
--- a/mDNSShared/Java/DNSSDRegistration.java
+++ b/mDNSShared/Java/DNSSDRegistration.java
@@ -3,8 +3,6 @@
  *
  * @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
@@ -25,6 +23,9 @@
     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.
 
@@ -41,10 +42,20 @@ 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 later be updated or deregistered by passing the DNSRecord returned 
-		by this function to updateRecord() or removeRecord().<P>
+		The record can be updated or deregistered by sending it an update() or remove() message.<P>
 
 		@param	flags
 					Currently unused, reserved for future use.
@@ -64,37 +75,5 @@ 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;
 } 
 
diff --git a/mDNSShared/Java/DNSSDService.java b/mDNSShared/Java/DNSSDService.java
index bd7611a..9868372 100644
--- a/mDNSShared/Java/DNSSDService.java
+++ b/mDNSShared/Java/DNSSDService.java
@@ -3,8 +3,6 @@
  *
  * @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/Java/DomainListener.java b/mDNSShared/Java/DomainListener.java
index 13fad3b..bfb319a 100644
--- a/mDNSShared/Java/DomainListener.java
+++ b/mDNSShared/Java/DomainListener.java
@@ -3,8 +3,6 @@
  *
  * @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/Java/JNISupport.c b/mDNSShared/Java/JNISupport.c
index b57bd46..ef9940a 100644
--- a/mDNSShared/Java/JNISupport.c
+++ b/mDNSShared/Java/JNISupport.c
@@ -3,8 +3,6 @@
  *
  * @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
@@ -25,8 +23,30 @@
     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 doesn't build on Tiger8A132
+<rdar://problem/3672903>: Java project build errors
 
 Revision 1.1  2004/04/30 16:29:35  rpantos
 First checked in.
@@ -34,46 +54,45 @@ 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 it does on Windows).
+// callbacks automatically (as in the early Windows prototypes).
 // AUTO_CALLBACKS should be set to 0 if the client must call DNSServiceProcessResult() to
-// invoke response callbacks (as is true on Mac OS X).
+// 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.)
 #ifndef	AUTO_CALLBACKS
 #define	AUTO_CALLBACKS	0
 #endif
 
-// (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
+#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>
 
 #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 
@@ -112,16 +131,6 @@ 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;
@@ -189,7 +198,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)
 	{
@@ -303,7 +312,7 @@ JNIEXPORT void JNICALL Java_com_apple_dnssd_AppleService_ProcessResults( JNIEnv
 }
 
 
-static void CALLBACK_COMPAT	ServiceBrowseReply( DNSServiceRef sdRef _UNUSED, DNSServiceFlags flags, uint32_t interfaceIndex, 
+static void DNSSD_API	ServiceBrowseReply( DNSServiceRef sdRef _UNUSED, DNSServiceFlags flags, uint32_t interfaceIndex, 
 								DNSServiceErrorType errorCode, const char *serviceName, const char *regtype, 
 								const char *replyDomain, void *context)
 {
@@ -368,7 +377,7 @@ JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleBrowser_CreateBrowser( JNIEnv *
 }
 
 
-static void CALLBACK_COMPAT	ServiceResolveReply( DNSServiceRef sdRef _UNUSED, DNSServiceFlags flags, uint32_t interfaceIndex, 
+static void DNSSD_API	ServiceResolveReply( DNSServiceRef sdRef _UNUSED, DNSServiceFlags flags, uint32_t interfaceIndex, 
 								DNSServiceErrorType errorCode, const char *fullname, const char *hosttarget, 
 								uint16_t port, uint16_t txtLen, const char *txtRecord, void *context)
 {
@@ -453,7 +462,7 @@ JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleResolver_CreateResolver( JNIEnv
 }
 
 
-static void CALLBACK_COMPAT	ServiceRegisterReply( DNSServiceRef sdRef _UNUSED, DNSServiceFlags flags, 
+static void DNSSD_API	ServiceRegisterReply( DNSServiceRef sdRef _UNUSED, DNSServiceFlags flags, 
 								DNSServiceErrorType errorCode, const char *fullname, 
 								const char *regType, const char *domain, void *context)
 {
@@ -564,23 +573,28 @@ JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleRegistration_AddRecord( JNIEnv
 	return err;
 }
 
-JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleRegistration_UpdateRecord( JNIEnv *pEnv, jobject pThis, 
-							jobject destObj, jint flags, jbyteArray rData, jint ttl)
+JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleDNSRecord_Update( JNIEnv *pEnv, jobject pThis, 
+														jint flags, jbyteArray rData, jint ttl)
 {
 	jclass					cls = (*pEnv)->GetObjectClass( pEnv, pThis);
-	jfieldID				contextField = (*pEnv)->GetFieldID( pEnv, cls, "fNativeContext", "I");
-	jclass					destCls = (*pEnv)->GetObjectClass( pEnv, destObj);
-	jfieldID				recField = (*pEnv)->GetFieldID( pEnv, destCls, "fRecord", "I");
+	jfieldID				ownerField = (*pEnv)->GetFieldID( pEnv, cls, "fOwner", "Lcom/apple/dnssd/AppleService;");
+	jfieldID				recField = (*pEnv)->GetFieldID( pEnv, cls, "fRecord", "I");
 	OpContext				*pContext = NULL;
 	DNSServiceErrorType		err = kDNSServiceErr_NoError;
 	jbyte					*pBytes;
 	jsize					numBytes;
 	DNSRecordRef			recRef = NULL;
 
-	if ( contextField != 0)
-		pContext = (OpContext*) (*pEnv)->GetIntField( pEnv, pThis, contextField);
+	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 ( recField != 0)
-		recRef = (DNSRecordRef) (*pEnv)->GetIntField( pEnv, destObj, recField);
+		recRef = (DNSRecordRef) (*pEnv)->GetIntField( pEnv, pThis, recField);
 	if ( pContext == NULL || pContext->ServiceRef == NULL)
 		return kDNSServiceErr_BadParam;
 
@@ -595,31 +609,35 @@ JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleRegistration_UpdateRecord( JNIE
 	return err;
 }
 
-JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleRegistration_RemoveRecord( JNIEnv *pEnv, jobject pThis, 
-							jobject destObj, jint flags)
+JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleDNSRecord_Remove( JNIEnv *pEnv, jobject pThis)
 {
 	jclass					cls = (*pEnv)->GetObjectClass( pEnv, pThis);
-	jfieldID				contextField = (*pEnv)->GetFieldID( pEnv, cls, "fNativeContext", "I");
-	jclass					destCls = (*pEnv)->GetObjectClass( pEnv, destObj);
-	jfieldID				recField = (*pEnv)->GetFieldID( pEnv, destCls, "fRecord", "I");
+	jfieldID				ownerField = (*pEnv)->GetFieldID( pEnv, cls, "fOwner", "Lcom/apple/dnssd/AppleService;");
+	jfieldID				recField = (*pEnv)->GetFieldID( pEnv, cls, "fRecord", "I");
 	OpContext				*pContext = NULL;
 	DNSServiceErrorType		err = kDNSServiceErr_NoError;
 	DNSRecordRef			recRef = NULL;
 
-	if ( contextField != 0)
-		pContext = (OpContext*) (*pEnv)->GetIntField( pEnv, pThis, contextField);
+	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 ( recField != 0)
-		recRef = (DNSRecordRef) (*pEnv)->GetIntField( pEnv, destObj, recField);
+		recRef = (DNSRecordRef) (*pEnv)->GetIntField( pEnv, pThis, recField);
 	if ( pContext == NULL || pContext->ServiceRef == NULL)
 		return kDNSServiceErr_BadParam;
 
-	err = DNSServiceRemoveRecord( pContext->ServiceRef, recRef, flags);
+	err = DNSServiceRemoveRecord( pContext->ServiceRef, recRef, 0);
 
 	return err;
 }
 
 
-static void CALLBACK_COMPAT	ServiceQueryReply( DNSServiceRef sdRef _UNUSED, DNSServiceFlags flags, uint32_t interfaceIndex, 
+static void DNSSD_API	ServiceQueryReply( DNSServiceRef sdRef _UNUSED, DNSServiceFlags flags, uint32_t interfaceIndex, 
 								DNSServiceErrorType errorCode, const char *serviceName,
 								uint16_t rrtype, uint16_t rrclass, uint16_t rdlen,
 								const void *rdata, uint32_t ttl, void *context)
@@ -685,7 +703,7 @@ JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleQuery_CreateQuery( JNIEnv *pEnv
 }
 
 
-static void CALLBACK_COMPAT	DomainEnumReply( DNSServiceRef sdRef _UNUSED, DNSServiceFlags flags, uint32_t interfaceIndex, 
+static void DNSSD_API	DomainEnumReply( DNSServiceRef sdRef _UNUSED, DNSServiceFlags flags, uint32_t interfaceIndex, 
 								DNSServiceErrorType errorCode, const char *replyDomain, void *context)
 {
 	OpContext		*pContext = (OpContext*) context;
@@ -784,5 +802,141 @@ 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
diff --git a/mDNSShared/Java/QueryListener.java b/mDNSShared/Java/QueryListener.java
index 1a8637b..7ece74c 100644
--- a/mDNSShared/Java/QueryListener.java
+++ b/mDNSShared/Java/QueryListener.java
@@ -3,8 +3,6 @@
  *
  * @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/Java/RegisterListener.java b/mDNSShared/Java/RegisterListener.java
index 28c9fa5..a6cf331 100644
--- a/mDNSShared/Java/RegisterListener.java
+++ b/mDNSShared/Java/RegisterListener.java
@@ -3,8 +3,6 @@
  *
  * @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/Java/ResolveListener.java b/mDNSShared/Java/ResolveListener.java
index ac606cf..0e21353 100644
--- a/mDNSShared/Java/ResolveListener.java
+++ b/mDNSShared/Java/ResolveListener.java
@@ -3,8 +3,6 @@
  *
  * @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/Java/TXTRecord.java b/mDNSShared/Java/TXTRecord.java
index 97bcea9..5eed93e 100644
--- a/mDNSShared/Java/TXTRecord.java
+++ b/mDNSShared/Java/TXTRecord.java
@@ -3,8 +3,6 @@
  *
  * @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
@@ -25,6 +23,15 @@
     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.
 
@@ -42,7 +49,7 @@ package	com.apple.dnssd;
 
 /**	
 	Object used to construct and parse DNS-SD format TXT records.
-	For more info see <a href="http://www.zeroconf.org/Rendezvous/txtrecords.html">DNS-SD TXT record format</a>. 
+	For more info see <a href="http://files.dns-sd.org/draft-cheshire-dnsext-dns-sd.txt">DNS-Based Service Discovery</a>, section 6. 
 */
 
 public class	TXTRecord
@@ -90,10 +97,8 @@ 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");
@@ -108,17 +113,66 @@ public class	TXTRecord
 
 		if ( keyBytes.length + valLen >= 255)
 			throw new ArrayIndexOutOfBoundsException();
-		newLen = (byte) ( keyBytes.length + valLen + (valLen > 0 ? 1 : 0));
 
-		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		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[ oldBytes.length + 1 + keyBytes.length] = kAttrSep;
-			System.arraycopy( value, 0, fBytes, oldBytes.length + keyBytes.length + 2, value.length);
+			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;
 		}
+		return -1;
 	}
 
 	/**	Return the number of keys in the TXT record. */
@@ -187,6 +241,7 @@ public class	TXTRecord
 				{
 					value = new byte[ avLen - aLen - 1];
 					System.arraycopy( fBytes, avStart + aLen + 2, value, 0, avLen - aLen - 1);
+					break;
 				}
 			}
 		}
@@ -234,5 +289,26 @@ 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 : "";
+	}
 }
 
diff --git a/mDNSShared/PlatformCommon.c b/mDNSShared/PlatformCommon.c
new file mode 100644
index 0000000..4525eb4
--- /dev/null
+++ b/mDNSShared/PlatformCommon.c
@@ -0,0 +1,131 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+
+$Log: PlatformCommon.c,v $
+Revision 1.3  2004/12/13 17:46:52  cheshire
+Use sizeof(buf) instead of fixed constant 1024
+
+Revision 1.2  2004/12/01 03:30:29  cheshire
+<rdar://problem/3889346> Add Unicast DNS support to mDNSPosix
+
+Revision 1.1  2004/12/01 01:51:35  cheshire
+Move ReadDDNSSettingsFromConfFile() from mDNSMacOSX.c to PlatformCommon.c
+
+ */
+
+#include <stdio.h>				// Needed for fopen() etc.
+#include <unistd.h>				// Needed for close()
+#include <string.h>				// Needed for strlen() etc.
+#include <sys/errno.h>			// Needed for errno etc.
+#include <sys/socket.h>			// Needed for socket() etc.
+#include <netinet/in.h>			// Needed for sockaddr_in
+
+#include "mDNSEmbeddedAPI.h"	// Defines the interface provided to the client layer above
+#include "PlatformCommon.h"
+
+#ifdef NOT_HAVE_SOCKLEN_T
+    typedef unsigned int socklen_t;
+#endif
+
+// Bind a UDP socket to a global destination to find the default route's interface address
+mDNSexport void FindDefaultRouteIP(mDNSAddr *a)
+	{
+	struct sockaddr_in addr;
+	socklen_t len = sizeof(addr);
+	int sock = socket(AF_INET,SOCK_DGRAM,0);
+	a->type = mDNSAddrType_None;
+	if (sock == -1) return;
+	addr.sin_family = AF_INET;
+	addr.sin_port = 1;	// Not important, any port and public address will do
+	addr.sin_addr.s_addr = 0x11111111;
+	if ((connect(sock,(const struct sockaddr*)&addr,sizeof(addr))) == -1) { close(sock); return; }
+	if ((getsockname(sock,(struct sockaddr*)&addr, &len)) == -1) { close(sock); return; }
+	close(sock);
+	a->type = mDNSAddrType_IPv4;
+	a->ip.v4.NotAnInteger = addr.sin_addr.s_addr;
+	}
+
+// dst must be at least MAX_ESCAPED_DOMAIN_NAME bytes, and option must be less than 20 bytes in length
+mDNSlocal mDNSBool GetConfigOption(char *dst, const char *option, FILE *f)
+	{
+	char buf[20+1+MAX_ESCAPED_DOMAIN_NAME];	// Option name, one space, option value
+	unsigned int len = strlen(option);
+	if (len + 1 + MAX_ESCAPED_DOMAIN_NAME > sizeof(buf)-1) { LogMsg("GetConfigOption: option %s too long", option); return mDNSfalse; }
+	fseek(f, 0, SEEK_SET);  // set position to beginning of stream
+	while (fgets(buf, sizeof(buf), f))		// Read at most sizeof(buf)-1 bytes from file, and append '\0' C-string terminator
+		{
+		if (!strncmp(buf, option, len))
+			{
+			strncpy(dst, buf + len + 1, MAX_ESCAPED_DOMAIN_NAME-1);
+			if (dst[MAX_ESCAPED_DOMAIN_NAME-1]) dst[MAX_ESCAPED_DOMAIN_NAME-1] = '\0';
+			len = strlen(dst);
+			if (len && dst[len-1] == '\n') dst[len-1] = '\0';  // chop newline
+			return mDNStrue;
+			}
+		}
+	debugf("Option %s not set", option);
+	return mDNSfalse;
+	}
+
+mDNSexport void ReadDDNSSettingsFromConfFile(mDNS *const m, const char *const filename, domainname *const hostname, domainname *const domain)
+	{
+	char zone  [MAX_ESCAPED_DOMAIN_NAME];
+	char fqdn  [MAX_ESCAPED_DOMAIN_NAME];
+	char secret[MAX_ESCAPED_DOMAIN_NAME] = "";
+	int slen;
+	mStatus err;
+	FILE *f = fopen(filename, "r");
+
+    hostname->c[0] = 0;
+    domain->c[0] = 0;
+
+	if (f)
+		{
+		if (GetConfigOption(fqdn, "hostname", f) && !MakeDomainNameFromDNSNameString(hostname, fqdn)) goto badf;
+		if (GetConfigOption(zone, "zone", f) && !MakeDomainNameFromDNSNameString(domain, zone)) goto badf;
+		GetConfigOption(secret, "secret-64", f);  // failure means no authentication	   
+		fclose(f);
+		f = NULL;
+		}
+	else
+		{
+		if (errno != ENOENT) LogMsg("ERROR: Config file exists, but cannot be opened.");
+		return;
+		}
+
+	if (secret[0])
+		{
+		// for now we assume keyname = service reg domain and we use same key for service and hostname registration
+		slen = strlen(secret);
+		err = mDNS_SetSecretForZone(m, domain, domain, secret, slen, mDNStrue);
+		if (err) LogMsg("ERROR: mDNS_SetSecretForZone returned %d for domain %##s", err, domain->c);
+		}
+
+	return;
+
+	badf:
+	LogMsg("ERROR: malformatted config file");
+	if (f) fclose(f);	
+	}
diff --git a/mDNSShared/PlatformCommon.h b/mDNSShared/PlatformCommon.h
new file mode 100644
index 0000000..9e4638b
--- /dev/null
+++ b/mDNSShared/PlatformCommon.h
@@ -0,0 +1,36 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+
+$Log: PlatformCommon.h,v $
+Revision 1.2  2004/12/01 03:30:29  cheshire
+<rdar://problem/3889346> Add Unicast DNS support to mDNSPosix
+
+Revision 1.1  2004/12/01 01:51:35  cheshire
+Move ReadDDNSSettingsFromConfFile() from mDNSMacOSX.c to PlatformCommon.c
+
+ */
+
+extern void FindDefaultRouteIP(mDNSAddr *a);
+extern void ReadDDNSSettingsFromConfFile(mDNS *const m, const char *const filename, domainname *const hostname, domainname *const domain);
diff --git a/mDNSShared/dns-sd.1 b/mDNSShared/dns-sd.1
new file mode 100644
index 0000000..a8a602b
--- /dev/null
+++ b/mDNSShared/dns-sd.1
@@ -0,0 +1,208 @@
+.\" 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: dns-sd.1,v $
+.\" Revision 1.2  2004/09/24 18:33:05  cheshire
+.\" <rdar://problem/3561780> Update man pages to clarify that mDNS and dns-sd are not intended for script use
+.\"
+.\" Revision 1.1  2004/09/22 22:46:25  cheshire
+.\" Man page for dns-sd command-line tool
+.\"
+.\"
+.\"
+.Dd April 2004              \" Date
+.Dt dns-sd 1                \" Document Title
+.Os Darwin                  \" Operating System
+.\"
+.Sh NAME
+.Nm dns-sd
+.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 .
+However, unlike those tools, most of its functionality is not implemented in the
+.Nm
+executable itself, but in library code that is available to any application.
+The library API that
+.Nm
+uses is documented in
+.Pa /usr/include/dns_sd.h .
+The
+.Nm
+command replaces the older
+.Xr mDNS 1
+command.
+.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 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.
+.br
+If you wish to perform DNS Service Discovery operations from a
+scripting language, then the best way to do this is not to execute the
+.Nm
+command and then attempt to decipher the textual output, but instead to
+directly call the DNS-SD APIs using a binding for your chosen language.
+.br
+For example, if you are programming in Ruby, then you can
+directly call DNS-SD APIs using the dnssd package documented at
+.Pa <http://rubyforge.org/projects/dnssd/> .
+.br
+Similar bindings for other languages are also in development.
+.Pp
+.Bl -tag -width R
+.It Nm 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 Nm 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 Nm 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 Nm Fl R Ns \ \&"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 Nm Fl R Ns \ \&"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 Nm Fl B Ns \ _http._tcp
+.Pp
+While that command is running, in another window, try the
+.Nm Fl R
+example given above to advertise a web page, and you should see the
+"Add" event reported to the
+.Nm Fl B
+window. Now press Ctrl-C in the
+.Nm Fl R
+window and you should see the "Remove" event reported to the
+.Nm Fl B
+window.
+.Pp
+.Sh FILES
+.Pa /usr/bin/dns-sd \" Pathname
+.\"
+.Sh SEE ALSO
+.Xr mDNS 1
+.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/dns_sd.h b/mDNSShared/dns_sd.h
index 45f51b7..7d14fca 100755
--- a/mDNSShared/dns_sd.h
+++ b/mDNSShared/dns_sd.h
@@ -1,84 +1,28 @@
 /*
- * 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
+ * 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.
  */
 
 #ifndef _DNS_SD_H
@@ -88,9 +32,28 @@ Update to APSL 2.0
     extern "C" {
 #endif
 
-#if defined(__FreeBSD__) && (__FreeBSD_version < 500000)
+/* 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)
 /* 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
@@ -155,10 +118,89 @@ 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
     {
@@ -175,12 +217,16 @@ 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_NoSuchKey           = -65556,
+    kDNSServiceErr_NATTraversal        = -65557,
+    kDNSServiceErr_DblNAT              = -65558,
+    kDNSServiceErr_BadTime             = -65559
     /* mDNS Error codes are in the range
      * FFFE FF00 (-65792) to FFFE FFFF (-65537) */
     };
@@ -191,13 +237,91 @@ enum
 
 #define kDNSServiceMaxDomainName 1005
 
-/* 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
+/*
+ * 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 pass kDNSServiceInterfaceIndexLocalOnly when browsing.
+ * 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.
+ * Note that to discover these special non-public services, the browsing
+ * client also has to explicitly use kDNSServiceInterfaceIndexLocalOnly in its
+ * DNSServiceBrowse() call. These special non-public services are not reported to
+ * other clients on the same machine using interface index 0 or other index values.
+ * 
+ * If the client passes kDNSServiceInterfaceIndexLocalOnly when browsing
+ * then it will find only records registered on that same local machine.
+ * Note that this is *not* exactly symmetrical with the registering case:
+ * Services advertised using LocalOnly are ONLY discovered by clients browsing
+ * on LocalOnly; in contrast, clients browsing on LocalOnly find ALL services
+ * advertised by this machine, not only those advertised on LocalOnly.
+ * 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.
  */
 
 #define kDNSServiceInterfaceIndexAny 0
-#define kDNSServiceInterfaceIndexLocalOnly ( (uint32_t) ~0 )
+#define kDNSServiceInterfaceIndexLocalOnly ( (uint32_t) -1 )
 
 
 typedef uint32_t DNSServiceFlags;
@@ -232,7 +356,7 @@ typedef int32_t DNSServiceErrorType;
  *                  error.
  */
 
-int DNSServiceRefSockFD(DNSServiceRef sdRef);
+int DNSSD_API DNSServiceRefSockFD(DNSServiceRef sdRef);
 
 
 /* DNSServiceProcessResult()
@@ -253,7 +377,7 @@ int DNSServiceRefSockFD(DNSServiceRef sdRef);
  *                  an error code indicating the specific failure that occurred.
  */
 
-DNSServiceErrorType DNSServiceProcessResult(DNSServiceRef sdRef);
+DNSServiceErrorType DNSSD_API DNSServiceProcessResult(DNSServiceRef sdRef);
 
 
 /* DNSServiceRefDeallocate()
@@ -282,7 +406,7 @@ DNSServiceErrorType DNSServiceProcessResult(DNSServiceRef sdRef);
  *
  */
 
-void DNSServiceRefDeallocate(DNSServiceRef sdRef);
+void DNSSD_API DNSServiceRefDeallocate(DNSServiceRef sdRef);
 
 
 /*********************************************************************************************
@@ -294,11 +418,16 @@ void 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:
  *
@@ -321,7 +450,7 @@ void DNSServiceRefDeallocate(DNSServiceRef sdRef);
  *
  */
 
-typedef void (*DNSServiceDomainEnumReply)
+typedef void (DNSSD_API *DNSServiceDomainEnumReply)
     (
     DNSServiceRef                       sdRef,
     DNSServiceFlags                     flags,
@@ -335,8 +464,10 @@ typedef void (*DNSServiceDomainEnumReply)
 /* DNSServiceEnumerateDomains() Parameters:
  *
  *
- * sdRef:           A pointer to an uninitialized DNSServiceRef.  May be passed to
- *                  DNSServiceRefDeallocate() to cancel the enumeration.
+ * 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().
  *
  * flags:           Possible values are:
  *                  kDNSServiceFlagsBrowseDomains to enumerate domains recommended for browsing.
@@ -346,7 +477,7 @@ typedef void (*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.
+ *                  all interfaces. See "Constants for specifying an interface index" for more details.
  *
  * callBack:        The function to be called when a domain is found or the call asynchronously
  *                  fails.
@@ -360,7 +491,7 @@ typedef void (*DNSServiceDomainEnumReply)
  *                  is not initialized.)
  */
 
-DNSServiceErrorType DNSServiceEnumerateDomains
+DNSServiceErrorType DNSSD_API DNSServiceEnumerateDomains
     (
     DNSServiceRef                       *sdRef,
     DNSServiceFlags                     flags,
@@ -403,7 +534,7 @@ DNSServiceErrorType DNSServiceEnumerateDomains
  *
  */
 
-typedef void (*DNSServiceRegisterReply)
+typedef void (DNSSD_API *DNSServiceRegisterReply)
     (
     DNSServiceRef                       sdRef,
     DNSServiceFlags                     flags,
@@ -417,15 +548,15 @@ typedef void (*DNSServiceRegisterReply)
 
 /* DNSServiceRegister()  Parameters:
  *
- * sdRef:           A pointer to an uninitialized DNSServiceRef.  If this call succeeds, the reference
- *                  may be passed to
- *                  DNSServiceRefDeallocate() to deregister the service.
+ * sdRef:           A pointer to an uninitialized DNSServiceRef. If the call succeeds 
+ *                  then it initializes the DNSServiceRef, returns kDNSServiceErr_NoError,
+ *                  and the registration will remain active indefinitely until the client
+ *                  terminates it by passing this DNSServiceRef to DNSServiceRefDeallocate().
  *
  * interfaceIndex:  If non-zero, specifies the interface on which to register the service
  *                  (the index for a given interface is determined via the if_nametoindex()
  *                  family of calls.)  Most applications will pass 0 to register on all
- *                  available interfaces.  Pass -1 to register a service only on the local
- *                  machine (service will not be visible to remote hosts.)
+ *                  available interfaces. See "Constants for specifying an interface index" for more details.
  *
  * flags:           Indicates the renaming behavior on name conflict (most applications
  *                  will pass 0).  See flag definitions above for details.
@@ -478,7 +609,7 @@ typedef void (*DNSServiceRegisterReply)
  *
  */
 
-DNSServiceErrorType DNSServiceRegister
+DNSServiceErrorType DNSSD_API DNSServiceRegister
     (
     DNSServiceRef                       *sdRef,
     DNSServiceFlags                     flags,
@@ -514,19 +645,19 @@ DNSServiceErrorType DNSServiceRegister
  *
  * flags:           Currently ignored, reserved for future use.
  *
- * rrtype:          The type of the record (e.g. TXT, SRV, etc), as defined in nameser.h.
+ * rrtype:          The type of the record (e.g. kDNSServiceType_TXT, kDNSServiceType_SRV, etc)
  *
  * 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.
+ * ttl:             The time to live of the resource record, in seconds.  Pass 0 to use a default value.
  *
  * return value:    Returns kDNSServiceErr_NoError on success, otherwise returns an
  *                  error code indicating the error that occurred (the RecordRef is not initialized).
  */
 
-DNSServiceErrorType DNSServiceAddRecord
+DNSServiceErrorType DNSSD_API DNSServiceAddRecord
     (
     DNSServiceRef                       sdRef,
     DNSRecordRef                        *RecordRef,
@@ -566,7 +697,7 @@ DNSServiceErrorType DNSServiceAddRecord
  *                  error code indicating the error that occurred.
  */
 
-DNSServiceErrorType DNSServiceUpdateRecord
+DNSServiceErrorType DNSSD_API DNSServiceUpdateRecord
     (
     DNSServiceRef                       sdRef,
     DNSRecordRef                        RecordRef,     /* may be NULL */
@@ -598,7 +729,7 @@ DNSServiceErrorType DNSServiceUpdateRecord
  *                  error code indicating the error that occurred.
  */
 
-DNSServiceErrorType DNSServiceRemoveRecord
+DNSServiceErrorType DNSSD_API DNSServiceRemoveRecord
     (
     DNSServiceRef                 sdRef,
     DNSRecordRef                  RecordRef,
@@ -629,19 +760,29 @@ DNSServiceErrorType DNSServiceRemoveRecord
  *                  indicate the failure that occurred.  Other parameters are undefined if
  *                  the errorCode is nonzero.
  *
- * serviceName:     The service name discovered.
+ * serviceName:     The discovered service name. This name should be displayed to the user,
+ *                  and stored for subsequent use in the DNSServiceResolve() call.
  *
- * regtype:         The service type, as passed in to DNSServiceBrowse().
+ * 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.
  *
- * 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.)
+ * 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.
  *
  * context:         The context pointer that was passed to the callout.
  *
  */
 
-typedef void (*DNSServiceBrowseReply)
+typedef void (DNSSD_API *DNSServiceBrowseReply)
     (
     DNSServiceRef                       sdRef,
     DNSServiceFlags                     flags,
@@ -656,15 +797,17 @@ typedef void (*DNSServiceBrowseReply)
 
 /* DNSServiceBrowse() Parameters:
  *
- * sdRef:           A pointer to an uninitialized DNSServiceRef.  May be passed to
- *                  DNSServiceRefDeallocate() to terminate the browse.
+ * 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().
  *
  * flags:           Currently ignored, reserved for future use.
  *
  * interfaceIndex:  If non-zero, specifies the interface on which to browse for services
  *                  (the index for a given interface is determined via the if_nametoindex()
  *                  family of calls.)  Most applications will pass 0 to browse on all available
- *                  interfaces.  Pass -1 to only browse for services provided on the local host.
+ *                  interfaces. See "Constants for specifying an interface index" for more details.
  *
  * regtype:         The service type being browsed for followed by the protocol, separated by a
  *                  dot (e.g. "_ftp._tcp").  The transport protocol must be "_tcp" or "_udp".
@@ -685,7 +828,7 @@ typedef void (*DNSServiceBrowseReply)
  *                  is not initialized.)
  */
 
-DNSServiceErrorType DNSServiceBrowse
+DNSServiceErrorType DNSSD_API DNSServiceBrowse
     (
     DNSServiceRef                       *sdRef,
     DNSServiceFlags                     flags,
@@ -725,12 +868,10 @@ DNSServiceErrorType DNSServiceBrowse
  *                  the errorCode is nonzero.
  *
  * fullname:        The full service domain name, in the form <servicename>.<protocol>.<domain>.
- *                  (Any literal dots (".") are escaped with a backslash ("\."), and literal
- *                  backslashes are escaped with a second backslash ("\\"), e.g. a web server
- *                  named "Dr. Pepper" would have the fullname  "Dr\.\032Pepper._http._tcp.local.").
- *                  This is the appropriate format to pass to standard system DNS APIs such as
- *                  res_query(), or to the special-purpose functions included in this API that
- *                  take fullname parameters.
+ *                  (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.)
  *
  * 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.
@@ -746,7 +887,7 @@ DNSServiceErrorType DNSServiceBrowse
  *
  */
 
-typedef void (*DNSServiceResolveReply)
+typedef void (DNSSD_API *DNSServiceResolveReply)
     (
     DNSServiceRef                       sdRef,
     DNSServiceFlags                     flags,
@@ -763,23 +904,29 @@ typedef void (*DNSServiceResolveReply)
 
 /* DNSServiceResolve() Parameters
  *
- * sdRef:           A pointer to an uninitialized DNSServiceRef.  May be passed to
- *                  DNSServiceRefDeallocate() to terminate the resolve.
+ * sdRef:           A pointer to an uninitialized DNSServiceRef. If the call succeeds 
+ *                  then it initializes the DNSServiceRef, returns kDNSServiceErr_NoError,
+ *                  and the resolve operation will run indefinitely until the client
+ *                  terminates it by passing this DNSServiceRef to DNSServiceRefDeallocate().
  *
  * flags:           Currently ignored, reserved for future use.
  *
- * 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.
+ * 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.
  *
- * name:            The servicename to be resolved.
+ * name:            The name 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".
+ * regtype:         The type 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.
+ * domain:          The domain of the service instance to be resolved, as reported to the
+ *                  DNSServiceBrowseReply() callback.
  *
  * callBack:        The function to be called when a result is found, or if the call
  *                  asynchronously fails.
@@ -793,7 +940,7 @@ typedef void (*DNSServiceResolveReply)
  *                  is not initialized.)
  */
 
-DNSServiceErrorType DNSServiceResolve
+DNSServiceErrorType DNSSD_API DNSServiceResolve
     (
     DNSServiceRef                       *sdRef,
     DNSServiceFlags                     flags,
@@ -812,28 +959,6 @@ DNSServiceErrorType 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
@@ -851,7 +976,7 @@ DNSServiceErrorType DNSServiceResolve
  *                  case the DNSServiceRef is not initialized).
  */
 
-DNSServiceErrorType DNSServiceCreateConnection(DNSServiceRef *sdRef);
+DNSServiceErrorType DNSSD_API DNSServiceCreateConnection(DNSServiceRef *sdRef);
 
 
 /* DNSServiceRegisterRecord
@@ -881,7 +1006,7 @@ DNSServiceErrorType DNSServiceCreateConnection(DNSServiceRef *sdRef);
  *
  */
 
- typedef void (*DNSServiceRegisterRecordReply)
+ typedef void (DNSSD_API *DNSServiceRegisterRecordReply)
     (
     DNSServiceRef                       sdRef,
     DNSRecordRef                        RecordRef,
@@ -907,21 +1032,19 @@ DNSServiceErrorType 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.
- *                  Passing -1 causes the record to only be visible on the local host.
+ *                  See "Constants for specifying an interface index" for more details.
  *
  * fullname:        The full domain name of the resource record.
  *
- * rrtype:          The numerical type of the resource record (e.g. PTR, SRV, etc), as defined
- *                  in nameser.h.
+ * rrtype:          The numerical type of the resource record (e.g. kDNSServiceType_PTR, kDNSServiceType_SRV, etc)
  *
- * rrclass:         The class of the resource record, as defined in nameser.h (usually 1 for the
- *                  Internet class).
+ * rrclass:         The class of the resource record (usually kDNSServiceClass_IN)
  *
  * 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.
+ * ttl:             The time to live of the resource record, in seconds.  Pass 0 to use a default value.
  *
  * callBack:        The function to be called when a result is found, or if the call
  *                  asynchronously fails (e.g. because of a name conflict.)
@@ -935,7 +1058,7 @@ DNSServiceErrorType DNSServiceCreateConnection(DNSServiceRef *sdRef);
  *                  not initialized.)
  */
 
-DNSServiceErrorType DNSServiceRegisterRecord
+DNSServiceErrorType DNSSD_API DNSServiceRegisterRecord
     (
     DNSServiceRef                       sdRef,
     DNSRecordRef                        *RecordRef,
@@ -967,6 +1090,7 @@ DNSServiceErrorType 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
@@ -974,9 +1098,9 @@ DNSServiceErrorType DNSServiceRegisterRecord
  *
  * fullname:        The resource record's full domain name.
  *
- * rrtype:          The resource record's type (e.g. PTR, SRV, etc) as defined in nameser.h.
+ * rrtype:          The resource record's type (e.g. kDNSServiceType_PTR, kDNSServiceType_SRV, etc)
  *
- * rrclass:         The class of the resource record, as defined in nameser.h (usually 1).
+ * rrclass:         The class of the resource record (usually kDNSServiceClass_IN).
  *
  * rdlen:           The length, in bytes, of the resource record rdata.
  *
@@ -988,7 +1112,7 @@ DNSServiceErrorType DNSServiceRegisterRecord
  *
  */
 
-typedef void (*DNSServiceQueryRecordReply)
+typedef void (DNSSD_API *DNSServiceQueryRecordReply)
     (
     DNSServiceRef                       DNSServiceRef,
     DNSServiceFlags                     flags,
@@ -1006,7 +1130,10 @@ typedef void (*DNSServiceQueryRecordReply)
 
 /* DNSServiceQueryRecord() Parameters:
  *
- * sdRef:           A pointer to an uninitialized DNSServiceRef.
+ * sdRef:           A pointer to an uninitialized DNSServiceRef. If the call succeeds 
+ *                  then it initializes the DNSServiceRef, returns kDNSServiceErr_NoError,
+ *                  and the query operation will run indefinitely until the client
+ *                  terminates it by passing this DNSServiceRef to DNSServiceRefDeallocate().
  *
  * flags:           Pass kDNSServiceFlagsLongLivedQuery to create a "long-lived" unicast
  *                  query in a non-local domain.  Without setting this flag, unicast queries
@@ -1018,16 +1145,14 @@ typedef void (*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.  Passing -1 causes the name to be queried for only on the
- *                  local host.
+ *                  interfaces. See "Constants for specifying an interface index" for more details.
  *
  * fullname:        The full domain name of the resource record to be queried for.
  *
- * rrtype:          The numerical type of the resource record to be queried for (e.g. PTR, SRV, etc)
- *                  as defined in nameser.h.
+ * rrtype:          The numerical type of the resource record to be queried for
+ *                  (e.g. kDNSServiceType_PTR, kDNSServiceType_SRV, etc)
  *
- * rrclass:         The class of the resource record, as defined in nameser.h
- *                  (usually 1 for the Internet class).
+ * rrclass:         The class of the resource record (usually kDNSServiceClass_IN).
  *
  * callBack:        The function to be called when a result is found, or if the call
  *                  asynchronously fails.
@@ -1041,7 +1166,7 @@ typedef void (*DNSServiceQueryRecordReply)
  *                  is not initialized.)
  */
 
-DNSServiceErrorType DNSServiceQueryRecord
+DNSServiceErrorType DNSSD_API DNSServiceQueryRecord
     (
     DNSServiceRef                       *sdRef,
     DNSServiceFlags                     flags,
@@ -1065,11 +1190,14 @@ DNSServiceErrorType 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. PTR, SRV, etc) as defined in nameser.h.
+ * rrtype:          The resource record's type (e.g. kDNSServiceType_PTR, kDNSServiceType_SRV, etc)
  *
- * rrclass:         The class of the resource record, as defined in nameser.h (usually 1).
+ * rrclass:         The class of the resource record (usually kDNSServiceClass_IN).
  *
  * rdlen:           The length, in bytes, of the resource record rdata.
  *
@@ -1077,7 +1205,7 @@ DNSServiceErrorType DNSServiceQueryRecord
  *
  */
 
-void DNSServiceReconfirmRecord
+void DNSSD_API DNSServiceReconfirmRecord
     (
     DNSServiceFlags                    flags,
     uint32_t                           interfaceIndex,
@@ -1107,21 +1235,21 @@ void 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 slashes must NOT be escaped.
+ * service:         The service name - any dots or backslashes 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".  Any literal dots or backslashes
- *                  must be escaped.
+ * domain:          The domain name, e.g. "apple.com.".  Literal dots or backslashes,
+ *                  if any, must be escaped, e.g. "1st\. Floor.apple.com."
  *
  * return value:    Returns 0 on success, -1 on error.
  *
  */
 
-int DNSServiceConstructFullName
+int DNSSD_API DNSServiceConstructFullName
     (
     char                            *fullName,
     const char                      *service,      /* may be NULL */
@@ -1157,7 +1285,7 @@ int DNSServiceConstructFullName
  * Note: Represents a DNS-SD TXT record.
  */
 
-typedef struct _TXTRecordRef_t { char private[16]; } TXTRecordRef;
+typedef struct _TXTRecordRef_t { char privatedata[16]; } TXTRecordRef;
 
 
 /* TXTRecordCreate()
@@ -1187,6 +1315,11 @@ typedef struct _TXTRecordRef_t { char private[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.
@@ -1196,7 +1329,7 @@ typedef struct _TXTRecordRef_t { char private[16]; } TXTRecordRef;
  *                  the TXTRecordRef.
  */
 
-void TXTRecordCreate
+void DNSSD_API TXTRecordCreate
     (
     TXTRecordRef     *txtRecord,
     uint16_t         bufferLen,
@@ -1214,7 +1347,7 @@ void TXTRecordCreate
  *
  */
 
-void TXTRecordDeallocate
+void DNSSD_API TXTRecordDeallocate
     (
     TXTRecordRef     *txtRecord
     );
@@ -1237,7 +1370,7 @@ void TXTRecordDeallocate
  *
  * key:             A null-terminated string which only contains printable ASCII
  *                  values (0x20-0x7E), excluding '=' (0x3D). Keys should be
- *                  14 characters or less (not counting the terminating null).
+ *                  8 characters or less (not counting the terminating null).
  *
  * valueSize:       The size of the value.
  *
@@ -1257,7 +1390,7 @@ void TXTRecordDeallocate
  *                  exceed the available storage.
  */
 
-DNSServiceErrorType TXTRecordSetValue
+DNSServiceErrorType DNSSD_API TXTRecordSetValue
     (
     TXTRecordRef     *txtRecord,
     const char       *key,
@@ -1281,7 +1414,7 @@ DNSServiceErrorType TXTRecordSetValue
  *
  */
 
-DNSServiceErrorType TXTRecordRemoveValue
+DNSServiceErrorType DNSSD_API TXTRecordRemoveValue
     (
     TXTRecordRef     *txtRecord,
     const char       *key
@@ -1301,7 +1434,7 @@ DNSServiceErrorType TXTRecordRemoveValue
  *
  */
 
-uint16_t TXTRecordGetLength
+uint16_t DNSSD_API TXTRecordGetLength
     (
     const TXTRecordRef *txtRecord
     );
@@ -1319,7 +1452,7 @@ uint16_t TXTRecordGetLength
  *
  */
 
-const void * TXTRecordGetBytesPtr
+const void * DNSSD_API TXTRecordGetBytesPtr
     (
     const TXTRecordRef *txtRecord
     );
@@ -1374,7 +1507,7 @@ const void * TXTRecordGetBytesPtr
  *
  */
 
-int TXTRecordContainsKey
+int DNSSD_API TXTRecordContainsKey
     (
     uint16_t         txtLen,
     const void       *txtRecord,
@@ -1403,7 +1536,7 @@ int TXTRecordContainsKey
  *                  For non-empty value, valueLen will be length of value data.
  */
 
-const void * TXTRecordGetValuePtr
+const void * DNSSD_API TXTRecordGetValuePtr
     (
     uint16_t         txtLen,
     const void       *txtRecord,
@@ -1425,7 +1558,7 @@ const void * TXTRecordGetValuePtr
  *
  */
 
-uint16_t TXTRecordGetCount
+uint16_t DNSSD_API TXTRecordGetCount
     (
     uint16_t         txtLen,
     const void       *txtRecord
@@ -1456,7 +1589,7 @@ uint16_t 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
- *                  14 characters or less. To hold the maximum possible
+ *                  8 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.
@@ -1470,7 +1603,7 @@ uint16_t TXTRecordGetCount
  *                  TXTRecordGetCount()-1.
  */
 
-DNSServiceErrorType TXTRecordGetItemAtIndex
+DNSServiceErrorType DNSSD_API TXTRecordGetItemAtIndex
     (
     uint16_t         txtLen,
     const void       *txtRecord,
@@ -1481,6 +1614,39 @@ DNSServiceErrorType 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/dnsextd.8 b/mDNSShared/dnsextd.8
new file mode 100644
index 0000000..12009f6
--- /dev/null
+++ b/mDNSShared/dnsextd.8
@@ -0,0 +1,80 @@
+.\" 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: dnsextd.8,v $
+.\" Revision 1.1  2004/08/15 18:49:18  cheshire
+.\" <rdar://problem/3763030> No man page for dnsextd
+.\"
+.\"
+.\"
+.Dd August 2004             \" Date
+.Dt dnsextd 8               \" Document Title
+.Os Darwin                  \" Operating System
+.\"
+.Sh NAME
+.Nm dnsextd
+.Nd BIND Extension Daemon   \" Name Description for whatis database
+.\" 
+.Sh SYNOPSIS
+.Nm
+.\"
+.Sh DESCRIPTION
+.Nm
+is a daemon invoked at boot time, running alongside BIND 9,
+to implement two EDNS0 extensions to the standard DNS protocol.
+.Pp
+.Nm
+allows clients to perform DNS Updates with an attached lease lifetime,
+so that if the client crashes or is disconnected from the network, its
+address records will be automatically deleted after the lease expires.
+.Pp
+.Nm
+allows clients to perform long-lived queries. Instead of rapidly polling
+the server to discover when information changes, long-lived queries
+enable a client to indicate its interest in some set of data, and then
+be notified asynchronously by the server whenever any of that data changes.
+.Pp
+.Nm
+has no user-specifiable command-line argument, and users should not run
+.Nm
+manually.
+.\"
+.Sh SEE ALSO
+.Xr mDNS 1
+.Xr mDNSResponder 8
+.Pp
+For information on Dynamic DNS Update, see RFC 2136
+"Dynamic Updates in the Domain Name System (DNS UPDATE)"
+.Pp
+For information on Dynamic DNS Update Leases, see
+.Pa http://files.dns-sd.org/draft-dns-update-leases.txt
+.Pp
+For information on Long-Lived Queries, see
+.Pa http://files.dns-sd.org/draft-dns-llq.txt
+.\"
+.Sh BUGS
+.Nm
+bugs are tracked in Apple Radar component "mDNSResponder".
+.\"
+.Sh HISTORY
+The
+.Nm
+daemon first appeared in Mac OS X 10.4 (Tiger).
diff --git a/mDNSShared/dnssd_clientlib.c b/mDNSShared/dnssd_clientlib.c
index d5a0f04..40ab0d0 100755
--- a/mDNSShared/dnssd_clientlib.c
+++ b/mDNSShared/dnssd_clientlib.c
@@ -1,30 +1,47 @@
 /*
- * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
+ * 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@
+ * 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.
 
    Change History (most recent first):
 
 $Log: dnssd_clientlib.c,v $
+Revision 1.9  2004/10/06 02:22:19  cheshire
+Changed MacRoman copyright symbol (should have been UTF-8 in any case :-) to ASCII-compatible "(c)"
+
+Revision 1.8  2004/10/01 22:15:55  rpantos
+rdar://problem/3824265: Replace APSL in client lib with BSD license.
+
+Revision 1.7  2004/06/26 03:16:34  shersche
+clean up warning messages on Win32 platform
+
+Submitted by: herscher
+
+Revision 1.6  2004/06/12 01:09:45  cheshire
+To be callable from the broadest range of clients on Windows (e.g. Visual Basic, C#, etc.)
+API routines have to be declared as "__stdcall", instead of the C default, "__cdecl"
+
 Revision 1.5  2004/05/25 18:29:33  cheshire
 Move DNSServiceConstructFullName() from dnssd_clientstub.c to dnssd_clientlib.c,
 so that it's also accessible to dnssd_clientshim.c (single address space) clients.
@@ -53,6 +70,11 @@ like Muse Research who want to be able to use mDNS/DNS-SD from GPL-licensed code
 #pragma export on
 #endif
 
+#if defined(_WIN32)
+// disable warning "conversion from <data> to uint16_t"
+#pragma warning(disable:4244)
+#endif
+
 /*********************************************************************************************
  *
  *  Supporting Functions
@@ -86,7 +108,7 @@ static uint8_t *InternalTXTRecordSearch
 	{
 	uint8_t *p = (uint8_t*)txtRecord;
 	uint8_t *e = p + txtLen;
-	*keylen = strlen(key);
+	*keylen = (unsigned long) strlen(key);
 	while (p<e)
 		{
 		uint8_t *x = p;
@@ -103,7 +125,7 @@ static uint8_t *InternalTXTRecordSearch
  *
  *********************************************************************************************/
 
-int DNSServiceConstructFullName
+int DNSSD_API DNSServiceConstructFullName
 	(
 	char                      *fullName,
 	const char                *service,      /* may be NULL */
@@ -137,7 +159,7 @@ int DNSServiceConstructFullName
 		}
 
 	if (!regtype) return -1;
-	len = strlen(regtype);
+	len = (unsigned long) strlen(regtype);
 	if (DomainEndsInDot(regtype)) len--;
 	if (len < 6) return -1; // regtype must be at least "x._udp" or "x._tcp"
 	if (strncmp((regtype + len - 4), "_tcp", 4) && strncmp((regtype + len - 4), "_udp", 4)) return -1;
diff --git a/mDNSShared/dnssd_clientshim.c b/mDNSShared/dnssd_clientshim.c
index 98b187f..121b0df 100644
--- a/mDNSShared/dnssd_clientshim.c
+++ b/mDNSShared/dnssd_clientshim.c
@@ -3,8 +3,6 @@
  * 
  * @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,8 +21,8 @@
  * @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
+ * and an implementation of mDNSCore ("mDNSEmbeddedAPI.h" APIs) in the same address space.
+ * When the client calls a dns_sd.h function, the shim calls the corresponding mDNSEmbeddedAPI.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,
@@ -33,6 +31,23 @@
 	Change History (most recent first):
 
 $Log: dnssd_clientshim.c,v $
+Revision 1.7  2004/12/10 04:08:43  cheshire
+Added comments about autoname and autorename
+
+Revision 1.6  2004/10/19 21:33:22  cheshire
+<rdar://problem/3844991> Cannot resolve non-local registrations using the mach API
+Added flag 'kDNSServiceFlagsForceMulticast'. Passing through an interface id for a unicast name
+doesn't force multicast unless you set this flag to indicate explicitly that this is what you want
+
+Revision 1.5  2004/09/21 23:29:51  cheshire
+<rdar://problem/3680045> DNSServiceResolve should delay sending packets
+
+Revision 1.4  2004/09/17 01:08:55  cheshire
+Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
+  The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
+  declared in that file are ONLY appropriate to single-address-space embedded applications.
+  For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
+
 Revision 1.3  2004/05/27 06:26:31  cheshire
 Add shim for DNSServiceQueryRecord()
 
@@ -46,7 +61,7 @@ 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
+#include "mDNSEmbeddedAPI.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
@@ -75,8 +90,8 @@ typedef struct
 	mDNS_DirectOP_Dispose  *disposefn;
 	DNSServiceRegisterReply callback;
 	void                   *context;
-	mDNSBool                autoname;
-	mDNSBool                autorename;
+	mDNSBool                autoname;		// Set if this name is tied to the Computer Name
+	mDNSBool                autorename;		// Set if we just got a name conflict and now need to automatically pick a new name
 	domainlabel             name;
 	ServiceRecordSet        s;
 	} mDNS_DirectOP_Register;
@@ -431,7 +446,7 @@ DNSServiceErrorType DNSServiceBrowse
 	x->q.QuestionContext = x;
 
 	// Do the operation
-	err = mDNS_StartBrowse(&mDNSStorage, &x->q, &t, &d, mDNSInterface_Any, FoundInstance, x);
+	err = mDNS_StartBrowse(&mDNSStorage, &x->q, &t, &d, mDNSInterface_Any, (flags & kDNSServiceFlagsForceMulticast) != 0, FoundInstance, x);
 	if (err) { mDNSPlatformMemFree(x); errormsg = "mDNS_StartBrowse"; goto fail; }
 
 	// Succeeded: Wrap up and return
@@ -524,6 +539,9 @@ DNSServiceErrorType DNSServiceResolve
 	AssignDomainName(x->qSRV.qname, srv);
 	x->qSRV.qtype               = kDNSType_SRV;
 	x->qSRV.qclass              = kDNSClass_IN;
+	x->qSRV.LongLived           = mDNSfalse;
+	x->qSRV.ExpectUnique        = mDNStrue;
+	x->qSRV.ForceMCast          = mDNSfalse;
 	x->qSRV.QuestionCallback    = FoundServiceInfo;
 	x->qSRV.QuestionContext     = x;
 
@@ -533,6 +551,9 @@ DNSServiceErrorType DNSServiceResolve
 	AssignDomainName(x->qTXT.qname, srv);
 	x->qTXT.qtype               = kDNSType_TXT;
 	x->qTXT.qclass              = kDNSClass_IN;
+	x->qTXT.LongLived           = mDNSfalse;
+	x->qTXT.ExpectUnique        = mDNStrue;
+	x->qTXT.ForceMCast          = mDNSfalse;
 	x->qTXT.QuestionCallback    = FoundServiceInfo;
 	x->qTXT.QuestionContext     = x;
 
@@ -652,6 +673,9 @@ DNSServiceErrorType DNSServiceQueryRecord
 	MakeDomainNameFromDNSNameString(&x->q.qname, fullname);
 	x->q.qtype               = rrtype;
 	x->q.qclass              = rrclass;
+	x->q.LongLived           = (flags & kDNSServiceFlagsLongLivedQuery) != 0;
+	x->q.ExpectUnique        = mDNSfalse;
+	x->q.ForceMCast          = (flags & kDNSServiceFlagsForceMulticast) != 0;
 	x->q.QuestionCallback    = DNSServiceQueryRecordResponse;
 	x->q.QuestionContext     = x;
 
diff --git a/mDNSShared/dnssd_clientstub.c b/mDNSShared/dnssd_clientstub.c
index 6173ca7..d060a66 100755
--- a/mDNSShared/dnssd_clientstub.c
+++ b/mDNSShared/dnssd_clientstub.c
@@ -1,30 +1,104 @@
-/*
- * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
+/* -*- Mode: C; tab-width: 4 -*-
  *
- * @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@
+ * 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.
 
     Change History (most recent first):
 
 $Log: dnssd_clientstub.c,v $
+Revision 1.40  2004/11/23 03:39:47  cheshire
+Let interface name/index mapping capability live directly in JNISupport.c,
+instead of having to call through to the daemon via IPC to get this information.
+
+Revision 1.39  2004/11/12 03:22:00  rpantos
+rdar://problem/3809541 Add DNSSDMapIfIndexToName, DNSSDMapNameToIfIndex.
+
+Revision 1.38  2004/11/02 02:51:23  cheshire
+<rdar://problem/3526342> Remove overly-restrictive flag checks
+
+Revision 1.37  2004/10/14 01:43:35  cheshire
+Fix opaque port passing problem
+
+Revision 1.36  2004/10/06 02:22:19  cheshire
+Changed MacRoman copyright symbol (should have been UTF-8 in any case :-) to ASCII-compatible "(c)"
+
+Revision 1.35  2004/10/01 22:15:55  rpantos
+rdar://problem/3824265: Replace APSL in client lib with BSD license.
+
+Revision 1.34  2004/09/17 22:36:13  cheshire
+Add comment explaining that deliver_request frees the message it sends
+
+Revision 1.33  2004/09/17 01:17:31  ksekar
+Remove double-free of msg header, freed automatically by deliver_request()
+
+Revision 1.32  2004/09/17 01:08:55  cheshire
+Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
+  The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
+  declared in that file are ONLY appropriate to single-address-space embedded applications.
+  For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
+
+Revision 1.31  2004/09/16 23:37:19  cheshire
+Free hdr before returning
+
+Revision 1.30  2004/09/16 23:14:24  cheshire
+Changes for Windows compatibility
+
+Revision 1.29  2004/09/16 21:46:38  ksekar
+<rdar://problem/3665304> Need SPI for LoginWindow to associate a UID with a Wide Area Rendezvous domain
+
+Revision 1.28  2004/08/11 17:10:04  cheshire
+Fix signed/unsigned warnings
+
+Revision 1.27  2004/08/11 00:54:16  cheshire
+Change "hdr->op.request_op" to just "hdr->op"
+
+Revision 1.26  2004/07/26 06:07:27  shersche
+fix bugs when using an error socket to communicate with the daemon
+
+Revision 1.25  2004/07/26 05:54:02  shersche
+DNSServiceProcessResult() returns NoError if socket read returns EWOULDBLOCK
+
+Revision 1.24  2004/07/20 06:46:21  shersche
+<rdar://problem/3730123> fix endless loop in my_read() if recv returns 0
+Bug #: 3730123
+
+Revision 1.23  2004/06/29 00:48:38  cheshire
+Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions;
+use an explicit while() loop instead.
+
+Revision 1.22  2004/06/26 03:16:34  shersche
+clean up warning messages on Win32 platform
+
+Submitted by: herscher
+
+Revision 1.21  2004/06/18 04:53:56  rpantos
+Use platform layer for socket types. Introduce USE_TCP_LOOPBACK. Remove dependency on mDNSEmbeddedAPI.h.
+
+Revision 1.20  2004/06/12 00:50:22  cheshire
+Changes for Windows compatibility
+
 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.
@@ -76,111 +150,348 @@ Update to APSL 2.0
  */
 
 #include <errno.h>
+#include <stdlib.h>
+#if defined(_WIN32)
+#include <winsock2.h>
+#include <windows.h>
+#define sockaddr_mdns sockaddr_in
+#define AF_MDNS AF_INET
+#else
 #include <sys/time.h>
 #include <sys/socket.h>
+#define sockaddr_mdns sockaddr_un
+#define AF_MDNS AF_LOCAL
+#endif
 
 #include "dnssd_ipc.h"
 
+#if defined(_WIN32)
+// disable warning: "'type cast' : from data pointer 'void *' to
+// function pointer"
+#pragma warning(disable:4055)
+
+// disable warning: "nonstandard extension, function/data pointer
+// conversion in expression"
+#pragma warning(disable:4152)
+
+static int g_initWinsock = 0;
+#endif
+
 
 #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);
-// 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
+    dnssd_sock_t sockfd;  // connected socket between client and daemon
+    uint32_t op;          // request_op_t or reply_op_t
     process_reply_callback process_reply;
     void *app_callback;
     void *app_context;
     uint32_t max_index;  //largest assigned record index - 0 if no additl. recs registered
-    } _DNSServiceRef_t;			
+    } _DNSServiceRef_t;
 
 typedef struct _DNSRecordRef_t
     {
     void *app_context;
     DNSServiceRegisterRecordReply app_callback;
     DNSRecordRef recref;
-    int record_index;  // index is unique to the ServiceDiscoveryRef
+    uint32_t record_index;  // index is unique to the ServiceDiscoveryRef
     DNSServiceRef sdr;
     } _DNSRecordRef_t;
 
-
 // exported functions
 
-int DNSServiceRefSockFD(DNSServiceRef sdRef)
+// write len bytes.  return 0 on success, -1 on error
+static int my_write(dnssd_sock_t sd, char *buf, int len)
+    {
+    // Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions; use an explicit while() loop instead.
+    //if (send(sd, buf, len, MSG_WAITALL) != len)   return -1;
+    while (len)
+    	{
+    	ssize_t num_written = send(sd, buf, len, 0);
+    	if (num_written < 0 || num_written > len) return -1;
+    	buf += num_written;
+    	len -= num_written;
+    	}
+    return 0;
+    }
+
+// read len bytes.  return 0 on success, -1 on error
+static int my_read(dnssd_sock_t sd, char *buf, int len)
+    {
+    // Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions; use an explicit while() loop instead.
+    //if (recv(sd, buf, len, MSG_WAITALL) != len)  return -1;
+    while (len)
+    	{
+    	ssize_t num_read = recv(sd, buf, len, 0);
+    	if ((num_read == 0) || (num_read < 0) || (num_read > len)) return -1;
+    	buf += num_read;
+    	len -= num_read;
+    	}
+    return 0;
+    }
+
+/* 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(uint32_t op, size_t *len, char **data_start, int reuse_socket)
+    {
+    char *msg = NULL;
+    ipc_msg_hdr *hdr;
+    int datalen;
+    char ctrl_path[256];
+
+    if (!reuse_socket)
+        {
+#if defined(USE_TCP_LOOPBACK)
+		*len += 2;	// Allocate space for two-byte port number
+#else
+		struct timeval time;
+		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;
+#endif
+        }
+
+    datalen = (int) *len;
+    *len += sizeof(ipc_msg_hdr);
+
+    // write message to buffer
+    msg = malloc(*len);
+    if (!msg) return NULL;
+
+    bzero(msg, *len);
+    hdr = (void *)msg;
+    hdr->datalen = datalen;
+    hdr->version = VERSION;
+    hdr->op = op;
+    if (reuse_socket) hdr->flags |= IPC_FLAGS_REUSE_SOCKET;
+    *data_start = msg + sizeof(ipc_msg_hdr);
+#if defined(USE_TCP_LOOPBACK)
+	// Put dummy data in for the port, since we don't know what
+	// it is yet.  The data will get filled in before we
+	// send the message. This happens in deliver_request().
+	if (!reuse_socket)	put_short(0, data_start);
+#else
+    if (!reuse_socket)  put_string(ctrl_path, data_start);
+#endif
+    return hdr;
+    }
+
+    // return a connected service ref (deallocate with DNSServiceRefDeallocate)
+static DNSServiceRef connect_to_server(void)
+    {
+	dnssd_sockaddr_t saddr;
+	DNSServiceRef sdr;
+
+#if defined(_WIN32)
+	if (!g_initWinsock)
+		{
+		WSADATA wsaData;
+		DNSServiceErrorType err;
+		
+		g_initWinsock = 1;
+
+		err = WSAStartup( MAKEWORD( 2, 2 ), &wsaData );
+
+		if (err != 0) return NULL;
+		}
+#endif
+
+	sdr = malloc(sizeof(_DNSServiceRef_t));
+	if (!sdr) return(NULL);
+	sdr->sockfd = socket(AF_DNSSD, SOCK_STREAM, 0);
+	if (sdr->sockfd == dnssd_InvalidSocket) { free(sdr); return NULL; }
+#if defined(USE_TCP_LOOPBACK)
+	saddr.sin_family		=	AF_INET;
+	saddr.sin_addr.s_addr	=	inet_addr(MDNS_TCP_SERVERADDR);
+	saddr.sin_port			=	htons(MDNS_TCP_SERVERPORT);
+#else
+	saddr.sun_family = AF_LOCAL;
+	strcpy(saddr.sun_path, MDNS_UDS_SERVERPATH);
+#endif
+	if (connect(sdr->sockfd, (struct sockaddr *) &saddr, sizeof(saddr)) < 0) { free(sdr); return NULL; }
+    return sdr;
+	}
+
+static DNSServiceErrorType deliver_request(void *msg, DNSServiceRef sdr, int reuse_sd)
+    {
+    ipc_msg_hdr *hdr = msg;
+    uint32_t datalen = hdr->datalen;
+    dnssd_sockaddr_t caddr, daddr;  // (client and daemon address structs)
+    char *data = (char *)msg + sizeof(ipc_msg_hdr);
+    dnssd_sock_t listenfd = dnssd_InvalidSocket, errsd = dnssd_InvalidSocket;
+	int ret, len = sizeof(caddr);
+    DNSServiceErrorType err = kDNSServiceErr_Unknown;
+
+    if (!hdr || sdr->sockfd < 0) return kDNSServiceErr_Unknown;
+
+	if (!reuse_sd)
+		{
+        // setup temporary error socket
+        if ((listenfd = socket(AF_DNSSD, SOCK_STREAM, 0)) < 0)
+            goto cleanup;
+        bzero(&caddr, sizeof(caddr));
+
+#if defined(USE_TCP_LOOPBACK)
+			{
+			union { uint16_t s; u_char b[2]; } port;
+			caddr.sin_family      = AF_INET;
+			caddr.sin_port        = 0;
+			caddr.sin_addr.s_addr = inet_addr(MDNS_TCP_SERVERADDR);
+			ret = bind(listenfd, (struct sockaddr*) &caddr, sizeof(caddr));
+			if (ret < 0) goto cleanup;
+			if (getsockname(listenfd, (struct sockaddr*) &caddr, &len) < 0) goto cleanup;
+			listen(listenfd, 1);
+			port.s = caddr.sin_port;
+			data[0] = port.b[0];	// don't switch the byte order, as the
+			data[1] = port.b[1];	// daemon expects it in network byte order
+			}
+#else
+			{
+			mode_t mask = umask(0);
+			caddr.sun_family = AF_LOCAL;
+#ifndef NOT_HAVE_SA_LEN		// According to Stevens (section 3.2), there is no portable way to
+								// determine whether sa_len is defined on a particular platform.
+			caddr.sun_len = sizeof(struct sockaddr_un);
+#endif
+			strcpy(caddr.sun_path, data);
+			ret = bind(listenfd, (struct sockaddr *)&caddr, sizeof(caddr));
+			umask(mask);
+			if (ret < 0) goto cleanup;
+			listen(listenfd, 1);
+			}
+#endif
+		}
+
+	ConvertHeaderBytes(hdr);
+    if (my_write(sdr->sockfd, msg, datalen + sizeof(ipc_msg_hdr)) < 0)
+        goto cleanup;
+    free(msg);
+    msg = NULL;
+
+    if (reuse_sd) errsd = sdr->sockfd;
+    else
+        {
+        len = sizeof(daddr);
+        errsd = accept(listenfd, (struct sockaddr *)&daddr, &len);
+        if (errsd < 0)  goto cleanup;
+        }
+
+    if (my_read(errsd, (char*)&err, (int)sizeof(err)) < 0)
+        err = kDNSServiceErr_Unknown;
+    else
+    	err = ntohl(err);
+
+cleanup:
+    if (!reuse_sd && listenfd > 0) dnssd_close(listenfd);
+    if (!reuse_sd && errsd > 0) dnssd_close(errsd);
+#if !defined(USE_TCP_LOOPBACK)
+    if (!reuse_sd && data) unlink(data);
+#endif
+    if (msg) free(msg);
+    return err;
+    }
+
+int DNSSD_API DNSServiceRefSockFD(DNSServiceRef sdRef)
     {
     if (!sdRef) return -1;
-    return sdRef->sockfd;
+    return (int) sdRef->sockfd;
     }
 
 // handle reply from server, calling application client callback.  If there is no reply
 // from the daemon on the socket contained in sdRef, the call will block.
-DNSServiceErrorType DNSServiceProcessResult(DNSServiceRef sdRef)
+DNSServiceErrorType DNSSD_API DNSServiceProcessResult(DNSServiceRef sdRef)
     {
     ipc_msg_hdr hdr;
     char *data;
 
-    if (!sdRef || sdRef->sockfd < 0 || !sdRef->process_reply) 
+    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 (my_read(sdRef->sockfd, (void *)&hdr, sizeof(hdr)) < 0)
+		// return NoError on EWOULDBLOCK. This will handle the case
+		// where a non-blocking socket is told there is data, but
+		// it was a false positive.
+		return (dnssd_errno() == dnssd_EWOULDBLOCK) ? kDNSServiceErr_NoError : kDNSServiceErr_Unknown;
+	ConvertHeaderBytes(&hdr);
     if (hdr.version != VERSION)
         return kDNSServiceErr_Incompatible;
     data = malloc(hdr.datalen);
     if (!data) return kDNSServiceErr_NoMemory;
-    if (my_read(sdRef->sockfd, data, hdr.datalen) < 0) 
+    if (my_read(sdRef->sockfd, data, hdr.datalen) < 0)
         return kDNSServiceErr_Unknown;
     sdRef->process_reply(sdRef, &hdr, data);
     free(data);
     return kDNSServiceErr_NoError;
     }
 
-
-void DNSServiceRefDeallocate(DNSServiceRef sdRef)
+void DNSSD_API DNSServiceRefDeallocate(DNSServiceRef sdRef)
     {
     if (!sdRef) return;
-    if (sdRef->sockfd > 0) close(sdRef->sockfd);
+    if (sdRef->sockfd > 0) dnssd_close(sdRef->sockfd);
     free(sdRef);
     }
 
+static void handle_resolve_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data)
+    {
+    DNSServiceFlags flags;
+    char fullname[kDNSServiceMaxDomainName];
+    char target[kDNSServiceMaxDomainName];
+    uint16_t txtlen;
+    union { uint16_t s; u_char b[2]; } port;
+    uint32_t ifi;
+    DNSServiceErrorType err;
+    char *txtrecord;
+    int str_error = 0;
+    (void)hdr; 		//unused
+
+    flags = get_flags(&data);
+    ifi = get_long(&data);
+    err = get_error_code(&data);
+    if (get_string(&data, fullname, kDNSServiceMaxDomainName) < 0) str_error = 1;
+    if (get_string(&data, target, kDNSServiceMaxDomainName) < 0) str_error = 1;
+    port.b[0] = *data++;
+    port.b[1] = *data++;
+    txtlen = get_short(&data);
+    txtrecord = get_rdata(&data, txtlen);
+
+	if (!err && str_error) err = kDNSServiceErr_Unknown;
+    ((DNSServiceResolveReply)sdr->app_callback)(sdr, flags, ifi, err, fullname, target, port.s, txtlen, txtrecord, sdr->app_context);
+    }
 
-DNSServiceErrorType DNSServiceResolve
+DNSServiceErrorType DNSSD_API DNSServiceResolve
     (
     DNSServiceRef                  	*sdRef,
-    const DNSServiceFlags               flags,
-    const uint32_t                      interfaceIndex,
+    DNSServiceFlags               flags,
+    uint32_t                      interfaceIndex,
     const char                         	*name,
     const char                         	*regtype,
     const char                         	*domain,
-    const DNSServiceResolveReply        callBack,
+    DNSServiceResolveReply        callBack,
     void                               	*context
     )
     {
     char *msg = NULL, *ptr;
-    int len;
+    size_t len;
     ipc_msg_hdr *hdr;
     DNSServiceRef sdr;
     DNSServiceErrorType err;
-    
+
     if (!sdRef) return kDNSServiceErr_BadParam;
     *sdRef = NULL;
-    
+
 	if (!name || !regtype || !domain || !callBack) return kDNSServiceErr_BadParam;
 
     // calculate total message length
@@ -199,7 +510,7 @@ DNSServiceErrorType DNSServiceResolve
     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);
@@ -213,7 +524,7 @@ DNSServiceErrorType DNSServiceResolve
     sdr->app_callback = callBack;
     sdr->app_context = context;
     *sdRef = sdr;
-    
+
     return err;
 
 error:
@@ -221,54 +532,52 @@ error:
     if (*sdRef) { free(*sdRef);  *sdRef = NULL; }
     return kDNSServiceErr_Unknown;
     }
-    
-    
-static void handle_resolve_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data)
+
+static void handle_query_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;
+    uint32_t interfaceIndex, ttl;
+    DNSServiceErrorType errorCode;
+    char name[kDNSServiceMaxDomainName];
+    uint16_t rrtype, rrclass, rdlen;
+    char *rdata;
     int str_error = 0;
-    (void)hdr; 		//unused
-    
+    (void)hdr;//Unused
+
     flags = get_flags(&data);
-    ifi = get_long(&data);
-    err = get_error_code(&data);
-    if (get_string(&data, fullname, kDNSServiceMaxDomainName) < 0) str_error = 1;
-    if (get_string(&data, target, kDNSServiceMaxDomainName) < 0) str_error = 1;
-    port = get_short(&data);
-    txtlen = get_short(&data);
-    txtrecord = get_rdata(&data, txtlen);
+    interfaceIndex = get_long(&data);
+    errorCode = get_error_code(&data);
+    if (get_string(&data, name, kDNSServiceMaxDomainName) < 0) str_error = 1;
+    rrtype = get_short(&data);
+    rrclass = get_short(&data);
+    rdlen = get_short(&data);
+    rdata = get_rdata(&data, rdlen);
+	ttl = get_long(&data);
 
-	if (!err && str_error) err = kDNSServiceErr_Unknown;
-    ((DNSServiceResolveReply)sdr->app_callback)(sdr, flags, ifi, err, fullname, target, port, txtlen, txtrecord, sdr->app_context);
+	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;
     }
-    
-    
-
 
-DNSServiceErrorType DNSServiceQueryRecord
+DNSServiceErrorType DNSSD_API DNSServiceQueryRecord
 (
  DNSServiceRef       	         	*sdRef,
- const DNSServiceFlags		         flags,
- const uint32_t                      	interfaceIndex,
+ DNSServiceFlags		         flags,
+ uint32_t                      	interfaceIndex,
  const char                   		*name,
- const uint16_t                      	rrtype,
- const uint16_t                      	rrclass,
- const DNSServiceQueryRecordReply     	callBack,
+ uint16_t                      	rrtype,
+ uint16_t                      	rrclass,
+ DNSServiceQueryRecordReply     	callBack,
  void                               	*context
  )
     {
     char *msg = NULL, *ptr;
-    int len;
+    size_t len;
     ipc_msg_hdr *hdr;
     DNSServiceRef sdr;
     DNSServiceErrorType err;
-    
+
     if (!sdRef) return kDNSServiceErr_BadParam;
     *sdRef = NULL;
 
@@ -312,47 +621,39 @@ error:
     return kDNSServiceErr_Unknown;
     }
 
-
-static void handle_query_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data)
+static void handle_browse_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data)
     {
-    DNSServiceFlags flags;
-    uint32_t interfaceIndex, ttl;
-    DNSServiceErrorType errorCode;
-    char name[kDNSServiceMaxDomainName]; 
-    uint16_t rrtype, rrclass, rdlen;
-    char *rdata;
+    DNSServiceFlags      flags;
+    uint32_t                      interfaceIndex;
+    DNSServiceErrorType      errorCode;
+    char replyName[256], replyType[kDNSServiceMaxDomainName],
+        replyDomain[kDNSServiceMaxDomainName];
     int str_error = 0;
-    (void)hdr;//Unused
+	(void)hdr;//Unused
 
     flags = get_flags(&data);
     interfaceIndex = get_long(&data);
     errorCode = get_error_code(&data);
-    if (get_string(&data, name, kDNSServiceMaxDomainName) < 0) str_error = 1;
-    rrtype = get_short(&data);
-    rrclass = get_short(&data);
-    rdlen = get_short(&data);
-    rdata = get_rdata(&data, rdlen);
-	ttl = get_long(&data);
-
+    if (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;
-	((DNSServiceQueryRecordReply)sdr->app_callback)(sdr, flags, interfaceIndex, errorCode, name, rrtype, rrclass,
-													rdlen, rdata, ttl, sdr->app_context);
-    return;
+	((DNSServiceBrowseReply)sdr->app_callback)(sdr, flags, interfaceIndex, errorCode, replyName, replyType, replyDomain, sdr->app_context);
     }
 
-DNSServiceErrorType DNSServiceBrowse
+DNSServiceErrorType DNSSD_API DNSServiceBrowse
 (
  DNSServiceRef                      *sdRef,
- const DNSServiceFlags              flags,
- const uint32_t                     interfaceIndex,
+ DNSServiceFlags              flags,
+ uint32_t                     interfaceIndex,
  const char                         *regtype,
  const char                         *domain,
- const DNSServiceBrowseReply        callBack,
+ DNSServiceBrowseReply        callBack,
  void                               *context
  )
     {
     char *msg = NULL, *ptr;
-    int len;
+    size_t len;
     ipc_msg_hdr *hdr;
     DNSServiceRef sdr;
     DNSServiceErrorType err;
@@ -396,51 +697,71 @@ error:
     return kDNSServiceErr_Unknown;
     }
 
+DNSServiceErrorType DNSSD_API DNSServiceSetDefaultDomainForUser
+(
+ DNSServiceFlags                    flags,
+ const char                         *domain
+ )
+    {
+    DNSServiceRef sdr;
+    DNSServiceErrorType err;
+    char *ptr = NULL;
+    size_t len = sizeof(flags) + strlen(domain) + 1;
+    ipc_msg_hdr *hdr = create_hdr(setdomain_request, &len, &ptr, 1);
 
+    if (!hdr) return kDNSServiceErr_Unknown;
+    put_flags(flags, &ptr);
+    put_string(domain, &ptr);
 
+    sdr = connect_to_server();
+    if (!sdr) { free(hdr); return kDNSServiceErr_Unknown; }
+    err = deliver_request((char *)hdr, sdr, 1);		// deliver_request frees the message for us
+	DNSServiceRefDeallocate(sdr);
+	return err;
+    }
 
-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)
     {
-    DNSServiceFlags      flags;
-    uint32_t                      interfaceIndex;
-    DNSServiceErrorType      errorCode;
-    char replyName[256], replyType[kDNSServiceMaxDomainName], 
-        replyDomain[kDNSServiceMaxDomainName];
+    DNSServiceFlags flags;
+    uint32_t interfaceIndex;
+    DNSServiceErrorType errorCode;
+    char name[256], regtype[kDNSServiceMaxDomainName], domain[kDNSServiceMaxDomainName];
     int str_error = 0;
 	(void)hdr;//Unused
 
     flags = get_flags(&data);
     interfaceIndex = get_long(&data);
     errorCode = get_error_code(&data);
-    if (get_string(&data, 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 (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;
-	((DNSServiceBrowseReply)sdr->app_callback)(sdr, flags, interfaceIndex, errorCode, replyName, replyType, replyDomain, sdr->app_context);
+    ((DNSServiceRegisterReply)sdr->app_callback)(sdr, flags, errorCode, name, regtype, domain, sdr->app_context);
     }
 
-
-DNSServiceErrorType DNSServiceRegister
+DNSServiceErrorType DNSSD_API 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       
+    DNSServiceFlags                     flags,
+    uint32_t                            interfaceIndex,
+    const char                          *name,
+    const char                          *regtype,
+    const char                          *domain,
+    const char                          *host,
+    uint16_t                            PortInNetworkByteOrder,
+    uint16_t                            txtLen,
+    const void                          *txtRecord,
+    DNSServiceRegisterReply             callBack,
+    void                                *context
     )
     {
     char *msg = NULL, *ptr;
-    int len;
+    size_t len;
     ipc_msg_hdr *hdr;
     DNSServiceRef sdr;
     DNSServiceErrorType err;
+    union { uint16_t s; u_char b[2]; } port = { PortInNetworkByteOrder };
 
     if (!sdRef) return kDNSServiceErr_BadParam;
     *sdRef = NULL;
@@ -449,8 +770,8 @@ DNSServiceErrorType DNSServiceRegister
     if (!regtype) return kDNSServiceErr_BadParam;
     if (!domain) domain = "";
     if (!host) host = "";
-    if (!txtRecord) (char *)txtRecord = "";
-    
+    if (!txtRecord) txtRecord = (void*)"";
+
     // auto-name must also have auto-rename
     if (!name[0]  && (flags & kDNSServiceFlagsNoAutoRename))
         return kDNSServiceErr_BadParam;
@@ -474,7 +795,8 @@ DNSServiceErrorType DNSServiceRegister
     put_string(regtype, &ptr);
     put_string(domain, &ptr);
     put_string(host, &ptr);
-    put_short(port, &ptr);
+    *ptr++ = port.b[0];
+    *ptr++ = port.b[1];
     put_short(txtLen, &ptr);
     put_rdata(txtLen, txtRecord, &ptr);
 
@@ -486,7 +808,7 @@ DNSServiceErrorType DNSServiceRegister
         DNSServiceRefDeallocate(sdr);
         return err;
         }
-        
+
     sdr->op = reg_service_request;
     sdr->process_reply = callBack ? handle_regservice_response : NULL;
     sdr->app_callback = callBack;
@@ -494,55 +816,51 @@ DNSServiceErrorType DNSServiceRegister
     *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)
+static void handle_enumeration_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data)
     {
     DNSServiceFlags flags;
     uint32_t interfaceIndex;
-    DNSServiceErrorType errorCode;
-    char name[256], regtype[kDNSServiceMaxDomainName], domain[kDNSServiceMaxDomainName];
+    DNSServiceErrorType err;
+    char domain[kDNSServiceMaxDomainName];
     int str_error = 0;
 	(void)hdr;//Unused
 
     flags = get_flags(&data);
     interfaceIndex = get_long(&data);
-    errorCode = get_error_code(&data);
-    if (get_string(&data, name, 256) < 0) str_error = 1;
-    if (get_string(&data, regtype, kDNSServiceMaxDomainName) < 0) str_error = 1;
+    err = get_error_code(&data);
     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);
+	if (!err && str_error) err = kDNSServiceErr_Unknown;
+    ((DNSServiceDomainEnumReply)sdr->app_callback)(sdr, flags, interfaceIndex, err, domain, sdr->app_context);
     }
 
-DNSServiceErrorType DNSServiceEnumerateDomains
+DNSServiceErrorType DNSSD_API DNSServiceEnumerateDomains
 (
  DNSServiceRef                    *sdRef,
- const DNSServiceFlags            flags,
- const uint32_t                   interfaceIndex,
- const DNSServiceDomainEnumReply  callBack,
+ DNSServiceFlags            flags,
+ uint32_t                   interfaceIndex,
+ DNSServiceDomainEnumReply  callBack,
  void                             *context
  )
     {
     char *msg = NULL, *ptr;
-    int len;
+    size_t len;
     ipc_msg_hdr *hdr;
     DNSServiceRef sdr;
     DNSServiceErrorType err;
-
+    int f1 = (flags & kDNSServiceFlagsBrowseDomains) != 0;
+    int f2 = (flags & kDNSServiceFlagsRegistrationDomains) != 0;
+    if (f1 + f2 != 1) return kDNSServiceErr_BadParam;
 
     if (!sdRef) return kDNSServiceErr_BadParam;
     *sdRef = NULL;
 
-	if (flags != kDNSServiceFlagsBrowseDomains && flags != kDNSServiceFlagsRegistrationDomains)
-		return kDNSServiceErr_BadParam;
-
 	len = sizeof(DNSServiceFlags);
     len += sizeof(uint32_t);
 
@@ -575,26 +893,26 @@ error:
     return kDNSServiceErr_Unknown;
     }
 
-
-static void handle_enumeration_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data)
+static void handle_regrecord_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data)
     {
     DNSServiceFlags flags;
     uint32_t interfaceIndex;
-    DNSServiceErrorType err;
-    char domain[kDNSServiceMaxDomainName];
-    int str_error = 0;
-	(void)hdr;//Unused
+    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);
-    err = get_error_code(&data);
-    if (get_string(&data, domain, kDNSServiceMaxDomainName) < 0) str_error = 1;
-	if (!err && str_error) err = kDNSServiceErr_Unknown;
-    ((DNSServiceDomainEnumReply)sdr->app_callback)(sdr, flags, interfaceIndex, err, domain, sdr->app_context);
-    }
+    errorCode = get_error_code(&data);
 
+    rref->app_callback(rref->sdr, rref, flags, errorCode, rref->app_context);
+    }
 
-DNSServiceErrorType DNSServiceCreateConnection(DNSServiceRef *sdRef)
+DNSServiceErrorType DNSSD_API DNSServiceCreateConnection(DNSServiceRef *sdRef)
     {
     if (!sdRef) return kDNSServiceErr_BadParam;
     *sdRef = connect_to_server();
@@ -605,55 +923,34 @@ DNSServiceErrorType DNSServiceCreateConnection(DNSServiceRef *sdRef)
     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
+DNSServiceErrorType DNSSD_API DNSServiceRegisterRecord
 (
- const DNSServiceRef            	sdRef,
- DNSRecordRef                 		*RecordRef,  
- const DNSServiceFlags      	        flags,
- const uint32_t                      	interfaceIndex,
+ DNSServiceRef            	sdRef,
+ DNSRecordRef                 		*RecordRef,
+ DNSServiceFlags      	        flags,
+ uint32_t                      	interfaceIndex,
  const char                         	*fullname,
- const uint16_t                      	rrtype,
- const uint16_t                      	rrclass,
- const uint16_t                      	rdlen,
+ uint16_t                      	rrtype,
+ uint16_t                      	rrclass,
+ uint16_t                      	rdlen,
  const void                         	*rdata,
- const uint32_t                      	ttl,
- const DNSServiceRegisterRecordReply  	callBack,
+ uint32_t                      	ttl,
+ DNSServiceRegisterRecordReply  	callBack,
  void                               	*context
  )
     {
     char *msg = NULL, *ptr;
-    int len;
+    size_t len;
     ipc_msg_hdr *hdr = NULL;
     DNSServiceRef tmp = NULL;
     DNSRecordRef rref = NULL;
-    
-    if (!sdRef || sdRef->op != connection || sdRef->sockfd < 0) 
+    int f1 = (flags & kDNSServiceFlagsShared) != 0;
+    int f2 = (flags & kDNSServiceFlagsUnique) != 0;
+    if (f1 + f2 != 1) return kDNSServiceErr_BadParam;
+
+    if (!sdRef || sdRef->op != connection || sdRef->sockfd < 0)
         return kDNSServiceErr_BadReference;
     *RecordRef = NULL;
-    
-	if (flags != kDNSServiceFlagsShared && flags != kDNSServiceFlagsUnique)
-		return kDNSServiceErr_BadReference;
 
 	len = sizeof(DNSServiceFlags);
     len += 2 * sizeof(uint32_t);  // interfaceIndex, ttl
@@ -681,8 +978,8 @@ DNSServiceErrorType DNSServiceRegisterRecord
     rref->sdr = sdRef;
     *RecordRef = rref;
     hdr->client_context.context = rref;
-    hdr->reg_index = rref->record_index;  
-    
+    hdr->reg_index = rref->record_index;
+
     return deliver_request(msg, sdRef, 0);
 
 error:
@@ -693,26 +990,26 @@ error:
     }
 
 //sdRef returned by DNSServiceRegister()
-DNSServiceErrorType DNSServiceAddRecord
+DNSServiceErrorType DNSSD_API DNSServiceAddRecord
     (
-    const DNSServiceRef	                sdRef,
+    DNSServiceRef	                sdRef,
     DNSRecordRef			*RecordRef,
-    const DNSServiceFlags               flags,
-    const uint16_t			rrtype,
-    const uint16_t			rdlen,
+    DNSServiceFlags               flags,
+    uint16_t			rrtype,
+    uint16_t			rdlen,
     const void				*rdata,
-    const uint32_t			ttl
+    uint32_t			ttl
     )
     {
     ipc_msg_hdr *hdr;
-    int len = 0;
+    size_t len = 0;
     char *ptr;
     DNSRecordRef rref;
 
-    if (!sdRef || (sdRef->op != reg_service_request) || !RecordRef) 
+    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);
@@ -734,7 +1031,7 @@ DNSServiceErrorType DNSServiceAddRecord
     rref->sdr = sdRef;
     *RecordRef = rref;
     hdr->client_context.context = rref;
-    hdr->reg_index = rref->record_index;  
+    hdr->reg_index = rref->record_index;
     return deliver_request((char *)hdr, sdRef, 0);
 
 error:
@@ -743,25 +1040,24 @@ error:
     if (*RecordRef) *RecordRef = NULL;
     return kDNSServiceErr_Unknown;
 }
-    
 
 //DNSRecordRef returned by DNSServiceRegisterRecord or DNSServiceAddRecord
-DNSServiceErrorType DNSServiceUpdateRecord
+DNSServiceErrorType DNSSD_API DNSServiceUpdateRecord
     (
-    const DNSServiceRef         	sdRef,
+    DNSServiceRef         	sdRef,
     DNSRecordRef			RecordRef,
-    const DNSServiceFlags               flags,
-    const uint16_t			rdlen,
+    DNSServiceFlags               flags,
+    uint16_t			rdlen,
     const void				*rdata,
-    const uint32_t			ttl
+    uint32_t			ttl
     )
     {
     ipc_msg_hdr *hdr;
-    int len = 0;
+    size_t len = 0;
     char *ptr;
 
 	if (!sdRef) return kDNSServiceErr_BadReference;
-    
+
     len += sizeof(uint16_t);
     len += rdlen;
     len += sizeof(uint32_t);
@@ -776,24 +1072,22 @@ DNSServiceErrorType DNSServiceUpdateRecord
     put_long(ttl, &ptr);
     return deliver_request((char *)hdr, sdRef, 0);
     }
-    
-
 
-DNSServiceErrorType DNSServiceRemoveRecord
+DNSServiceErrorType DNSSD_API DNSServiceRemoveRecord
 (
- const DNSServiceRef            sdRef,
- const DNSRecordRef            	RecordRef,
- const DNSServiceFlags          flags
+ DNSServiceRef            sdRef,
+ DNSRecordRef            	RecordRef,
+ DNSServiceFlags          flags
  )
     {
     ipc_msg_hdr *hdr;
-    int len = 0;
+    size_t len = 0;
     char *ptr;
     DNSServiceErrorType err;
 
-    if (!sdRef || !RecordRef || !sdRef->max_index) 
+    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;
@@ -804,20 +1098,19 @@ DNSServiceErrorType DNSServiceRemoveRecord
     return err;
     }
 
-
-void DNSServiceReconfirmRecord
+void DNSSD_API DNSServiceReconfirmRecord
 (
- const DNSServiceFlags              flags,
- const uint32_t                     interfaceIndex,
+ DNSServiceFlags              flags,
+ uint32_t                     interfaceIndex,
  const char                         *fullname,
- const uint16_t                     rrtype,
- const uint16_t                     rrclass,
- const uint16_t                     rdlen,
+ uint16_t                     rrtype,
+ uint16_t                     rrclass,
+ uint16_t                     rdlen,
  const void                         *rdata
  )
     {
     char *ptr;
-    int len;
+    size_t len;
     ipc_msg_hdr *hdr;
     DNSServiceRef tmp;
 
@@ -838,164 +1131,9 @@ void DNSServiceReconfirmRecord
     put_short(rrclass, &ptr);
     put_short(rdlen, &ptr);
     put_rdata(rdlen, rdata, &ptr);
-    my_write(tmp->sockfd, (char *)hdr, len);
+	ConvertHeaderBytes(hdr);
+    my_write(tmp->sockfd, (char *)hdr, (int) len);
+    free(hdr);
     DNSServiceRefDeallocate(tmp);
     }
-        
-        
-    // 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)
-    {
-    while (len)
-    	{
-    	ssize_t num_written = send(sd, buf, len, 0);
-    	if (num_written < 0 || num_written > len) return -1;
-    	buf += num_written;
-    	len -= num_written;
-    	}
-    return 0;
-    }
-
-
-// read len bytes.  return 0 on success, -1 on error
-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;
-#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);
-            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-%.3lx-%.6lu", CTL_PATH_PREFIX, (int)getpid(), 
-		  (unsigned long)(time.tv_sec & 0xFFF), (unsigned long)(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/mDNSShared/dnssd_ipc.c b/mDNSShared/dnssd_ipc.c
index 9f509a4..e06737b 100644
--- a/mDNSShared/dnssd_ipc.c
+++ b/mDNSShared/dnssd_ipc.c
@@ -1,30 +1,47 @@
 /*
- * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
+ * 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):
+ * 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.
+
+	Change History (most recent first):
 
 $Log: dnssd_ipc.c,v $
+Revision 1.14  2004/10/06 02:22:20  cheshire
+Changed MacRoman copyright symbol (should have been UTF-8 in any case :-) to ASCII-compatible "(c)"
+
+Revision 1.13  2004/10/01 22:15:55  rpantos
+rdar://problem/3824265: Replace APSL in client lib with BSD license.
+
+Revision 1.12  2004/09/16 23:14:24  cheshire
+Changes for Windows compatibility
+
+Revision 1.11  2004/06/18 04:56:09  rpantos
+casting goodness
+
+Revision 1.10  2004/06/12 01:08:14  cheshire
+Changes for Windows compatibility
+
 Revision 1.9  2004/05/18 23:51:27  cheshire
 Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
 
@@ -39,107 +56,71 @@ 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);
-    }
+	{
+	(*ptr)[0] = (char)((l >> 24) &  0xFF);
+	(*ptr)[1] = (char)((l >> 16) &  0xFF);
+	(*ptr)[2] = (char)((l >>  8) &  0xFF);
+	(*ptr)[3] = (char)((l      ) &  0xFF);
+	*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);
-    }
+	{
+	uint8_t *p = (uint8_t*) *ptr;
+	*ptr += sizeof(uint32_t);
+	return((uint32_t) ((uint32_t)p[0] << 24 | (uint32_t)p[1] << 16 | (uint32_t)p[2] << 8 | p[3]));
+	}
+
+void put_short(uint16_t s, char **ptr)
+	{
+	(*ptr)[0] = (char)((s >>  8) &  0xFF);
+	(*ptr)[1] = (char)((s      ) &  0xFF);
+	*ptr += sizeof(uint16_t);
+	}
 
 uint16_t get_short(char **ptr)
-    {
-    uint16_t s;
-
-    s = *(uint16_t *)(*ptr);
-    *ptr += sizeof(uint16_t);
-    return s;
-    }
-
+	{
+	uint8_t *p = (uint8_t*) *ptr;
+	*ptr += sizeof(uint16_t);
+	return((uint16_t) ((uint16_t)p[0] << 8 | p[1]));
+	}
 
 int put_string(const char *str, char **ptr)
-    {
-    if (!str) str = "";
-    strcpy(*ptr, str);
-    *ptr += strlen(str) + 1;
-    return 0;
-    }
+	{
+	if (!str) str = "";
+	strcpy(*ptr, str);
+	*ptr += strlen(str) + 1;
+	return 0;
+	}
 
 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;
-    }	
+	{
+	int 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;	
-    }
+	{
+	memcpy(*ptr, rdata, rdlen);
+	*ptr += rdlen;
+	}
 
 char *get_rdata(char **ptr, int rdlen)
-    {
-    char *rd;
-		
-    rd = *ptr;
-    *ptr += rdlen;
-    return rd;
-    }
-
-
-
-
-
-
-
-
-
+	{
+	char *rd = *ptr;
+	*ptr += rdlen;
+	return rd;
+	}
+
+void ConvertHeaderBytes(ipc_msg_hdr *hdr)
+	{
+	hdr->version   = htonl(hdr->version);
+	hdr->datalen   = htonl(hdr->datalen);
+	hdr->flags     = htonl(hdr->flags);
+	hdr->op        = htonl(hdr->op );
+	hdr->reg_index = htonl(hdr->reg_index);
+	}
diff --git a/mDNSShared/dnssd_ipc.h b/mDNSShared/dnssd_ipc.h
index 4585284..60ffc16 100644
--- a/mDNSShared/dnssd_ipc.h
+++ b/mDNSShared/dnssd_ipc.h
@@ -1,30 +1,67 @@
 /*
- * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
+ * 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@
+ * 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.
 
     Change History (most recent first):
 
 $Log: dnssd_ipc.h,v $
+Revision 1.17  2004/11/23 03:39:47  cheshire
+Let interface name/index mapping capability live directly in JNISupport.c,
+instead of having to call through to the daemon via IPC to get this information.
+
+Revision 1.16  2004/11/12 03:21:41  rpantos
+rdar://problem/3809541 Add DNSSDMapIfIndexToName, DNSSDMapNameToIfIndex.
+
+Revision 1.15  2004/10/06 02:22:20  cheshire
+Changed MacRoman copyright symbol (should have been UTF-8 in any case :-) to ASCII-compatible "(c)"
+
+Revision 1.14  2004/10/01 22:15:55  rpantos
+rdar://problem/3824265: Replace APSL in client lib with BSD license.
+
+Revision 1.13  2004/09/16 23:14:25  cheshire
+Changes for Windows compatibility
+
+Revision 1.12  2004/09/16 21:46:38  ksekar
+<rdar://problem/3665304> Need SPI for LoginWindow to associate a UID with a Wide Area Rendezvous domain
+
+Revision 1.11  2004/08/10 06:24:56  cheshire
+Use types with precisely defined sizes for 'op' and 'reg_index', for better
+compatibility if the daemon and the client stub are built using different compilers
+
+Revision 1.10  2004/07/07 17:39:25  shersche
+Change MDNS_SERVERPORT from 5533 to 5354.
+
+Revision 1.9  2004/06/25 00:26:27  rpantos
+Changes to fix the Posix build on Solaris.
+
+Revision 1.8  2004/06/18 04:56:51  rpantos
+Add layer for platform code
+
+Revision 1.7  2004/06/12 01:08:14  cheshire
+Changes for Windows compatibility
+
 Revision 1.6  2003/08/12 19:56:25  cheshire
 Update to APSL 2.0
 
@@ -34,21 +71,67 @@ Update to APSL 2.0
 #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>
+
+
+//
+// Common cross platform services
+//
+#if defined(WIN32)
+#	include <winsock2.h>
+#	define dnssd_InvalidSocket	INVALID_SOCKET
+#	define dnssd_EWOULDBLOCK	WSAEWOULDBLOCK
+#	define dnssd_EINTR			WSAEINTR
+#	define MSG_WAITALL 			0
+#	define dnssd_sock_t			SOCKET
+#	define dnssd_sockbuf_t		
+#	define dnssd_close(sock)	closesocket(sock)
+#	define dnssd_errno()		WSAGetLastError()
+#	define ssize_t				int
+#	define getpid				_getpid
+#else
+#	include <sys/types.h>
+#	include <unistd.h>
+#	include <sys/un.h>
+#	include <string.h>
+#	include <stdio.h>
+#	include <stdlib.h>
+#	include <sys/stat.h>
+#	include <sys/socket.h>
+#	include <netinet/in.h>
+#	define dnssd_InvalidSocket	-1
+#	define dnssd_EWOULDBLOCK	EWOULDBLOCK
+#	define dnssd_EINTR			EINTR
+#	define dnssd_EPIPE			EPIPE
+#	define dnssd_sock_t			int
+#	define dnssd_close(sock)	close(sock)
+#	define dnssd_errno()		errno
+#endif
+
+#if defined(USE_TCP_LOOPBACK)
+#	define AF_DNSSD				AF_INET
+#	define MDNS_TCP_SERVERADDR	"127.0.0.1"
+#	define MDNS_TCP_SERVERPORT	5354
+#	define LISTENQ				5
+#	define dnssd_sockaddr_t		struct sockaddr_in
+#else
+#	define AF_DNSSD				AF_LOCAL
+#	define MDNS_UDS_SERVERPATH	"/var/run/mDNSResponder"
+#	define LISTENQ				100
+    // longest legal control path length
+#	define MAX_CTLPATH			256	
+#	define dnssd_sockaddr_t		struct sockaddr_un
+#endif
+
 
 //#define UDSDEBUG  // verbose debug output
 
+// Compatibility workaround
+#ifndef AF_LOCAL
+#define	AF_LOCAL	AF_UNIX
+#endif
+
 // 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
+#define TXT_RECORD_INDEX ((uint32_t)(-1))	// record index for default text record
 
 // IPC data encoding constants and types
 #define VERSION 1
@@ -56,7 +139,6 @@ Update to APSL 2.0
 #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()
@@ -69,7 +151,8 @@ typedef enum
     query_request,
     reconfirm_record_request,
     add_record_request,
-    update_record_request
+    update_record_request,
+    setdomain_request
     } request_op_t;
 
 typedef enum
@@ -82,10 +165,8 @@ typedef enum
     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
 
@@ -103,62 +184,43 @@ typedef union
     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;
+    uint32_t op;		// request_op_t or reply_op_t
     client_context_t client_context; // context passed from client, returned by server in corresponding reply
-    int reg_index;                   // identifier for a record registered via DNSServiceRegisterRecord() on a
+    uint32_t reg_index;            // identifier for a record registered via DNSServiceRegisterRecord() on a
     // socket connected by DNSServiceConnect().  Must be unique in the scope of the connection, such that and
     // index/socket pair uniquely identifies a record.  (Used to select records for removal by DNSServiceRemoveRecord())
-    } ipc_msg_hdr_struct;			
-
-
-
+    } ipc_msg_hdr_struct;
 
+// it is advanced to point to the next field, or the end of the message
 // routines to write to and extract data from message buffers.
-// caller responsible for bounds checking.  
+// 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);
+void put_short(uint16_t s, char **ptr);
+uint16_t get_short(char **ptr);
+
+#define put_flags put_long
+#define get_flags get_long
+
+#define put_error_code put_long
+#define get_error_code get_long
 
 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 - 
+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);
-
-
+void ConvertHeaderBytes(ipc_msg_hdr *hdr);
 
 #endif // DNSSD_IPC_H
-
-
-
-
-
-
-
-
-
-
-
diff --git a/mDNSShared/mDNS.1 b/mDNSShared/mDNS.1
index be51457..71c3daf 100644
--- a/mDNSShared/mDNS.1
+++ b/mDNSShared/mDNS.1
@@ -20,6 +20,12 @@
 .\" @APPLE_LICENSE_HEADER_END@
 .\"
 .\" $Log: mDNS.1,v $
+.\" Revision 1.5  2004/09/24 18:33:05  cheshire
+.\" <rdar://problem/3561780> Update man pages to clarify that mDNS and dns-sd are not intended for script use
+.\"
+.\" Revision 1.4  2004/09/22 22:18:48  cheshire
+.\" Update man page to cross-reference new dns-sd man page
+.\"
 .\" Revision 1.3  2004/05/19 00:31:28  cheshire
 .\" Add missing "name type domain" for -L option
 .\"
@@ -50,19 +56,32 @@
 The
 .Nm
 command is a network diagnostic tool, much like
-.Xr ping 8 or
+.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 .
+However, unlike those tools, most of its functionality is not implemented in the
+.Nm
+executable itself, but in library code that is available to any application.
+The library API that
+.Nm
+uses is documented in
+.Pa /usr/include/DNSServiceDiscovery/DNSServiceDiscovery.h .
+Note that this Mach-based API, first introduced in Mac OS X 10.2,
+is now deprecated in favour of the newer
+.Pa /usr/include/dns_sd.h
+API, which is built on Unix Domain Sockets and is supported on
+multiple platforms.
+The command-line tool to exercise the cross-platform
+.Pa dns_sd.h
+API is
+.Xr dns-sd 1 .
 .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
+the asynchronous nature of 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
@@ -73,9 +92,21 @@ 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.
+.br
+If you wish to perform DNS Service Discovery operations from a
+scripting language, then the best way to do this is not to execute the
+.Nm
+command and then attempt to decipher the textual output, but instead to
+directly call the DNS-SD APIs using a binding for your chosen language.
+.br
+For example, if you are programming in Ruby, then you can
+directly call DNS-SD APIs using the dnssd package documented at
+.Pa <http://rubyforge.org/projects/dnssd/> .
+.br
+Similar bindings for other languages are also in development.
 .Pp
 .Bl -tag -width R
-.It Fl R Ar name type domain port Op Ar key=value ...
+.It Nm Fl R Ar name type domain port Op Ar key=value ...
 register (advertise) a service in the specified
 .Ar domain 
 with the given
@@ -112,7 +143,7 @@ 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
+.It Nm Fl B Ar type domain
 browse for instances of service
 .Ar type
 in
@@ -125,7 +156,7 @@ see
 as described above. Omitting the
 .Ar domain
 or using "." means "pick a sensible default."
-.It Fl L Ar name type domain
+.It Nm 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
@@ -144,7 +175,7 @@ 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
+.Dl Nm Fl R Ns \ \&"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
@@ -155,23 +186,29 @@ 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
+.Dl Nm Fl R Ns \ \&"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
+.Dl Nm Fl B Ns \ _http._tcp
 .Pp
-While that command is running, in another window, try the "mDNS -R"
+While that command is running, in another window, try the
+.Nm Fl 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.
+"Add" event reported to the
+.Nm Fl B
+window. Now press Ctrl-C in the
+.Nm Fl R
+window and you should see the "Remove" event reported to the
+.Nm Fl B
+window.
 .Pp
 .Sh FILES
 .Pa /usr/bin/mDNS \" Pathname
 .\"
 .Sh SEE ALSO
+.Xr dns-sd 1
 .Xr mDNSResponder 8
 .\"
 .Sh BUGS
diff --git a/mDNSShared/mDNSDebug.c b/mDNSShared/mDNSDebug.c
index 9196f00..dc5ad0f 100644
--- a/mDNSShared/mDNSDebug.c
+++ b/mDNSShared/mDNSDebug.c
@@ -3,8 +3,6 @@
  *
  * @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
@@ -31,6 +29,15 @@
     Change History (most recent first):
 
 $Log: mDNSDebug.c,v $
+Revision 1.5  2004/09/17 01:08:55  cheshire
+Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
+  The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
+  declared in that file are ONLY appropriate to single-address-space embedded applications.
+  For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
+
+Revision 1.4  2004/06/11 22:36:51  cheshire
+Fixes for compatibility with Windows
+
 Revision 1.3  2004/01/28 21:14:23  cheshire
 Reconcile debug_mode and gDebugLogging into a single flag (mDNS_DebugMode)
 
@@ -45,9 +52,20 @@ Changes necessary to support mDNSResponder on Linux.
 #include "mDNSDebug.h"
 
 #include <stdio.h>
+
+#if defined(WIN32)
+// Need to add Windows syslog support here
+#define LOG_PID 0x01
+#define LOG_CONS 0x02
+#define LOG_PERROR 0x20
+#define openlog(A,B,C) (void)(A); (void)(B)
+#define syslog(A,B,C)
+#define closelog()
+#else
 #include <syslog.h>
+#endif
 
-#include "mDNSClientAPI.h"
+#include "mDNSEmbeddedAPI.h"
 
 #if MDNS_DEBUGMSGS
 mDNSexport int mDNS_DebugMode = mDNStrue;
@@ -98,13 +116,7 @@ mDNSlocal void WriteLogMsg(const char *ident, const char *buffer, int logoptflag
 		}
 	}
 
-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);
-	}
-
+// Log message with default "mDNSResponder" ident string at the start
 mDNSexport void LogMsg(const char *format, ...)
 	{
 	unsigned char buffer[512];
@@ -115,18 +127,24 @@ mDNSexport void LogMsg(const char *format, ...)
 	WriteLogMsg("mDNSResponder", buffer, 0);
 	}
 
+// Log message with specified ident string at the start
 mDNSexport void LogMsgIdent(const char *ident, const char *format, ...)
 	{
+	unsigned char buffer[512];
 	va_list ptr;
 	va_start(ptr,format);
-	LogMsgWithIdent(ident, format, ptr);
+	buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0;
 	va_end(ptr);
+	WriteLogMsg(ident, buffer, ident && *ident ? LOG_PID : 0);
 	}
 
+// Log message with no ident string at the start
 mDNSexport void LogMsgNoIdent(const char *format, ...)
 	{
+	unsigned char buffer[512];
 	va_list ptr;
 	va_start(ptr,format);
-	LogMsgWithIdent("", format, ptr);
+	buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0;
 	va_end(ptr);
+	WriteLogMsg("", buffer, 0);
 	}
diff --git a/mDNSShared/mDNSResponder.8 b/mDNSShared/mDNSResponder.8
index cef8944..8e7a23f 100644
--- a/mDNSShared/mDNSResponder.8
+++ b/mDNSShared/mDNSResponder.8
@@ -20,6 +20,9 @@
 .\" @APPLE_LICENSE_HEADER_END@
 .\"
 .\" $Log: mDNSResponder.8,v $
+.\" Revision 1.5  2004/06/29 02:41:38  cheshire
+.\" Add note that mDNSResponder is called mdnsd on some systems
+.\"
 .\" Revision 1.4  2004/05/18 18:14:36  cheshire
 .\" Minor wording update
 .\"
@@ -47,6 +50,9 @@
 .\"
 .Sh DESCRIPTION
 .Nm
+(also known as
+.Nm mdnsd
+on some systems)
 is a daemon invoked at boot time to implement Multicast DNS
 and DNS Service Discovery.
 .Pp
diff --git a/mDNSShared/uds_daemon.c b/mDNSShared/uds_daemon.c
index e393f69..7f50d74 100644
--- a/mDNSShared/uds_daemon.c
+++ b/mDNSShared/uds_daemon.c
@@ -1,10 +1,9 @@
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
  * 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
@@ -25,8 +24,283 @@
     Change History (most recent first):
 
 $Log: uds_daemon.c,v $
-Revision 1.55.2.1  2004/06/13 22:32:24  ksekar
-WWDC Branch
+Revision 1.139  2004/12/13 21:18:45  ksekar
+Include uDNS registrations in CountPeerRegistrations
+
+Revision 1.138  2004/12/13 18:23:18  ksekar
+<rdar://problem/3915805> mDNSResponder error when quitting iChat -
+don't close sockets delivering errors to blocked clients
+
+Revision 1.137  2004/12/13 00:09:22  ksekar
+<rdar://problem/3915805> mDNSResponder error when quitting iChat
+
+Revision 1.136  2004/12/11 01:52:10  cheshire
+<rdar://problem/3785820> Support kDNSServiceFlagsAllowRemoteQuery for registering services too
+
+Revision 1.135  2004/12/10 20:46:37  cheshire
+Change LogOperation message to debugf
+
+Revision 1.134  2004/12/10 13:19:37  cheshire
+Add verbosedebugf() logging message in CountPeerRegistrations()
+
+Revision 1.133  2004/12/10 05:27:26  cheshire
+<rdar://problem/3909147> Guard against multiple autoname services of the same type on the same machine
+
+Revision 1.132  2004/12/10 04:28:28  cheshire
+<rdar://problem/3914406> User not notified of name changes for services using new UDS API
+
+Revision 1.131  2004/12/10 02:09:25  cheshire
+<rdar://problem/3898376> Modify default TTLs
+
+Revision 1.130  2004/12/10 00:55:24  cheshire
+Add full name and type to LogOperation messages for DNSServiceAddRecord/UpdateRecord/RemoveRecord
+
+Revision 1.129  2004/12/09 03:17:23  ksekar
+<rdar://problem/3910435> DomainEnumeration interface index should be zero
+
+Revision 1.128  2004/12/07 21:26:05  ksekar
+<rdar://problem/3908336> DNSServiceRegisterRecord() can crash on deregistration
+
+Revision 1.127  2004/12/07 20:42:34  cheshire
+Add explicit context parameter to mDNS_RemoveRecordFromService()
+
+Revision 1.126  2004/12/07 17:23:55  ksekar
+Fixed LogOperation
+
+Revision 1.125  2004/12/06 21:15:23  ksekar
+<rdar://problem/3884386> mDNSResponder crashed in CheckServiceRegistrations
+
+Revision 1.124  2004/11/30 02:19:14  cheshire
+<rdar://problem/3827971> Raise maxfds.rlim_cur for mDNSResponder
+
+Revision 1.123  2004/11/29 23:50:57  cheshire
+Checkin 1.122 not necessary
+
+Revision 1.122  2004/11/24 17:55:01  ksekar
+Added log message clarifying <rdar://problem/3869241> For unicast operations, verify that service types are legal
+
+Revision 1.121  2004/11/24 04:45:52  cheshire
+Spelling mistake
+
+Revision 1.120  2004/11/24 00:10:44  cheshire
+<rdar://problem/3869241> For unicast operations, verify that service types are legal
+
+Revision 1.119  2004/11/23 23:54:17  ksekar
+<rdar://problem/3890318> Wide-Area DNSServiceRegisterRecord() failures
+can crash mDNSResponder
+
+Revision 1.118  2004/11/23 22:33:01  cheshire
+<rdar://problem/3654910> Remove temporary workaround code for iChat
+
+Revision 1.117  2004/11/23 20:23:10  ksekar
+Fixed LogOperation that causes crash on connected service deregistrations
+
+Revision 1.116  2004/11/23 03:39:47  cheshire
+Let interface name/index mapping capability live directly in JNISupport.c,
+instead of having to call through to the daemon via IPC to get this information.
+
+Revision 1.115  2004/11/13 00:12:53  ksekar
+Fixed some LogOperation printf converstions for debug builds.
+
+Revision 1.114  2004/11/12 18:25:45  shersche
+Tidy up cross platform usleep code fragment.
+
+Revision 1.113  2004/11/12 03:21:41  rpantos
+rdar://problem/3809541 Add DNSSDMapIfIndexToName, DNSSDMapNameToIfIndex.
+
+Revision 1.112  2004/11/11 16:58:32  ksekar
+Removed unused code (previously wrapped in #if 0)
+
+Revision 1.111  2004/11/05 22:47:37  shersche
+Conditionally compile usleep(1000) to be Sleep(1) on Windows
+Submitted by: Pavel Repin <prepin@gmail.com>
+
+Revision 1.110  2004/11/05 19:56:56  ksekar
+<rdar://problem/3862646> We no longer need to browse .Mac domains by
+default - changed #if 0 to more descriptive #ifdef _HAVE_SETDOMAIN_SUPPORT_
+
+Revision 1.109  2004/11/04 03:40:45  cheshire
+More debugging messages
+
+Revision 1.108  2004/11/03 02:25:51  cheshire
+<rdar://problem/3324137> Conflict for Computer Name should update *all* empty string services, not just the one with the conflict
+
+Revision 1.107  2004/11/02 19:39:23  ksekar
+<rdar://problem/3862646> We no longer need to browse .Mac domains by default
+
+Revision 1.106  2004/11/02 02:12:21  cheshire
+<rdar://problem/3839111> Remove unnecessary memory allocations
+
+Revision 1.105  2004/10/28 19:07:19  cheshire
+Add some more debugging checks and improved LogOperation() messages
+
+Revision 1.104  2004/10/26 18:53:15  cheshire
+Avoid unused variable warning
+
+Revision 1.103  2004/10/26 07:15:55  cheshire
+Add file descriptor number to all LogOperation messages
+
+Revision 1.102  2004/10/26 06:11:42  cheshire
+Add improved logging to aid in diagnosis of <rdar://problem/3842714> mDNSResponder crashed
+
+Revision 1.101  2004/10/26 04:31:44  cheshire
+Rename CountSubTypes() as ChopSubTypes()
+
+Revision 1.100  2004/10/26 01:17:48  cheshire
+Use "#if 0" instead of commenting out code
+
+Revision 1.99  2004/10/19 21:33:22  cheshire
+<rdar://problem/3844991> Cannot resolve non-local registrations using the mach API
+Added flag 'kDNSServiceFlagsForceMulticast'. Passing through an interface id for a unicast name
+doesn't force multicast unless you set this flag to indicate explicitly that this is what you want
+
+Revision 1.98  2004/10/14 01:59:33  cheshire
+<rdar://problem/3839208> UDS resolves don't work for uDNS services
+
+Revision 1.97  2004/10/13 00:58:35  cheshire
+<rdar://problem/3832738> Registering a proxy doesn't work
+
+Revision 1.96  2004/09/30 00:25:00  ksekar
+<rdar://problem/3695802> Dynamically update default registration domains on config change
+
+Revision 1.95  2004/09/26 23:20:36  ksekar
+<rdar://problem/3813108> Allow default registrations in multiple wide-area domains
+
+Revision 1.94  2004/09/22 18:27:06  ksekar
+<rdar://problem/3811427> allow DNSServiceAddRecord to pass zero to get
+default record TTL
+
+Revision 1.93  2004/09/22 02:39:44  cheshire
+<rdar://problem/3810757> Allow DNSServiceRegisterRecord to pass zero to get default record TTL
+
+Revision 1.92  2004/09/22 02:34:04  cheshire
+Rename parameter "ttl" to "GetTTL" for clarity
+
+Revision 1.91  2004/09/22 02:25:43  cheshire
+Fix spelling errors
+
+Revision 1.90  2004/09/21 23:40:12  ksekar
+<rdar://problem/3810349> mDNSResponder to return errors on NAT traversal failure
+
+Revision 1.89  2004/09/21 23:29:51  cheshire
+<rdar://problem/3680045> DNSServiceResolve should delay sending packets
+
+Revision 1.88  2004/09/21 23:12:46  cheshire
+Reorder initialization of question fields to match structure order
+
+Revision 1.87  2004/09/21 22:18:33  cheshire
+In SIGINFO output, display a '-' next to records that have the Unique bit set
+
+Revision 1.86  2004/09/21 21:05:11  cheshire
+Move duplicate code out of mDNSMacOSX/daemon.c and mDNSPosix/PosixDaemon.c,
+into mDNSShared/uds_daemon.c
+
+Revision 1.85  2004/09/18 01:11:58  ksekar
+<rdar://problem/3806734> Add a user's default domain to empty-string browse list
+
+Revision 1.84  2004/09/17 01:08:55  cheshire
+Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
+  The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
+  declared in that file are ONLY appropriate to single-address-space embedded applications.
+  For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
+
+Revision 1.83  2004/09/16 23:26:33  cheshire
+Move version check inside preceeding "if" that checks we have a complete header
+
+Revision 1.82  2004/09/16 23:14:25  cheshire
+Changes for Windows compatibility
+
+Revision 1.81  2004/09/16 21:46:38  ksekar
+<rdar://problem/3665304> Need SPI for LoginWindow to associate a UID with a Wide Area Rendezvous domain
+
+Revision 1.80  2004/09/16 01:58:23  cheshire
+Fix compiler warnings
+
+Revision 1.79  2004/09/16 00:24:49  cheshire
+<rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
+
+Revision 1.78  2004/09/15 21:44:20  cheshire
+<rdar://problem/3681031> Randomize initial timenow_adjust value in mDNS_Init
+Show time value in log to help diagnose errors
+
+Revision 1.77  2004/09/15 00:19:18  cheshire
+<rdar://problem/3785823> read_rr_from_ipc_msg should use mDNS_SetupResourceRecord()
+
+Revision 1.76  2004/09/02 06:39:52  cheshire
+Minor textual cleanup for clarity
+
+Revision 1.75  2004/09/02 03:48:47  cheshire
+<rdar://problem/3709039> Disable targeted unicast query support by default
+1. New flag kDNSServiceFlagsAllowRemoteQuery to indicate we want to allow remote queries for this record
+2. New field AllowRemoteQuery in AuthRecord structure
+3. uds_daemon.c sets AllowRemoteQuery if kDNSServiceFlagsAllowRemoteQuery is set
+4. mDNS.c only answers remote queries if AllowRemoteQuery is set
+
+Revision 1.74  2004/08/25 02:32:47  cheshire
+Minor cleanup: replace "&regtype[0]" with "regtype"
+
+Revision 1.73  2004/08/25 02:30:40  cheshire
+<rdar://problem/3588761> Current method of doing subtypes causes name collisions
+
+Revision 1.72  2004/08/14 03:22:42  cheshire
+<rdar://problem/3762579> Dynamic DNS UI <-> mDNSResponder glue
+Add GetUserSpecifiedDDNSName() routine
+Convert ServiceRegDomain to domainname instead of C string
+Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs
+
+Revision 1.71  2004/08/11 04:21:21  rpantos
+Fix Windows build.
+
+Revision 1.70  2004/08/11 02:07:00  cheshire
+Remove "mDNS *globalInstance" parameter from udsserver_init()
+Move CheckForDuplicateRegistrations from daemon.c
+<rdar://problem/3501938> No warning when accidentally registering the same service multiple times using socket API
+
+Revision 1.69  2004/08/10 16:14:48  cheshire
+Fix debug builds (oops)
+
+Revision 1.68  2004/08/10 06:24:56  cheshire
+Use types with precisely defined sizes for 'op' and 'reg_index', for better
+compatibility if the daemon and the client stub are built using different compilers
+
+Revision 1.67  2004/07/27 07:14:16  shersche
+make error socket non-blocking after call to connect()
+
+Revision 1.66  2004/07/13 21:24:25  rpantos
+Fix for <rdar://problem/3701120>.
+
+Revision 1.65  2004/06/26 03:17:14  shersche
+implement cross-platform strerror function
+
+Submitted by: herscher
+
+Revision 1.64  2004/06/25 00:26:27  rpantos
+Changes to fix the Posix build on Solaris.
+
+Revision 1.63  2004/06/24 03:43:44  rpantos
+Fix previous checkin so it builds on Windows.
+
+Revision 1.62  2004/06/24 00:57:08  ksekar
+Replaced code acccidentally removed in checkin 1.59.
+
+Revision 1.61  2004/06/19 00:09:39  cheshire
+Remove unused strsep() implementation
+
+Revision 1.60  2004/06/18 19:10:00  cheshire
+<rdar://problem/3588761> Current method of doing subtypes causes name collisions
+
+Revision 1.59  2004/06/18 05:10:31  rpantos
+Changes to allow code to be used on Windows
+
+Revision 1.58  2004/06/15 03:54:08  cheshire
+Include mDNS_TimeNow(&mDNSStorage) in SIGINFO output
+
+Revision 1.57  2004/06/12 01:47:27  ksekar
+<rdar://problem/3690241>: BBEdit crashes when trying to check for newer version
+udsserver_idle compared time in ticks to interval in seconds.
+
+Revision 1.56  2004/06/12 01:35:47  cheshire
+Changes for Windows compatibility
 
 Revision 1.55  2004/06/05 00:04:27  cheshire
 <rdar://problem/3668639>: wide-area domains should be returned in reg. domain enumeration
@@ -39,7 +313,7 @@ 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
+<rdar://problem/3667105>: wide-area DNS-SD servers don't appear in
 Finder
 Use local-only InterfaceID for GetDomains calls for sockets-API
 
@@ -127,7 +401,7 @@ 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()
+Changed gettimeofday() to mDNS_TimeNow(&mDNSStorage);
 
 Revision 1.25  2003/10/22 23:37:49  ksekar
 <rdar://problem/3459141>: crash/hang in abort_client
@@ -175,21 +449,37 @@ Update to APSL 2.0
 
  */
 
+#if defined(_WIN32)
+#include <process.h>
+#define dnssd_strerror(X)	win32_strerror(X)
+#define usleep(X)				Sleep(((X)+999)/1000)
+static char * win32_strerror(int inErrorCode);
+#else
 #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>
+#define dnssd_strerror(X)	strerror(X)
+#endif
 
-#include "mDNSClientAPI.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include "mDNSEmbeddedAPI.h"
+#include "DNSCommon.h"
 #include "uds_daemon.h"
 #include "dns_sd.h"
 #include "dnssd_ipc.h"
 
-// convenience definition 
-#define	_UNUSED	__attribute__ ((unused))
+// Apple specific configuration functionality, not required for other platforms
+#ifdef __MACOSX__
+#include <sys/ucred.h>
+#ifndef LOCAL_PEERCRED
+#define LOCAL_PEERCRED 0x001 /* retrieve peer credentials */
+#endif // LOCAL_PEERCRED
+#endif //__MACOSX__
+
 // Types and Data Structures
 // ----------------------------------------------------------------------
 
@@ -204,51 +494,85 @@ typedef enum
 
 typedef void (*req_termination_fn)(void *);
 
-
 typedef struct registered_record_entry
     {
-    int key;
+    uint32_t key;
     AuthRecord *rr;
     struct registered_record_entry *next;
+    client_context_t client_context;
+    struct request_state *rstate;
     } registered_record_entry;
-    
-typedef struct extra_record_entry
-    {
-    int key;
-    struct extra_record_entry *next;
-    ExtraResourceRecord e;
-    } extra_record_entry;
 
-typedef struct registered_service
+// A single registered service: ServiceRecordSet + bookkeeping
+// Note that we duplicate some fields from parent service_info object
+// to facilitate cleanup, when instances and parent may be deallocated at different times.
+typedef struct service_instance
     {
-    int autoname;
-    int renameonconflict;
-    int rename_on_memfree;  	// set flag on config change when we deregister original name
+    struct service_instance *next;  
+    mDNSBool autoname;				// Set if this name is tied to the Computer Name
+    mDNSBool autorename;			// Set if this client wants us to automatically rename on conflict
+    mDNSBool allowremotequery;		// Respond to unicast queries from outside the local link?
+    mDNSBool rename_on_memfree;  	// Set on config change when we deregister original name
     domainlabel name;
-    ServiceRecordSet *srs;
+    domainname domain;
+    mDNSBool default_local;			// is this the "local." from an empty-string registration?
     struct request_state *request;
+    int sd;
     AuthRecord *subtypes;
-    extra_record_entry *extras;
-    } registered_service;
+    ServiceRecordSet srs; // note - must be last field in struct 
+    } service_instance;
+
+// A client-created service.  May reference several service_info objects if default
+// settings cause registration in multiple domains.
+typedef struct
+	{
+    uint16_t txtlen;
+    void *txtdata;
+    mDNSIPPort port;
+    domainlabel name;
+    char type_as_string[MAX_ESCAPED_DOMAIN_NAME];
+    domainname type;
+    mDNSBool default_domain;
+    domainname host;
+    mDNSBool autoname;				// Set if this name is tied to the Computer Name
+    mDNSBool autorename;			// Set if this client wants us to automatically rename on conflict
+    mDNSBool allowremotequery;		// Respond to unicast queries from outside the local link?
+    int num_subtypes;
+    mDNSInterfaceID InterfaceID;
+    service_instance *instances;
+    struct request_state *request;
+	} service_info;
 
+// for multi-domain default browsing
+typedef struct browser_t
+	{
+    DNSQuestion q;
+    domainname domain;
+    struct browser_t *next;
+	} browser_t;
+
+// parent struct for browser instances: list pointer plus metadata
 typedef struct
 	{
-    registered_service *local;
-    registered_service *global;
-	} servicepair_t;
+    mDNSBool default_domain;
+    mDNSBool ForceMCast;
+    domainname regtype;
+    mDNSInterfaceID interface_id;
+    struct request_state *rstate;
+    browser_t *browsers;
+	} browser_info_t;
 
 typedef struct 
     {
-    mStatus err;
+    mStatus err;		// Note: This field is in NETWORK byte order
     int nwritten;
-    int sd;
+    dnssd_sock_t sd;
     } undelivered_error_t;
 
 typedef struct request_state
     {
     // connection structures
-    int sd;	
-    int errfd;		
+    dnssd_sock_t sd, errfd;		
                                 
     // state of read (in case message is read over several recv() calls)                            
     transfer_state ts;
@@ -271,25 +595,24 @@ 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
-    servicepair_t servicepair;
-    struct resolve_result_t *resolve_results;
-    
+    service_info *service_registration;
+    browser_info_t *browser_info;
     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;
+    DNSServiceFlags flags;			// Note: This field is in NETWORK byte order
+    uint32_t ifi;					// Note: This field is in NETWORK byte order
+    DNSServiceErrorType error;		// Note: This field is in NETWORK byte order
     } reply_hdr;
     
 
 typedef struct reply_state
     {
     // state of the transmission
-    int sd;
+    dnssd_sock_t sd;
     transfer_state ts;
     uint32_t nwriten;
     uint32_t len;
@@ -323,57 +646,41 @@ typedef struct
 
 typedef struct
     {
-    DNSQuestion question;
-    uint16_t	qtype;
-    request_state *rstate;
-    } resolve_t;
-    
-typedef struct
-    {
-    resolve_t *txt;
-    resolve_t *srv;
     request_state *rstate;
+    DNSQuestion qtxt;
+    DNSQuestion qsrv;
+    // const ResourceRecord *txt;
+    // const ResourceRecord *srv;
+    mDNSBool   srv;
+    mDNSBool   txt;
+    domainname target;
+    mDNSIPPort port;
+    mDNSu16    txtlen;
+    mDNSu8     txtdata[AbsoluteMaxDNSMessageData];
     } 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;
-
-// for multi-domain browsing
-typedef struct qlist_t
-	{
-    DNSQuestion q;
-    struct qlist_t *next;
-	} qlist_t;
-
-typedef struct
+#ifdef _HAVE_SETDOMAIN_SUPPORT_
+typedef struct default_browse_list_t
 	{
-    qlist_t *qlist;
-    request_state *rstate;
-	} browse_termination_context;
+    struct default_browse_list_t *next;
+    uid_t uid;
+    AuthRecord ptr_rec;
+	} default_browse_list_t;
 
+static default_browse_list_t *default_browse_list = NULL;
+#endif // _HAVE_SETDOMAIN_SUPPORT_
 
 // 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
-//in the idle() routine.
-
-
-#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    
+mDNSexport mDNS mDNSStorage;
+#define gmDNS (&mDNSStorage)
+
+static dnssd_sock_t			listenfd		=	dnssd_InvalidSocket;  
+static request_state	*	all_requests	=	NULL;  
+
+#define MAX_TIME_BLOCKED 60 * mDNSPlatformOneSecond  // try to send data to a blocked client for 60 seconds before
+                                                     // terminating connection
+#define MSG_PAD_BYTES 5                              // pad message buffer (read from client) with n zero'd bytes to guarantee
+                                                     // n get_string() calls w/o buffer overrun    
 // private function prototypes
 static void connect_callback(void *info);
 static int read_msg(request_state *rs);
@@ -410,16 +717,18 @@ 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 reply_state *create_reply(reply_op_t op, size_t 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);
 static int validate_message(request_state *rstate);
-static mStatus remove_extra_rr_from_service(request_state *rstate);
+static mStatus remove_extra(request_state *rstate, service_instance *serv);
 static mStatus remove_record(request_state *rstate);
-static void free_service_registration(registered_service *srv);
+static void free_service_instance(service_instance *srv);
+static uint32_t dnssd_htonl(uint32_t l);
+static void handle_setdomain_request(request_state *rstate);
 
 // initialization, setup/teardown functions
 
@@ -428,15 +737,13 @@ static void free_service_registration(registered_service *srv);
 #define PID_FILE "/var/run/mDNSResponder.pid"
 #endif
 
-int udsserver_init( mDNS *globalInstance)  
+int udsserver_init(void)
     {
-    mode_t mask;
-    struct sockaddr_un laddr;
-    struct rlimit maxfds;
-
-    if ( !globalInstance)
-        goto error;
-	gmDNS = globalInstance;
+	dnssd_sockaddr_t laddr;
+	int				 ret;
+#if defined(_WIN32)
+	u_long opt = 1;
+#endif
 
 	// If a particular platform wants to opt out of having a PID file, define PID_FILE to be ""
 	if (PID_FILE[0])
@@ -449,60 +756,104 @@ int udsserver_init( mDNS *globalInstance)
 			}
 		}
 
-    if ((listenfd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0) 
-        goto error;
-    unlink(MDNS_UDS_SERVERPATH);  //OK if this fails
+	if ((listenfd = socket(AF_DNSSD, SOCK_STREAM, 0)) == dnssd_InvalidSocket)
+		goto error;
+
     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);
+
+#if defined(USE_TCP_LOOPBACK)
+		{
+		laddr.sin_family		=	AF_INET;
+		laddr.sin_port			=	htons(MDNS_TCP_SERVERPORT);
+		laddr.sin_addr.s_addr	=	inet_addr(MDNS_TCP_SERVERADDR);
+    	ret = bind(listenfd, (struct sockaddr *) &laddr, sizeof(laddr));
+		if (ret < 0)
+			goto error;
+		}
+#else
+		{
+    	mode_t mask = umask(0);
+    	unlink(MDNS_UDS_SERVERPATH);  //OK if this fails
+    	laddr.sun_family = AF_LOCAL;
+#	ifndef NOT_HAVE_SA_LEN	
+	// According to Stevens (section 3.2), there is no portable way to 
+	// determine whether sa_len is defined on a particular platform. 
+    	laddr.sun_len = sizeof(struct sockaddr_un);
+#	endif
+    	strcpy(laddr.sun_path, MDNS_UDS_SERVERPATH);
+		ret = bind(listenfd, (struct sockaddr *) &laddr, sizeof(laddr));
+		umask(mask);
+		if (ret < 0)
+			goto error;
+		}
 #endif
-    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);
-    
+#if defined(_WIN32)
+	//
+	// SEH: do we even need to do this on windows?  this socket
+	// will be given to WSAEventSelect which will automatically
+	// set it to non-blocking
+	//
+	if (ioctlsocket(listenfd, FIONBIO, &opt) != 0)
+#else
+    if (fcntl(listenfd, F_SETFL, O_NONBLOCK) != 0)
+#endif
+	{
+		my_perror("ERROR: could not set listen socket to non-blocking mode");
+		goto error;
+	}
+
+	if (listen(listenfd, LISTENQ) != 0)
+		{
+		my_perror("ERROR: could not listen on listen socket");
+		goto error;
+		}
+
     if (mStatus_NoError != udsSupportAddFDToEventLoop(listenfd, connect_callback, (void *) NULL))
         {
         my_perror("ERROR: could not add listen socket to event loop");
         goto error;
         }
-    
-    // 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");
+
+#if !defined(PLATFORM_NO_RLIMIT)
+	{
+	// Set maximum number of open file descriptors
+	#define MIN_OPENFILES 10240
+	struct rlimit maxfds, newfds;
+
+	// Due to bugs in OS X (<rdar://problem/2941095>, <rdar://problem/3342704>, <rdar://problem/3839173>)
+	// you have to get and set rlimits once before getrlimit will return sensible values
+	if (getrlimit(RLIMIT_NOFILE, &maxfds) < 0) { my_perror("ERROR: Unable to get file descriptor limit"); return 0; }
+	if (setrlimit(RLIMIT_NOFILE, &maxfds) < 0) my_perror("ERROR: Unable to set maximum file descriptor limit");
+
+	if (getrlimit(RLIMIT_NOFILE, &maxfds) < 0) { my_perror("ERROR: Unable to get file descriptor limit"); return 0; }
+	newfds.rlim_max = (maxfds.rlim_max > MIN_OPENFILES) ? maxfds.rlim_max : MIN_OPENFILES;
+	newfds.rlim_cur = (maxfds.rlim_cur > MIN_OPENFILES) ? maxfds.rlim_cur : MIN_OPENFILES;
+	if (newfds.rlim_max != maxfds.rlim_max || newfds.rlim_cur != maxfds.rlim_cur)
+		if (setrlimit(RLIMIT_NOFILE, &newfds) < 0) my_perror("ERROR: Unable to set maximum file descriptor limit");
+
+	if (getrlimit(RLIMIT_NOFILE, &maxfds) < 0) { my_perror("ERROR: Unable to get file descriptor limit"); return 0; }
+	debugf("maxfds.rlim_max %d", (long)maxfds.rlim_max);
+	debugf("maxfds.rlim_cur %d", (long)maxfds.rlim_cur);
+	}
+#endif
+	
     return 0;
 	
 error:
+
     my_perror("ERROR: udsserver_init");
     return -1;
     }
 
 int udsserver_exit(void)
     {
-    close(listenfd);
-    unlink(MDNS_UDS_SERVERPATH);
+	dnssd_close(listenfd);
+
+#if !defined(USE_TCP_LOOPBACK)
+	unlink(MDNS_UDS_SERVERPATH);
+#endif
+
     return 0;
     }
 
@@ -512,7 +863,7 @@ mDNSs32 udsserver_idle(mDNSs32 nextevent)
     request_state *req = all_requests, *tmp, *prev = NULL;
     reply_state *fptr;
     transfer_state result; 
-    mDNSs32 now = mDNSPlatformTimeNow();
+    mDNSs32 now = mDNS_TimeNow(&mDNSStorage);
 
     while(req)
         {
@@ -524,7 +875,7 @@ mDNSs32 udsserver_idle(mDNSs32 nextevent)
             {
             while(req->replies)
                 {
-                if (req->replies->next) req->replies->rhdr->flags |= kDNSServiceFlagsMoreComing;
+                if (req->replies->next) req->replies->rhdr->flags |= dnssd_htonl(kDNSServiceFlagsMoreComing);
                 result = send_msg(req->replies);
                 if (result == t_complete)
                     {
@@ -544,10 +895,10 @@ mDNSs32 udsserver_idle(mDNSs32 nextevent)
         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);
+	    debugf("udsserver_idle: client has been blocked for %ld seconds", (now - req->time_blocked) / mDNSPlatformOneSecond);
 	    if (now - req->time_blocked >= MAX_TIME_BLOCKED)
 		{
-		LogMsg("Could not write data to client after %d seconds - aborting connection", MAX_TIME_BLOCKED / mDNSPlatformOneSecond);
+		LogMsg("Could not write data to client after %ld seconds - aborting connection", MAX_TIME_BLOCKED / mDNSPlatformOneSecond);
 		abort_request(req);
 		result = t_terminated;
 		}
@@ -571,41 +922,75 @@ mDNSs32 udsserver_idle(mDNSs32 nextevent)
     return nextevent;
     }
 
-void udsserver_info(void)
+void udsserver_info(mDNS *const m)
     {
+	mDNSs32 now = mDNS_TimeNow(m);
+	mDNSu32 CacheUsed = 0, CacheActive = 0;
+	mDNSu32 slot;
     request_state *req;
-	qlist_t *qlist;
+
+    LogMsgNoIdent("Timenow 0x%08lX (%ld)", (mDNSu32)now, now);
+
+	for (slot = 0; slot < CACHE_HASH_SLOTS; slot++)
+		{
+		mDNSu32 SlotUsed = 0;
+		CacheRecord *rr;
+		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 %s%-6s%-6s%s",
+				rr->CRActiveQuestion ? "*" : " ", remain,
+				(rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) ? "-" : " ", DNSTypeName(rr->resrec.rrtype),
+				((NetworkInterfaceInfo *)rr->resrec.InterfaceID)->ifname, CRDisplayString(m, rr));
+			usleep(1000);	// Limit rate a little so we don't flood syslog too fast
+			}
+		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);
+
     for (req = all_requests; req; req=req->next)
         {
         void *t = req->termination_context;
         if (!t) continue;
         if (req->terminate == regservice_termination_callback)
-            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)
 			{
-			for (qlist = ((browse_termination_context *)t)->qlist; qlist; qlist = qlist->next)
-				LogMsgNoIdent("DNSServiceBrowse           %##s", qlist->q.qname.c);
+			service_instance *ptr;
+			for (ptr = ((service_info *)t)->instances; ptr; ptr = ptr->next)
+				LogMsgNoIdent("DNSServiceRegister         %##s %u", ptr->srs.RR_SRV.resrec.name.c, SRS_PORT(&ptr->srs));
+			}
+		else if (req->terminate == browse_termination_callback)
+			{
+			browser_t *blist;
+			for (blist = req->browser_info->browsers; blist; blist = blist->next)
+				LogMsgNoIdent("DNSServiceBrowse           %##s", blist->q.qname.c);
 			}
         else if (req->terminate == resolve_termination_callback)
-            LogMsgNoIdent("DNSServiceResolve          %##s", ((resolve_termination_t *)t)->srv->question.qname.c);
+            LogMsgNoIdent("DNSServiceResolve          %##s", ((resolve_termination_t *)t)->qsrv.qname.c);
         else if (req->terminate == question_termination_callback)
             LogMsgNoIdent("DNSServiceQueryRecord      %##s", ((DNSQuestion *)          t)->qname.c);
         else if (req->terminate == enum_termination_callback)
             LogMsgNoIdent("DNSServiceEnumerateDomains %##s", ((enum_termination_t *)   t)->all->question.qname.c);
         }
-    }
 
+    now = mDNS_TimeNow(m);
+    LogMsgNoIdent("Timenow 0x%08lX (%ld)", (mDNSu32)now, now);
+    }
 
-static void rename_service(registered_service *srv)
+static void rename_service(service_instance *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
+		if (mDNS_DeregisterService(gmDNS, &srv->srs))	// If service deregistered already, we can re-register immediately
+			regservice_callback(gmDNS, &srv->srs, mStatus_MemFree);
 		}	
 	}
 
@@ -616,69 +1001,58 @@ void udsserver_handle_configchange(void)
     
     for (req = all_requests; req; req = req->next)
         {
-		if (req->servicepair.local) rename_service(req->servicepair.local);
-		if (req->servicepair.global) rename_service(req->servicepair.global);
+		if (req->service_registration)
+			{
+			service_instance *ptr;
+			for (ptr = req->service_registration->instances; ptr; ptr = ptr->next)
+				rename_service(ptr);
+			}
 		}
     }
 
-static void connect_callback(void *info _UNUSED)
+static void connect_callback(void *info)
     {
-    int sd, clilen, optval;
-    struct sockaddr_un cliaddr;
+    dnssd_sock_t sd;
+	int len;
+	unsigned long optval;
+    dnssd_sockaddr_t cliaddr;
     request_state *rstate;
-//    int errpipe[2];
+    (void)info; // Unused
+
+	len = (int) sizeof(cliaddr);
     
-    clilen = sizeof(cliaddr);
-    sd = accept(listenfd, (struct sockaddr *)&cliaddr, &clilen);
+	sd = accept(listenfd, (struct sockaddr*) &cliaddr, &len);
 
-    if (sd < 0)
+    if (sd == dnssd_InvalidSocket)
         {
-        if (errno == EWOULDBLOCK) return; 
+        if (dnssd_errno() == dnssd_EWOULDBLOCK) return; 
         my_perror("ERROR: accept");
         return;
     	}
     optval = 1;
+
 #ifdef SO_NOSIGPIPE
 	// Some environments (e.g. OS X) support turning off SIGPIPE for a socket
     if (setsockopt(sd, SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)) < 0)
     	{
         my_perror("ERROR: setsockopt - SOL_NOSIGPIPE - aborting client");  
-        close(sd);
+        dnssd_close(sd);
         return;
     	}
 #endif
 
-    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)
+#if defined(_WIN32)
+	if (ioctlsocket(sd, FIONBIO, &optval) != 0)
+#else
+	if (fcntl(sd, F_SETFL, O_NONBLOCK) != 0)
+#endif
         {
-        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
+		my_perror("ERROR: setsockopt - SOL_NOSIGPIPE - aborting client");  
+		dnssd_close(sd);
+		return;
+		}
+	
+	// allocate a request_state struct that will live with the socket
     rstate = mallocL("connect_callback", sizeof(request_state));
     if (!rstate)
     	{
@@ -688,8 +1062,8 @@ static void connect_callback(void *info _UNUSED)
     bzero(rstate, sizeof(request_state));
     rstate->ts = t_morecoming;
     rstate->sd = sd;
-    //rstate->errfd = errpipe[1];
     
+	LogOperation("%3d: Adding FD", rstate->sd);
     if ( mStatus_NoError != udsSupportAddFDToEventLoop( sd, request_callback, rstate))
         return;
     rstate->next = all_requests;
@@ -702,8 +1076,10 @@ static void request_callback(void *info)
     {
     request_state *rstate = info;
     transfer_state result;
-    struct sockaddr_un cliaddr;
-    char ctrl_path[MAX_CTLPATH];
+    dnssd_sockaddr_t cliaddr;
+#if defined(_WIN32)
+    u_long opt = 1;
+#endif
     
     result = read_msg(rstate);
     if (result == t_morecoming)
@@ -749,35 +1125,53 @@ static void request_callback(void *info)
     if (rstate->hdr.flags & IPC_FLAGS_REUSE_SOCKET)
         rstate->errfd = rstate->sd;
     else
-       {
-        if ((rstate->errfd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0)
+		{
+		if ((rstate->errfd = socket(AF_DNSSD, SOCK_STREAM, 0)) == dnssd_InvalidSocket)
             {
             my_perror("ERROR: socket");	
             exit(1);
             }
-        if (fcntl(rstate->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;
-            }        
+
+#if defined(USE_TCP_LOOPBACK)
+		{
+		mDNSOpaque16 port;
+		port.b[0] = rstate->msgdata[0];
+		port.b[1] = rstate->msgdata[1];
+        rstate->msgdata += 2;
+		cliaddr.sin_family      = AF_INET;
+		cliaddr.sin_port        = port.NotAnInteger;
+		cliaddr.sin_addr.s_addr = inet_addr(MDNS_TCP_SERVERADDR);
+		}
+#else
+		{
+    	char ctrl_path[MAX_CTLPATH];
         get_string(&rstate->msgdata, ctrl_path, 256);	// path is first element in message buffer
         bzero(&cliaddr, sizeof(cliaddr));
         cliaddr.sun_family = AF_LOCAL;
         strcpy(cliaddr.sun_path, ctrl_path);
+		}
+#endif
         if (connect(rstate->errfd, (struct sockaddr *)&cliaddr, sizeof(cliaddr)) < 0)
             {
             my_perror("ERROR: connect");
             abort_request(rstate);
             unlink_request(rstate);
+			return;
             }
-        }
-
-        
-
+#if defined(_WIN32)
+		if (ioctlsocket(rstate->errfd, FIONBIO, &opt) != 0)
+#else
+    	if (fcntl(rstate->errfd, F_SETFL, O_NONBLOCK) != 0)
+#endif
+            {
+            my_perror("ERROR: could not set control socket to non-blocking mode");
+            abort_request(rstate);
+            unlink_request(rstate);
+            return;
+            }        
+		}
 
-    switch(rstate->hdr.op.request_op)
+    switch(rstate->hdr.op)
     	{
         case resolve_request: handle_resolve_request(rstate); break;
         case query_request: handle_query_request(rstate);  break;
@@ -789,8 +1183,9 @@ static void request_callback(void *info)
         case update_record_request: handle_update_request(rstate); break;
         case remove_record_request: handle_removerecord_request(rstate); break;
         case reconfirm_record_request: handle_reconfirm_request(rstate); break;
+		case setdomain_request: handle_setdomain_request(rstate); break;
         default:
-            debugf("ERROR: udsserver_recv_request - unsupported request type: %d", rstate->hdr.op.request_op);
+            LogMsg("%3d: ERROR: udsserver_recv_request - unsupported request type: %d", rstate->sd, rstate->hdr.op);
     	}
     }
 
@@ -843,17 +1238,21 @@ static void handle_query_request(request_state *rstate)
     	}
     bzero(q, sizeof(DNSQuestion));	
 
+    q->InterfaceID      = InterfaceID;
+    q->Target           = zeroAddr;
     if (!MakeDomainNameFromDNSNameString(&q->qname, name)) { freeL("DNSQuestion", q); goto bad_param; }	
-    q->QuestionContext = rstate;
+    q->qtype            = rrtype;
+    q->qclass           = rrclass;
+    q->LongLived        = (flags & kDNSServiceFlagsLongLivedQuery) != 0;
+    q->ExpectUnique     = mDNSfalse;
+    q->ForceMCast       = (flags & kDNSServiceFlagsForceMulticast) != 0;
     q->QuestionCallback = question_result_callback;
-    q->qtype = rrtype;
-    q->qclass = rrclass;
-    q->InterfaceID = InterfaceID;
-    q->Target = zeroAddr;
-	if (flags & kDNSServiceFlagsLongLivedQuery) q->LongLived = mDNStrue;
+    q->QuestionContext  = rstate;
+
     rstate->termination_context = q;
     rstate->terminate = question_termination_callback;
 
+	LogOperation("%3d: DNSServiceQueryRecord(%##s, %s) START", rstate->sd, q->qname.c, DNSTypeName(q->qtype));
     result = mDNS_StartQuery(gmDNS, q);
     if (result != mStatus_NoError) LogMsg("ERROR: mDNS_StartQuery: %d", (int)result);
 	
@@ -878,7 +1277,6 @@ static void handle_resolve_request(request_state *rstate)
     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;
     
@@ -902,69 +1300,60 @@ static void handle_resolve_request(request_state *rstate)
     flags = get_flags(&ptr);
     interfaceIndex = get_long(&ptr);
     InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS, interfaceIndex);
-    if (interfaceIndex && !InterfaceID) goto bad_param;
+    if (interfaceIndex && !InterfaceID)
+    	{ LogMsg("ERROR: handle_resolve_request - Couldn't find InterfaceID for interfaceIndex %d", interfaceIndex); goto bad_param; }
     if (get_string(&ptr, name, 256) < 0 ||
         get_string(&ptr, regtype, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
         get_string(&ptr, domain, MAX_ESCAPED_DOMAIN_NAME) < 0)
-        goto bad_param;
+    	{ LogMsg("ERROR: handle_resolve_request - Couldn't read name/regtype/domain"); goto bad_param; }
 
     // free memory in rstate since we don't need it anymore
     freeL("handle_resolve_request", rstate->msgbuf);
     rstate->msgbuf = NULL;
         
     if (build_domainname_from_strings(&fqdn, name, regtype, domain) < 0)
-        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;
-    srv->question.Target      = zeroAddr;
-
-    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;
-    txt->question.Target      = zeroAddr;
+    	{ LogMsg("ERROR: handle_resolve_request - Couldn't build_domainname_from_strings â%sâ â%sâ â%sâ", name, regtype, domain); goto bad_param; }
 
     // set up termination info
     term = mallocL("handle_resolve_request", sizeof(resolve_termination_t));
+    bzero(term, sizeof(*term));
     if (!term) goto malloc_error;
-    term->srv = srv;
-    term->txt = txt;
+
+    // format questions
+    term->qsrv.InterfaceID      = InterfaceID;
+    term->qsrv.Target           = zeroAddr;
+    memcpy(&term->qsrv.qname, &fqdn, MAX_DOMAIN_NAME);
+    term->qsrv.qtype            = kDNSType_SRV;
+    term->qsrv.qclass           = kDNSClass_IN;
+    term->qsrv.LongLived        = mDNSfalse;
+    term->qsrv.ExpectUnique     = mDNStrue;
+	term->qsrv.ForceMCast       = mDNSfalse;
+    term->qsrv.QuestionCallback = resolve_result_callback;
+    term->qsrv.QuestionContext  = rstate;
+    
+    term->qtxt.InterfaceID      = InterfaceID;
+    term->qtxt.Target           = zeroAddr;
+    memcpy(&term->qtxt.qname, &fqdn, MAX_DOMAIN_NAME);
+    term->qtxt.qtype            = kDNSType_TXT;
+    term->qtxt.qclass           = kDNSClass_IN;
+    term->qtxt.LongLived        = mDNSfalse;
+    term->qtxt.ExpectUnique     = mDNStrue;
+	term->qtxt.ForceMCast       = mDNSfalse;
+    term->qtxt.QuestionCallback = resolve_result_callback;
+    term->qtxt.QuestionContext  = rstate;
+
     term->rstate = rstate;
     rstate->termination_context = term;
     rstate->terminate = resolve_termination_callback;
     
-    // 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(gmDNS, &srv->question);
-    if (!err) err = mDNS_StartQuery(gmDNS, &txt->question);
+	LogOperation("%3d: DNSServiceResolve(%##s) START", rstate->sd, term->qsrv.qname.c);
+    err = mDNS_StartQuery(gmDNS, &term->qsrv);
+    if (!err) err = mDNS_StartQuery(gmDNS, &term->qtxt);
 
     if (err)
         {
-        freeL("handle_resolve_request", 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) 
@@ -996,44 +1385,60 @@ static void resolve_termination_callback(void *context)
         return;
         }
     rs = term->rstate;
+	LogOperation("%3d: DNSServiceResolve(%##s) STOP", rs->sd, term->qtxt.qname.c);
     
-    mDNS_StopQuery(gmDNS, &term->txt->question);
-    mDNS_StopQuery(gmDNS, &term->srv->question);
+    mDNS_StopQuery(gmDNS, &term->qtxt);
+    mDNS_StopQuery(gmDNS, &term->qsrv);
     
-    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 _UNUSED, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
+static void resolve_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
 {
-    int len = 0;
+    size_t len = 0;
     char fullname[MAX_ESCAPED_DOMAIN_NAME], target[MAX_ESCAPED_DOMAIN_NAME];
     char *data;
     transfer_state result;
     reply_state *rep;
     request_state *rs = question->QuestionContext;
-    resolve_result_t *res = rs->resolve_results;
+    resolve_termination_t *res = rs->termination_context;
+    (void)m; // Unused
+
+	LogOperation("%3d: DNSServiceResolve(%##s, %s) RESULT %s", rs->sd, question->qname.c, DNSTypeName(question->qtype), RRDisplayString(m, answer));
+    
+    // This code used to do this trick of just keeping a copy of the pointer to
+    // the answer record in the cache, but the unicast query code doesn't currently
+    // put its answer records in the cache, so for now we can't do this.
     
 	if (!AddRecord)
 		{
-		if (answer->rrtype == kDNSType_TXT && res->txt == answer) res->txt = mDNSNULL;
-		if (answer->rrtype == kDNSType_SRV && res->srv == answer) res->srv = mDNSNULL;
+		// 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 (answer->rrtype == kDNSType_TXT) res->txt = answer;
+    // if (answer->rrtype == kDNSType_SRV) res->srv = answer;
+
+    if (answer->rrtype == kDNSType_SRV)
+    	{
+    	AssignDomainName(res->target, answer->rdata->u.srv.target);
+    	res->port = answer->rdata->u.srv.port;
+    	res->srv = mDNStrue;
+    	}
+    if (answer->rrtype == kDNSType_TXT)
+    	{
+    	if (answer->rdlength > AbsoluteMaxDNSMessageData) return;
+    	res->txtlen = answer->rdlength;
+    	mDNSPlatformMemCopy(answer->rdata->u.data, res->txtdata, res->txtlen);
+    	res->txt = mDNStrue;
+    	}
 
     if (!res->txt || !res->srv) return;		// only deliver result to client if we have both answers
     
     ConvertDomainNameToCString(&answer->name, fullname);
-    ConvertDomainNameToCString(&res->srv->rdata->u.srv.target, target);
+    ConvertDomainNameToCString(&res->target, target);
 
     // calculate reply length
     len += sizeof(DNSServiceFlags);
@@ -1042,21 +1447,23 @@ static void resolve_result_callback(mDNS *const m _UNUSED, DNSQuestion *question
     len += strlen(fullname) + 1;
     len += strlen(target) + 1;
     len += 2 * sizeof(uint16_t);  // port, txtLen
-    len += res->txt->rdlength;
+    len += res->txtlen;
     
     // allocate/init reply header
     rep =  create_reply(resolve_reply, len, rs);
-    rep->rhdr->flags = 0;
-    rep->rhdr->ifi =  mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS, answer->InterfaceID);
-    rep->rhdr->error = kDNSServiceErr_NoError;
+    rep->rhdr->flags = dnssd_htonl(0);
+    rep->rhdr->ifi   = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS, answer->InterfaceID));
+    rep->rhdr->error = dnssd_htonl(kDNSServiceErr_NoError);
+
     data = rep->sdata;
     
     // write reply data to message
     put_string(fullname, &data);
     put_string(target, &data);
-    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);
+    *data++ = res->port.b[0];
+    *data++ = res->port.b[1];
+    put_short(res->txtlen, &data);
+    put_rdata(res->txtlen, res->txtdata, &data);
     
     result = send_msg(rep);
     if (result == t_error || result == t_terminated) 
@@ -1070,16 +1477,17 @@ static void resolve_result_callback(mDNS *const m _UNUSED, DNSQuestion *question
     }
  
 // 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 _UNUSED, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
+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;
+    request_state *req = question->QuestionContext;
     reply_state *rep;
-    int len;
+    size_t len;
+    (void)m; // Unused
 
+	LogOperation("%3d: DNSServiceQueryRecord(%##s, %s) RESULT %s", req->sd, question->qname.c, DNSTypeName(question->qtype), RRDisplayString(m, answer));
     //mDNS_StopQuery(m, question);
-    req = question->QuestionContext;
     
     // calculate reply data length
     len = sizeof(DNSServiceFlags);
@@ -1091,9 +1499,11 @@ static void question_result_callback(mDNS *const m _UNUSED, DNSQuestion *questio
     len += strlen(name) + 1;
     
     rep =  create_reply(query_reply, len, req);
-    rep->rhdr->flags = AddRecord ? kDNSServiceFlagsAdd : 0;
-    rep->rhdr->ifi =  mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS, answer->InterfaceID);
-    rep->rhdr->error = kDNSServiceErr_NoError;
+
+    rep->rhdr->flags = dnssd_htonl(AddRecord ? kDNSServiceFlagsAdd : 0);
+    rep->rhdr->ifi =  dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS, answer->InterfaceID));
+    rep->rhdr->error = dnssd_htonl(kDNSServiceErr_NoError);
+
     data = rep->sdata;
     
     put_string(name, &data);
@@ -1110,12 +1520,205 @@ static void question_result_callback(mDNS *const m _UNUSED, DNSQuestion *questio
 static void question_termination_callback(void *context)
     {
     DNSQuestion *q = context;
-
-
+	LogOperation("%3d: DNSServiceQueryRecord(%##s, %s) STOP", ((request_state *)q->QuestionContext)->sd, q->qname.c, DNSTypeName(q->qtype));
     mDNS_StopQuery(gmDNS, q);  // no need to error check
     freeL("question_termination_callback", q);
     }
 
+// 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
+mDNSexport mDNSs32 ChopSubTypes(char *regtype)
+	{
+	mDNSs32 NumSubTypes = 0;
+	char *stp = FindFirstSubType(regtype);
+	while (stp && *stp)					// If we found a comma...
+		{
+		if (*stp == ',') return(-1);
+		NumSubTypes++;
+		stp = FindNextSubType(stp);
+		}
+	if (!stp) return(-1);
+	return(NumSubTypes);
+	}
+
+mDNSexport AuthRecord *AllocateSubTypes(mDNSs32 NumSubTypes, char *p)
+	{
+	AuthRecord *st = mDNSNULL;
+	if (NumSubTypes)
+		{
+		mDNSs32 i;
+		st = mallocL("ServiceSubTypes", NumSubTypes * sizeof(AuthRecord));
+		if (!st) return(mDNSNULL);
+		for (i = 0; i < NumSubTypes; i++)
+			{
+			while (*p) p++;
+			p++;
+			if (!MakeDomainNameFromDNSNameString(&st[i].resrec.name, p))
+				{ freeL("ServiceSubTypes", st); return(mDNSNULL); }
+			}
+		}
+	return(st);
+	}
+
+
+#ifdef _HAVE_SETDOMAIN_SUPPORT_
+static void free_defdomain(mDNS *const m, AuthRecord *const rr, mStatus result)
+	{
+	(void)m;  // unused
+	if (result == mStatus_MemFree) free(rr->RecordContext);  // context is the enclosing list structure
+	}
+#endif
+
+static void handle_setdomain_request(request_state *request)
+	{
+	mStatus err = mStatus_NoError;
+	char *ptr;
+	char domainstr[MAX_ESCAPED_DOMAIN_NAME];
+	domainname domain;
+	DNSServiceFlags flags;
+#ifdef _HAVE_SETDOMAIN_SUPPORT_
+	struct xucred xuc;
+	socklen_t xuclen;
+#endif
+	
+	if (request->ts != t_complete)
+        {
+        LogMsg("ERROR: handle_setdomain_request - transfer state != t_complete");
+        abort_request(request);
+        unlink_request(request);
+        return;
+        }
+
+    // extract flags/domain from message
+    ptr = request->msgdata;
+    flags = get_flags(&ptr);
+    if (get_string(&ptr, domainstr, MAX_ESCAPED_DOMAIN_NAME) < 0 || 
+		!MakeDomainNameFromDNSNameString(&domain, domainstr))
+		{ err = mStatus_BadParamErr; goto end; }
+
+	freeL("handle_setdomain_request", request->msgbuf);
+    request->msgbuf = NULL;
+
+	debugf("%3d: DNSServiceSetDefaultDomainForUser(%##s)", request->sd, domain.c);
+
+#ifdef _HAVE_SETDOMAIN_SUPPORT_
+    // this functionality currently only used for Apple-specific configuration, so we don't burned other platforms by mandating
+	// the existence of this socket option
+	xuclen = sizeof(xuc);
+	if (getsockopt(request->sd, 0, LOCAL_PEERCRED, &xuc, &xuclen))
+		{ my_perror("ERROR: getsockopt, LOCAL_PEERCRED"); err = mStatus_UnknownErr; goto end; }
+	if (xuc.cr_version != XUCRED_VERSION) { LogMsg("getsockopt, LOCAL_PEERCRED - bad version"); err = mStatus_UnknownErr; goto end; }
+	LogMsg("Default domain %s %s for UID %d", domainstr, flags & kDNSServiceFlagsAdd ? "set" : "removed", xuc.cr_uid);	
+
+	if (flags & kDNSServiceFlagsAdd)
+		{
+		// register a local-only PRT record
+		default_browse_list_t *newelem = malloc(sizeof(default_browse_list_t));
+		if (!newelem) { LogMsg("ERROR: malloc"); err = mStatus_NoMemoryErr; goto end; }
+		mDNS_SetupResourceRecord(&newelem->ptr_rec, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, 7200,  kDNSRecordTypeShared, free_defdomain, newelem);
+		MakeDomainNameFromDNSNameString(&newelem->ptr_rec.resrec.name, "_default._browse._dns-sd._udp.local.");
+ 		AssignDomainName(newelem->ptr_rec.resrec.rdata->u.name, domain);
+		newelem->uid = xuc.cr_uid;
+		err = mDNS_Register(gmDNS, &newelem->ptr_rec);
+		if (err) free(newelem);
+		else
+			{
+			// link into list
+			newelem->next = default_browse_list;
+			default_browse_list = newelem;
+			}
+		
+		}
+	else
+		{
+		// remove - find in list, deregister
+		default_browse_list_t *ptr = default_browse_list, *prev = NULL;
+		while (ptr)
+			{
+			if (SameDomainName(&ptr->ptr_rec.resrec.rdata->u.name, &domain))
+				{
+				if (prev) prev->next = ptr->next;
+				else default_browse_list = ptr->next;
+				err = mDNS_Deregister(gmDNS, &ptr->ptr_rec);
+				break;
+				}
+			prev = ptr;
+			ptr = ptr->next;
+			}
+		if (!ptr) { LogMsg("Attempt to remove nonexistent domain %s for UID %d", domainstr, xuc.cr_uid); err = mStatus_Invalid; }
+		}		
+#else
+	err = mStatus_NoError;
+#endif // _HAVE_SETDOMAIN_SUPPORT_
+	
+	end:
+    deliver_error(request, err);
+    abort_request(request);
+    unlink_request(request);
+    }
+
+static mStatus add_domain_to_browser(browser_info_t *info, const domainname *d)
+	{
+	browser_t *b, *p;
+	mStatus err;
+   
+	for (p = info->browsers; p; p = p->next)
+		{
+		if (SameDomainName(&p->domain, d))
+			{ LogMsg("add_domain_to_browser - attempt to add domain %##d already in list", d->c); return mStatus_AlreadyRegistered; }
+		}
+
+	b = mallocL("browser_t", sizeof(*b));
+	if (!b) return mStatus_NoMemoryErr;
+	AssignDomainName(b->domain, *d);
+	err = mDNS_StartBrowse(gmDNS, &b->q, &info->regtype, d, info->interface_id, info->ForceMCast, browse_result_callback, info->rstate);
+	if (err)
+		{
+		LogMsg("mDNS_StartBrowse returned %d for type %##s domain %##s", err, info->regtype.c, d->c);
+		freeL("browser_t", b);
+		}
+	else
+		{
+		b->next = info->browsers;
+		info->browsers = b;
+		}
+		return err;
+	}
 
 static void handle_browse_request(request_state *request)
     {
@@ -1123,12 +1726,12 @@ static void handle_browse_request(request_state *request)
     uint32_t interfaceIndex;
     mDNSInterfaceID InterfaceID;
     char regtype[MAX_ESCAPED_DOMAIN_NAME], domain[MAX_ESCAPED_DOMAIN_NAME];
-	qlist_t *qlist = NULL, *qlist_elem;
-    domainname typedn;
+    domainname typedn, d, temp;
+    mDNSs32 NumSubTypes;
     char *ptr;
-    mStatus result;
-	DNameListElem *search_domain_list, *sdom, tmp;
-	browse_termination_context *term;
+    mStatus err;
+	DNameListElem *search_domain_list, *sdom;
+	browser_info_t *info = NULL;
 	
     if (request->ts != t_complete)
         {
@@ -1144,86 +1747,81 @@ 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;        
+		{ err = mStatus_BadParamErr;  goto error; }
     freeL("handle_browse_request", request->msgbuf);
     request->msgbuf = NULL;
 
     InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS, interfaceIndex);
-    if (interfaceIndex && !InterfaceID) goto bad_param;
+    if (interfaceIndex && !InterfaceID) { err = mStatus_BadParamErr;  goto error; }
+
+	typedn.c[0] = 0;
+	NumSubTypes = ChopSubTypes(regtype);	// Note: Modifies regtype string to remove trailing subtypes
+	if (NumSubTypes < 0 || NumSubTypes > 1) { err = mStatus_BadParamErr;  goto error; }
+	if (NumSubTypes == 1 && !AppendDNSNameString(&typedn, regtype + strlen(regtype) + 1))
+		{ err = mStatus_BadParamErr;  goto error; }
+
+    if (!regtype[0] || !AppendDNSNameString(&typedn, regtype)) { err = mStatus_BadParamErr;  goto error; }
 
-	if (!MakeDomainNameFromDNSNameString(&typedn, regtype)) goto bad_param;
+	if (!MakeDomainNameFromDNSNameString(&temp, regtype)) { err = mStatus_BadParamErr;  goto error; }
+	if (temp.c[0] > 15 && domain[0] == 0) strcpy(domain, "local."); // For over-long service types, we only allow domain "local"
 
-	//!!!KRS browse locally for ichat
-	if (!domain[0] && (!strcmp(regtype, "_ichat._tcp.") || !strcmp(regtype, "_presence._tcp.")))
-		strcpy(domain,"local.");
+	// allocate and set up browser info
+	info = mallocL("browser_info_t", sizeof(*info));
+	if (!info) { err = mStatus_NoMemoryErr; goto error; }
+
+	request->browser_info = info;
+	info->ForceMCast = (flags & kDNSServiceFlagsForceMulticast) != 0;
+	info->interface_id = InterfaceID;
+	AssignDomainName(info->regtype, typedn);
+	info->rstate = request;
+	info->default_domain = !domain[0];
+	info->browsers = NULL;
+
+	// setup termination context
+	request->termination_context = info;
+    request->terminate = browse_termination_callback;
 	
+	LogOperation("%3d: DNSServiceBrowse(%##s%s) START", request->sd, info->regtype.c, domain);
 	if (domain[0])
 		{
-		// 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;
+		if (!MakeDomainNameFromDNSNameString(&d, domain)) { err = mStatus_BadParamErr;  goto error; }
+		err = add_domain_to_browser(info, &d);
 		}
-	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;
-	
-	// 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)
+	else
+		{
+		search_domain_list = mDNSPlatformGetSearchDomainList();
+		for (sdom = search_domain_list; sdom; sdom = sdom->next)
 			{
-			// 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;
+			err = add_domain_to_browser(info, &sdom->name);
+			if (err)
+				{
+				if (SameDomainName(&sdom->name, &localdomain)) break;
+				else err = mStatus_NoError;  // suppress errors for non-local "default" domains
+				}
+
 			}
-		sdom = sdom->next;
+		mDNS_FreeDNameList(search_domain_list);
 		}
-	if (search_domain_list != &tmp) mDNS_FreeDNameList(search_domain_list);
+		
 	deliver_error(request, mStatus_NoError);
 	return;
     
-bad_param:
-    deliver_error(request, mStatus_BadParamErr);
+error:
+	if (info) freeL("browser_info_t", info);
+	if (request->termination_context) request->termination_context = NULL;
+    deliver_error(request, err);
     abort_request(request);
     unlink_request(request);
     }
 
-static void browse_result_callback(mDNS *const m _UNUSED, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
+static void browse_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
     {
-    request_state *req;
+    request_state *req = question->QuestionContext;
     reply_state *rep;
     mStatus err;
-        
-    req = question->QuestionContext;
+    (void)m; // Unused
+	LogOperation("%3d: DNSServiceBrowse(%##s, %s) RESULT %s", req->sd, question->qname.c, DNSTypeName(question->qtype), RRDisplayString(m, answer));
 
     err = gen_rr_response(&answer->rdata->u.name, answer->InterfaceID, req, &rep);
     if (err)
@@ -1235,78 +1833,139 @@ static void browse_result_callback(mDNS *const m _UNUSED, DNSQuestion *question,
             }
         return;
         }
-    if (AddRecord) rep->rhdr->flags |= kDNSServiceFlagsAdd;  // non-zero TTL indicates add
+    if (AddRecord) rep->rhdr->flags |= dnssd_htonl(kDNSServiceFlagsAdd);  // non-zero TTL indicates add
     append_reply(req, rep);
     return;
     }
 
 static void browse_termination_callback(void *context)
     {
-	browse_termination_context *t = context;
-	qlist_t *ptr, *fptr;
+	browser_info_t *info = context;
+	browser_t *ptr;
 	
-	if (!t) return;
-
-	ptr = t->qlist;
-	t->qlist = NULL;
+	if (!info) return;
 
-	while(ptr)
+	while(info->browsers)
 		{
+		ptr = info->browsers;
+		info->browsers = ptr->next;
+		LogOperation("%3d: DNSServiceBrowse(%##s) STOP", info->rstate->sd, ptr->q.qname.c);
 		mDNS_StopBrowse(gmDNS, &ptr->q);  // no need to error-check result
-		fptr = ptr;
-		ptr = ptr->next;
-		freeL("browse_termination_callback", fptr);
+		freeL("browse_termination_callback", ptr);
 		}
-	t->rstate->termination_context = NULL;
-	freeL("browse_termination_callback", t);
+	
+	info->rstate->termination_context = NULL;
+	freeL("browser_info", info);
 	}
 
-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)
+mDNSexport void udsserver_default_browse_domain_changed(const domainname *d, mDNSBool add)
 	{
-	registered_service *r_srv;
-    int srs_size, i;
-	char *sub;
-	mStatus result;	
-	*srv_ptr = NULL;
+	request_state *r;
 	
-	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]);
+	for (r = all_requests; r; r = r->next)
+		{
+		browser_info_t *info = r->browser_info;
+		
+		if (!info || !info->default_domain) continue;
+		if (add) add_domain_to_browser(info, d);
+		else
+			{
+			browser_t *ptr = info->browsers, *prev = NULL;
+			while (ptr)
+				{
+				if (SameDomainName(&ptr->domain, d))
+					{
+					if (prev) prev->next = ptr->next;
+					else info->browsers = ptr->next;
+					mDNS_StopBrowse(gmDNS, &ptr->q);
+					freeL("browser_t", ptr);
+					break;
+					}
+				prev = ptr;
+				ptr = ptr->next;
+				}
+			if (!ptr) LogMsg("Requested removal of default domain %##s not in list for sd %s", d->c, r->sd);
+			}
+		}
+	}
 
-    result = mDNS_RegisterService(gmDNS, r_srv->srs, n, t, d, h, port,
-    	txtdata, txtlen, r_srv->subtypes, num_subtypes, InterfaceID, regservice_callback, r_srv);
+// Count how many other service records we have locally with the same name, but different rdata.
+// For auto-named services, we can have at most one per machine -- if we allowed two auto-named services of
+// the same type on the same machine, we'd get into an infinite autoimmune-response loop of continuous renaming.
+mDNSexport int CountPeerRegistrations(mDNS *const m, ServiceRecordSet *const srs)
+	{
+	int count = 0;
+	ResourceRecord *r = &srs->RR_SRV.resrec;
+	AuthRecord *rr;
+	ServiceRecordSet *s;
+	
+	for (rr = m->ResourceRecords; rr; rr=rr->next)
+		if (rr->resrec.rrtype == kDNSType_SRV && SameDomainName(&rr->resrec.name, &r->name) && !SameRData(&rr->resrec, r))
+			count++;
 
-	if (result)
-		free_service_registration(r_srv);
-	else *srv_ptr = r_srv;
+	for (rr = m->uDNS_info.RecordRegistrations; rr; rr=rr->next)
+		if (rr->uDNS_info.state != regState_Unregistered && rr->resrec.rrtype == kDNSType_SRV && SameDomainName(&rr->resrec.name, &r->name) && !SameRData(&rr->resrec, r))
+			count++;
+
+	for (s = m->uDNS_info.ServiceRegistrations; s; s = s->next)
+		if (s->uDNS_info.state != regState_Unregistered && SameDomainName(&s->RR_SRV.resrec.name, &r->name) && !SameRData(&s->RR_SRV.resrec, r))
+			count++;
+		
+	verbosedebugf("%d peer registrations for %##s", count, r->name.c);
+	return(count);
+	}
+
+mDNSexport int CountExistingRegistrations(domainname *srv, mDNSIPPort port)
+	{
+	int count = 0;
+	AuthRecord *rr;
+	for (rr = gmDNS->ResourceRecords; rr; rr=rr->next)
+		if (rr->resrec.rrtype == kDNSType_SRV &&
+			rr->resrec.rdata->u.srv.port.NotAnInteger == port.NotAnInteger &&
+			SameDomainName(&rr->resrec.name, srv))
+			count++;
+	return(count);
+	}
+
+static mStatus register_service_instance(request_state *request, const domainname *domain)
+	{
+	service_info *info = request->service_registration;
+	service_instance *ptr, *instance;
+    int instance_size;
+	mStatus result;
 
+	for (ptr = info->instances; ptr; ptr = ptr->next)
+		{
+		if (SameDomainName(&ptr->domain, domain))
+			{ LogMsg("register_service_instance: domain %##s already registered", domain->c); return mStatus_AlreadyRegistered; }
+		}
+	
+	instance_size = sizeof(*instance);	
+	if (info->txtlen > sizeof(RDataBody)) instance_size += (info->txtlen - sizeof(RDataBody));
+	instance = mallocL("service_instance", instance_size);
+	if (!instance) { my_perror("ERROR: malloc"); return mStatus_NoMemoryErr; } 
+
+	instance->subtypes = AllocateSubTypes(info->num_subtypes, info->type_as_string);
+	if (info->num_subtypes && !instance->subtypes)
+		{ free_service_instance(instance); instance = NULL; goto malloc_error; }
+    instance->request           = request;
+	instance->sd                = request->sd;
+    instance->autoname          = info->autoname;
+    instance->autorename        = info->autorename;
+    instance->allowremotequery  = info->allowremotequery;
+    instance->rename_on_memfree = 0;
+	instance->name              = info->name;
+	AssignDomainName(instance->domain, *domain);
+	instance->default_local = (info->default_domain && SameDomainName(domain, &localdomain));
+    result = mDNS_RegisterService(gmDNS, &instance->srs, &instance->name, &info->type, domain, info->host.c[0] ? &info->host : NULL, info->port,
+								  info->txtdata, info->txtlen, instance->subtypes, info->num_subtypes, info->InterfaceID, regservice_callback, instance);
+
+	if (result) free_service_instance(instance);
+	else
+		{
+		instance->next = info->instances;
+		info->instances = instance;
+		}
 	return result;
 
 malloc_error:
@@ -1314,24 +1973,58 @@ malloc_error:
     exit(1);
 	}
 
+mDNSexport void udsserver_default_reg_domain_changed(const domainname *d, mDNSBool add)
+	{
+	request_state *rstate;
+	service_info *info;
+	
+	for (rstate = all_requests; rstate; rstate = rstate->next)
+		{
+		if (rstate->terminate != regservice_termination_callback) continue;
+		info = rstate->service_registration;
+		if (!info) { LogMsg("udsserver_default_reg_domain_changed - NULL service info"); continue; } // this should never happen
+		if (!info->default_domain)  continue;
+
+		// valid default registration
+		if (add) register_service_instance(rstate, d);
+		else
+			{
+			// find the instance to remove
+			service_instance *si = rstate->service_registration->instances, *prev = NULL;
+			while (si)
+				{
+				if (SameDomainName(&si->domain, d))
+					{
+					mStatus err;					
+					if (prev) prev->next = si->next;
+					else info->instances = si->next;
+					err = mDNS_DeregisterService(gmDNS, &si->srs);
+					if (err)
+						{
+						LogMsg("udsserver_default_reg_domain_changed - mDNS_DeregisterService err %d", err);
+						free_service_instance(si);
+						}
+					break;
+					}
+				prev = si;
+				si = si->next;
+				}
+			if (!si)  LogMsg("udsserver_default_reg_domain_changed - domain %##s not registered", d->c);
+			}
+		}
+	}
 
 // 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, *sub;
-    domainlabel n;
-    domainname d, h, t, srv;
+    char name[256], domain[MAX_ESCAPED_DOMAIN_NAME], host[MAX_ESCAPED_DOMAIN_NAME];
+    char *ptr;
+    domainname d, srv;
     mStatus result;
-    mDNSInterfaceID InterfaceID;
-	int num_subtypes;
-    char *rtype_ptr;
-    
+	service_info *service = NULL;
+	
 	if (request->ts != t_complete)
         {
         LogMsg("ERROR: handle_regservice_request - transfer state != t_complete");
@@ -1340,53 +2033,98 @@ static void handle_regservice_request(request_state *request)
         return;
         }
 
+	service = mallocL("service_info", sizeof(*service));
+	if (!service) { my_perror("ERROR: malloc"); result = mStatus_NoMemoryErr; goto finish; }
+
+	service->instances = NULL;
+	service->request = request;
+	request->service_registration = service;
+    request->termination_context = request->service_registration;
+    request->terminate = regservice_termination_callback;
+	
     // extract data from message
     ptr = request->msgdata;
     flags = get_flags(&ptr);
     ifi = get_long(&ptr);
-    InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS, ifi);
-    if (ifi && !InterfaceID) goto bad_param;
+    service->InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS, ifi);
+    if (ifi && !service->InterfaceID)
+    	{ LogMsg("ERROR: handle_regservice_request - Couldn't find InterfaceID for interfaceIndex %d", ifi); goto bad_param; }
     if (get_string(&ptr, name, 256) < 0 ||
-        get_string(&ptr, regtype, MAX_ESCAPED_DOMAIN_NAME) < 0 || 
+        get_string(&ptr, service->type_as_string, MAX_ESCAPED_DOMAIN_NAME) < 0 || 
         get_string(&ptr, domain, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
         get_string(&ptr, host, MAX_ESCAPED_DOMAIN_NAME) < 0)
-        goto bad_param;
+    	{ LogMsg("ERROR: handle_regservice_request - Couldn't read name/regtype/domain"); goto bad_param; }
         
-    port.NotAnInteger = get_short(&ptr);
-    txtlen = get_short(&ptr);
-    txtdata = get_rdata(&ptr, txtlen);
+    service->port.b[0] = *ptr++;
+    service->port.b[1] = *ptr++;
+    service->txtlen  = get_short(&ptr);
+    service->txtdata = get_rdata(&ptr, service->txtlen);
 
-    if (!*regtype || !MakeDomainNameFromDNSNameString(&t, regtype)) goto bad_param;
+	// Check for sub-types after the service type
+	service->num_subtypes = ChopSubTypes(service->type_as_string);	// Note: Modifies regtype string to remove trailing subtypes
+	if (service->num_subtypes < 0)
+    	{ LogMsg("ERROR: handle_regservice_request - ChopSubTypes failed %s", service->type_as_string); goto bad_param; }
 
-    // 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 = (gmDNS)->nicelabel;
-    else if (!MakeDomainLabelFromLiteralString(&n, name))  
-        goto bad_param;
-	
-    if ((!MakeDomainNameFromDNSNameString(&d, *domain ? domain : "local.")) ||
-		(!ConstructServiceName(&srv, &n, &t, &d)))
-        goto bad_param;
-
-	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);
+	// Don't try to construct "domainname t" until *after* ChopSubTypes has worked its magic
+    if (!*service->type_as_string || !MakeDomainNameFromDNSNameString(&service->type, service->type_as_string))
+    	{ LogMsg("ERROR: handle_regservice_request - service->type_as_string bad %s", service->type_as_string); goto bad_param; }
 
-	//!!!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."))
+    if (!name[0])
+		{
+		service->name = (gmDNS)->nicelabel;
+		service->autoname = mDNStrue;
+		}
+    else
+		{
+		if (!MakeDomainLabelFromLiteralString(&service->name, name))
+			{ LogMsg("ERROR: handle_regservice_request - name bad %s", name); goto bad_param; }
+		service->autoname = mDNSfalse;
+		}
+        	
+	if (*domain)
+		{
+		service->default_domain = mDNSfalse;
+		if (!MakeDomainNameFromDNSNameString(&d, domain))
+			{ LogMsg("ERROR: handle_regservice_request - domain bad %s", domain); goto bad_param; }
+		}
+	else
 		{
-		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
+		service->default_domain = mDNStrue;
+		MakeDomainNameFromDNSNameString(&d, "local.");
 		}
+	
+	if (!ConstructServiceName(&srv, &service->name, &service->type, &d))
+		{ LogMsg("ERROR: handle_regservice_request - Couldn't ConstructServiceName from, â%#sâ â%##sâ â%##sâ", service->name.c, service->type.c, d.c); goto bad_param; }
 		
-    request->termination_context = &request->servicepair;
-    request->terminate = regservice_termination_callback;
-    
+	if (!MakeDomainNameFromDNSNameString(&service->host, host))
+		{ LogMsg("ERROR: handle_regservice_request - host bad %s", host); goto bad_param; }
+	service->autorename       = (flags & kDNSServiceFlagsNoAutoRename    ) == 0;
+	service->allowremotequery = (flags & kDNSServiceFlagsAllowRemoteQuery) != 0;
+	
+	// Some clients use mDNS for lightweight copy protection, registering a pseudo-service with
+	// a port number of zero. When two instances of the protected client are allowed to run on one
+	// machine, we don't want to see misleading "Bogus client" messages in syslog and the console.
+	if (service->port.NotAnInteger)
+		{
+		int count = CountExistingRegistrations(&srv, service->port);
+		if (count)
+			LogMsg("Client application registered %d identical instances of service %##s port %u.",
+				count+1, srv.c, mDNSVal16(service->port));
+		}
+
+	LogOperation("%3d: DNSServiceRegister(%##s, %u) START", request->sd, srv.c, mDNSVal16(service->port));
+	result = register_service_instance(request, &d);
+	
+	if (!result && !*domain)
+		{
+		DNameListElem *ptr, *def_domains = mDNSPlatformGetRegDomainList();
+		for (ptr = def_domains; ptr; ptr = ptr->next)
+			register_service_instance(request, &ptr->name);
+		    // note that we don't report errors for non-local, non-explicit domains
+		mDNS_FreeDNameList(def_domains);
+		}
+	
+finish:
     deliver_error(request, result);
     if (result != mStatus_NoError) 
         {
@@ -1399,59 +2137,81 @@ static void handle_regservice_request(request_state *request)
     return;
 
 bad_param:
+	//if (service) freeL("service_info", service);	Don't think we should do this -- abort_request will free it a second time and crash
     deliver_error(request, mStatus_BadParamErr);
     abort_request(request);
     unlink_request(request);
     }
 
-
-
-
 // service registration callback performs three duties - frees memory for deregistered services,
 // handles name conflicts, and delivers completed registration information to the client (via
 // process_service_registraion())
 
-static void regservice_callback(mDNS *const m _UNUSED, ServiceRecordSet *const srs, mStatus result)
+static void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, mStatus result)
     {
     mStatus err;
-    registered_service *r_srv = srs->ServiceContext;
-    request_state *rs = r_srv->request;
-    
-    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;
-        }
+    service_instance *instance = srs->ServiceContext;
+    (void)m; // Unused
+    if (!srs)      { LogMsg("regservice_callback: srs is NULL %d",                 result); return; }
+    if (!instance) { LogMsg("regservice_callback: srs->ServiceContext is NULL %d", result); return; }
 
     if (result == mStatus_NoError)
-        return process_service_registration(srs);
+		LogOperation("%3d: DNSServiceRegister(%##s, %u) REGISTERED  ",  instance->sd, srs->RR_SRV.resrec.name.c, mDNSVal16(srs->RR_SRV.resrec.rdata->u.srv.port));
+	else if (result == mStatus_MemFree)
+		LogOperation("%3d: DNSServiceRegister(%##s, %u) DEREGISTERED",  instance->sd, srs->RR_SRV.resrec.name.c, mDNSVal16(srs->RR_SRV.resrec.rdata->u.srv.port));
+	else if (result == mStatus_NameConflict)
+		LogOperation("%3d: DNSServiceRegister(%##s, %u) NAME CONFLICT", instance->sd, srs->RR_SRV.resrec.name.c, mDNSVal16(srs->RR_SRV.resrec.rdata->u.srv.port));
+	else
+		LogOperation("%3d: DNSServiceRegister(%##s, %u) CALLBACK %d",   instance->sd, srs->RR_SRV.resrec.name.c, mDNSVal16(srs->RR_SRV.resrec.rdata->u.srv.port), result);
+
+    if (result == mStatus_NoError)
+		{
+		if (instance->allowremotequery)
+			{
+			srs->RR_ADV.AllowRemoteQuery = mDNStrue;
+			srs->RR_PTR.AllowRemoteQuery = mDNStrue;
+			srs->RR_SRV.AllowRemoteQuery = mDNStrue;
+			srs->RR_TXT.AllowRemoteQuery = mDNStrue;
+			}
+        process_service_registration(srs);
+        if (instance->autoname && CountPeerRegistrations(m, srs) == 0)
+        	RecordUpdatedNiceLabel(m, 0);	// Successfully got new name, tell user immediately
+		return;
+		}
     else if (result == mStatus_MemFree)
         {
-        if (r_srv->rename_on_memfree)
+        if (instance->rename_on_memfree)
             {
-            r_srv->rename_on_memfree = 0;
-            r_srv->name = gmDNS->nicelabel;
-            err = mDNS_RenameAndReregisterService(gmDNS, srs, &r_srv->name);
-            if (err) LogMsg("ERROR: regservice_callback - RenameAndReregisterService returned %d", err);
+            instance->rename_on_memfree = 0;
+            instance->name = gmDNS->nicelabel;
+            err = mDNS_RenameAndReregisterService(gmDNS, srs, &instance->name);
+            if (err) LogMsg("ERROR: regservice_callback - RenameAndReregisterService returned %ld", err);
             // error should never happen - safest to log and continue
             }
         else 
             {
-			free_service_registration(r_srv);
+			free_service_instance(instance);
             return;
             }
         }
     else if (result == mStatus_NameConflict)
     	{
-        if (r_srv->autoname || r_srv->renameonconflict)
+        if (instance->autoname && CountPeerRegistrations(m, srs) == 0)
+        	{
+        	// On conflict for an autoname service, rename and reregister *all* autoname services
+			IncrementLabelSuffix(&m->nicelabel, mDNStrue);
+			m->MainCallback(m, mStatus_ConfigChanged);
+        	}
+        else if (instance->autoname || instance->autorename)
             {
             mDNS_RenameAndReregisterService(gmDNS, srs, mDNSNULL);
             return;
             }
         else
             {
-			free_service_registration(r_srv);
+		    request_state *rs = instance->request;
+			if (!rs) { LogMsg("ERROR: regservice_callback: received result %ld with a NULL request pointer", result); return; }
+			free_service_instance(instance);
 			if (deliver_async_error(rs, reg_service_reply, result) < 0) 
                 {
                 abort_request(rs);
@@ -1462,7 +2222,10 @@ static void regservice_callback(mDNS *const m _UNUSED, ServiceRecordSet *const s
     	} 
     else 
         {
-        LogMsg("ERROR: unknown result in regservice_callback: %d", result);
+		request_state *rs = instance->request;
+		if (!rs) { LogMsg("ERROR: regservice_callback: received result %ld with a NULL request pointer", result); return; }
+        if (result != mStatus_NATTraversal) LogMsg("ERROR: unknown result in regservice_callback: %ld", result);
+		free_service_instance(instance);
         if (deliver_async_error(rs, reg_service_reply, result) < 0) 
             {
             abort_request(rs);
@@ -1472,37 +2235,47 @@ static void regservice_callback(mDNS *const m _UNUSED, ServiceRecordSet *const s
         }
     }
 
-static mStatus add_record_to_service(request_state *rstate, registered_service *r_srv, uint16_t rrtype, uint16_t rdlen, char *rdata, uint32_t ttl)
+mDNSexport void FreeExtraRR(mDNS *const m, AuthRecord *const rr, mStatus result)
+	{
+	ExtraResourceRecord *extra = (ExtraResourceRecord *)rr->RecordContext;
+	(void)m;  //unused
+	
+	if (result != mStatus_MemFree) { LogMsg("Error: FreeExtraRR invoked with unexpected error %d", result); return; }
+	
+	debugf("%##s: MemFree", rr->resrec.name.c);
+	if (rr->resrec.rdata != &rr->rdatastorage)
+		freeL("Extra RData", rr->resrec.rdata);
+	freeL("ExtraResourceRecord", extra);
+	}
+
+
+static mStatus add_record_to_service(request_state *rstate, service_instance *instance, uint16_t rrtype, uint16_t rdlen, char *rdata, uint32_t ttl)
 	{
-	ServiceRecordSet *srs = r_srv->srs;
+	ServiceRecordSet *srs = &instance->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)
+    extra = mallocL("ExtraResourceRecord", sizeof(*extra) - sizeof(RDataBody) + size);
+    if (!extra)
         {
         my_perror("ERROR: malloc");
-        exit(1);
+		return mStatus_NoMemoryErr;
         }
         
-    bzero(ere, sizeof(ExtraResourceRecord));  // OK if oversized rdata not zero'd
-    extra = &ere->e;
+    bzero(extra, sizeof(ExtraResourceRecord));  // OK if oversized rdata not zero'd
     extra->r.resrec.rrtype = rrtype;
-    extra->r.rdatastorage.MaxRDLength = size;
+    extra->r.rdatastorage.MaxRDLength = (mDNSu16) size;
     extra->r.resrec.rdlength = rdlen;
     memcpy(&extra->r.rdatastorage.u.data, rdata, rdlen);
-
+	
     result =  mDNS_AddRecordToService(gmDNS, srs , extra, &extra->r.rdatastorage, ttl);
-	if (result) { freeL("handle_add_request", ere); return result; }
+	if (result) { freeL("ExtraResourceRecord", extra); return result; }
 
-    ere->key = rstate->hdr.reg_index;
-    ere->next = r_srv->extras;
-    r_srv->extras = ere;
+    extra->ClientID = rstate->hdr.reg_index;
 	return result;
 	}
 
@@ -1512,29 +2285,31 @@ static void handle_add_request(request_state *rstate)
     uint32_t ttl;
     uint16_t rrtype, rdlen;
     char *ptr, *rdata;
-    mStatus result;
+    mStatus result = mStatus_UnknownErr;
     DNSServiceFlags flags;
-	registered_service *local, *global;
-
-	local = rstate->servicepair.local;
-	global = rstate->servicepair.global;
+	service_info *srvinfo = rstate->service_registration;
+	service_instance *i;
 
-	if (!local)
-        {
-        LogMsg("ERROR: handle_add_request - no service registered");
-        deliver_error(rstate, mStatus_UnknownErr);
-        return;
-        }	
+	if (!srvinfo) { LogMsg("handle_add_request called with NULL service_registration"); return; }
 
-    ptr = rstate->msgdata;
+	ptr = rstate->msgdata;
     flags = get_flags(&ptr);
     rrtype = get_short(&ptr);
     rdlen = get_short(&ptr);
     rdata = get_rdata(&ptr, rdlen);
     ttl = get_long(&ptr);
-    
-	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
+	
+    if (!ttl) ttl = DefaultTTLforRRType(rrtype);
+
+	LogOperation("%3d: DNSServiceAddRecord(%##s, %s)", rstate->sd, 
+		(srvinfo->instances) ? srvinfo->instances->srs.RR_SRV.resrec.name.c : NULL, DNSTypeName(rrtype));
+
+	for (i = srvinfo->instances; i; i = i->next)
+		{
+		result = add_record_to_service(rstate, i, rrtype, rdlen, rdata, ttl);
+		if (result && i->default_local) break;
+		else result = mStatus_NoError;  // suppress non-local default errors
+		}
 	
     deliver_error(rstate, result);
     reset_connected_rstate(rstate);
@@ -1554,87 +2329,76 @@ static mStatus update_record(AuthRecord *rr, uint16_t rdlen, char *rdata, uint32
         my_perror("ERROR: malloc");
         exit(1);
         }
-    newrd->MaxRDLength = rdsize;
+    newrd->MaxRDLength = (mDNSu16) 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); }
+	if (result) { LogMsg("ERROR: mDNS_Update - %ld", 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 *lRR, *gRR = NULL;
-    uint16_t rdlen;
+	uint16_t rdlen;
     char *ptr, *rdata;
     uint32_t ttl;
-    mStatus result;
-	
-    if (rstate->hdr.reg_index == TXT_RECORD_INDEX)
-        {
-		if (!rstate->servicepair.local)
-            {
-            deliver_error(rstate, mStatus_BadParamErr);
-            return;
-            }
-		lRR = &rstate->servicepair.local->srs->RR_TXT;
-		if (rstate->servicepair.global) gRR = &rstate->servicepair.global->srs->RR_TXT;
-        }
-    else
-        {
-		if (rstate->servicepair.local) // registered service
+    mStatus result = mStatus_BadReferenceErr;
+	service_info *srvinfo = rstate->service_registration;
+	service_instance *i;
+	AuthRecord *rr = NULL;
+
+	// get the message data
+	ptr = rstate->msgdata;
+    get_flags(&ptr);	// flags unused
+    rdlen = get_short(&ptr);
+    rdata = get_rdata(&ptr, rdlen);
+    ttl = get_long(&ptr);	
+
+	if (rstate->reg_recs)
+		{
+		// update an individually registered record
+		registered_record_entry *reptr;
+		for (reptr = rstate->reg_recs; reptr; reptr = reptr->next)
 			{
-			if (find_extras_by_key(rstate, &lRR, &gRR))
-				{ deliver_error(rstate, mStatus_BadReferenceErr); return; }
+			if (reptr->key == rstate->hdr.reg_index)
+				{
+				result = update_record(reptr->rr, rdlen, rdata, ttl);
+				goto end;
+				}
 			}
+		result = mStatus_BadReferenceErr;
+		goto end;
+		}
+
+	// update a record from a service record set
+	if (!srvinfo) { result = mStatus_BadReferenceErr;  goto end; }
+	for (i = srvinfo->instances; i; i = i->next)
+		{
+		if (rstate->hdr.reg_index == TXT_RECORD_INDEX) rr = &i->srs.RR_TXT;
 		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;
+			ExtraResourceRecord *e;
+			for (e = i->srs.Extras; e; e = e->next)
+				if (e->ClientID == rstate->hdr.reg_index) { rr = &e->r; break; }			
 			}
+
+		if (!rr) { result = mStatus_BadReferenceErr; goto end; }
+		result = update_record(rr, rdlen, rdata, ttl);
+		if (result && i->default_local) goto end;
+		else result = mStatus_NoError;  // suppress non-local default errors
 		}
 
-	// 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);
+end:
+	LogOperation("%3d: DNSServiceUpdateRecord(%##s, %s)", rstate->sd,
+		(srvinfo->instances) ? srvinfo->instances->srs.RR_SRV.resrec.name.c : NULL,
+		rr ? DNSTypeName(rr->resrec.rrtype) : "<NONE>");
 
-	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 _UNUSED, AuthRecord *const rr, RData *oldrd)
+static void update_callback(mDNS *const m, AuthRecord *const rr, RData *oldrd)
     {    
+    (void)m; // Unused
     if (oldrd != &rr->rdatastorage) freeL("update_callback", oldrd);
     }
     
@@ -1643,8 +2407,8 @@ 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;
+    service_instance *instance = srs->ServiceContext;
+    request_state *req = instance->request;
 
 
     err = gen_rr_response(&srs->RR_SRV.resrec.name, srs->RR_SRV.resrec.InterfaceID, req, &rep);
@@ -1668,59 +2432,63 @@ static void process_service_registration(ServiceRecordSet *const srs)
     else append_reply(req, rep);
     }
 
-static void free_service_registration(registered_service *srv)
+static void free_service_instance(service_instance *srv)
 	{
 	request_state *rstate = srv->request;
-	extra_record_entry *extra;
+	ExtraResourceRecord *e = srv->srs.Extras, *tmp;
 	
 	// 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;
+		service_instance *ptr = rstate->service_registration->instances, *prev = NULL;
+		while (ptr)
+			{
+			if (ptr == srv)
+				{
+				if (prev) prev->next = ptr->next;
+				else rstate->service_registration->instances = ptr->next;
+				break;
+				}
+			prev = ptr;
+			ptr = ptr->next;
+			}
 		}
-
-	while (srv->extras)
+	
+	while(e)
 		{
-		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);
+		e->r.RecordContext = e;
+		tmp = e;
+		e = e->next;
+		FreeExtraRR(gmDNS, &tmp->r, mStatus_MemFree);
 		}
 	
 	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)
     {
-    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 (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;	
+	service_info *info = context;
+	service_instance *i, *p;
+	if (!info) { LogMsg("regservice_termination_callback context is NULL"); return; }
+	if (!info->request) { LogMsg("regservice_termination_callback info->request is NULL"); return; }
+	i = info->instances;
+	while (i)
+		{
+		p = i;
+		i = i->next;
+		p->request = NULL;  // clear back pointer
+		// only safe to free memory if registration is not valid, ie deregister fails (which invalidates p)
+		LogOperation("%3d: DNSServiceRegister(%##s, %u) STOP", info->request->sd, p->srs.RR_SRV.resrec.name.c, mDNSVal16(p->srs.RR_SRV.resrec.rdata->u.srv.port));
+		if (mDNS_DeregisterService(gmDNS, &p->srs)) free_service_instance(p);
+		}
+	info->request->service_registration = NULL; // clear pointer from request back to info
+	freeL("service_info", info);
 	}
 
-
 static void handle_regrecord_request(request_state *rstate)
     {
     AuthRecord *rr;
-    regrecord_callback_context *rcc;
     registered_record_entry *re;
     mStatus result;
     
@@ -1738,19 +2506,16 @@ static void handle_regrecord_request(request_state *rstate)
         deliver_error(rstate, mStatus_BadParamErr);
         return;
         }
-	
-    rcc = mallocL("hanlde_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("hanlde_regrecord_request", sizeof(registered_record_entry));
+    re = mallocL("handle_regrecord_request", sizeof(registered_record_entry));
     if (!re) goto malloc_error;
     re->key = rstate->hdr.reg_index;
     re->rr = rr;
+    re->rstate = rstate;
+    re->client_context = rstate->hdr.client_context;
+    rr->RecordContext = re;
+    rr->RecordCallback = regrecord_callback;
     re->next = rstate->reg_recs;
     rstate->reg_recs = re;
 
@@ -1760,6 +2525,10 @@ static void handle_regrecord_request(request_state *rstate)
         rstate->termination_context = rstate;
     	}
     
+    if (rr->resrec.rroriginalttl == 0)
+        rr->resrec.rroriginalttl = DefaultTTLforRRType(rr->resrec.rrtype);
+    
+	LogOperation("%3d: DNSServiceRegisterRecord %s", rstate->sd, RRDisplayString(gmDNS, &rr->resrec));
     result = mDNS_Register(gmDNS, rr);
     deliver_error(rstate, result); 
     reset_connected_rstate(rstate);
@@ -1770,41 +2539,57 @@ malloc_error:
     return;
     }
 
-static void regrecord_callback(mDNS *const m _UNUSED, AuthRecord *const rr, mStatus result)
+static void regrecord_callback(mDNS *const m, AuthRecord * rr, mStatus result)
     {
-    regrecord_callback_context *rcc = rr->RecordContext;
+    registered_record_entry *re = rr->RecordContext;
+	request_state *rstate = re ? re->rstate : NULL;
     int len;
     reply_state *reply;
     transfer_state ts;
+    (void)m; // Unused
 
-    if (result == mStatus_MemFree) 	
-        { 
-        freeL("regrecord_callback", rcc);
-        rr->RecordContext = NULL;        
-        freeL("regrecord_callback", rr);
-        return; 
-        }
-
+	if (!re)
+		{
+		// parent struct alreadt freed by termination callback
+		if (!result) LogMsg("Error: regrecord_callback: successful registration of orphaned record");
+		else
+			{
+			if (result != mStatus_MemFree) LogMsg("regrecord_callback: error %d received after parent termination", result);
+			freeL("regrecord_callback", rr);
+			}			
+		return;
+		}
+	
     // 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(gmDNS, rr->resrec.InterfaceID);
-    reply->rhdr->error = result;
+    reply = create_reply(reg_record_reply, len, rstate);
+    reply->mhdr->client_context = re->client_context;
+    reply->rhdr->flags = dnssd_htonl(0);
+    reply->rhdr->ifi = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS, rr->resrec.InterfaceID));
+    reply->rhdr->error = dnssd_htonl(result);
 
+	if (result)
+		{
+		// unlink from list, free memory
+		registered_record_entry **ptr = &re->rstate->reg_recs;			
+		while (*ptr && (*ptr) != re) ptr = &(*ptr)->next;
+		if (!*ptr) { LogMsg("regrecord_callback - record not in list!"); return; }			
+		*ptr = (*ptr)->next;
+		freeL("regrecord_callback", re->rr);
+		re->rr = rr = NULL;
+		freeL("regrecord_callback", re);
+		re = NULL;
+		}
+	
     ts = send_msg(reply);
-    if (ts == t_error || ts == t_terminated) 
-        {
-        abort_request(rcc->rstate);
-        unlink_request(rcc->rstate);
-        }
+	
+    if (ts == t_error || ts == t_terminated) { abort_request(rstate); unlink_request(rstate); }
     else if (ts == t_complete) freeL("regrecord_callback", reply);
-    else if (ts == t_morecoming) append_reply(rcc->rstate, reply);   // client is blocked, link reply into list
-    }
+    else if (ts == t_morecoming) append_reply(rstate, reply);   // client is blocked, link reply into list
+	}
 
 static void connected_registration_termination(void *context)
     {
@@ -1815,32 +2600,36 @@ static void connected_registration_termination(void *context)
         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;
-            }
+		fptr->rr->RecordContext = NULL;
+        mDNS_Deregister(gmDNS, fptr->rr);		
         freeL("connected_registration_termination", fptr);
-        }
-    }
+		}
+	}
     
-
-
 static void handle_removerecord_request(request_state *rstate)
     {
-    mStatus err;
+    mStatus err = mStatus_BadReferenceErr;
     char *ptr;
+	service_info *srvinfo = rstate->service_registration;
 
     ptr = rstate->msgdata;
     get_flags(&ptr);	// flags unused
 
-    if (rstate->servicepair.local) err = remove_extra_rr_from_service(rstate);
-    else err = remove_record(rstate);
-
+	if (rstate->reg_recs)  err = remove_record(rstate);  // remove individually registered record
+	else if (!srvinfo) LogOperation("%3d: DNSServiceRemoveRecord (bad ref)", rstate->sd);
+    else
+		{
+		LogOperation("%3d: DNSServiceRemoveRecord(%##s, %s)", rstate->sd,
+			(srvinfo->instances) ? srvinfo->instances->srs.RR_SRV.resrec.name.c : NULL);
+		service_instance *i;
+		for (i = srvinfo->instances; i; i = i->next)
+			{
+			err = remove_extra(rstate, i);
+			if (err && i->default_local) break;
+			else err = mStatus_NoError;  // suppress non-local default errors
+			}
+		}
+	
     reset_connected_rstate(rstate);
     if (deliver_error(rstate, err) < 0)
         {
@@ -1853,76 +2642,41 @@ static void handle_removerecord_request(request_state *rstate)
 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;
-            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;
-    	}
-    return err;
+    registered_record_entry *e, **ptr = &rstate->reg_recs;
+	
+    while(*ptr && (*ptr)->key != rstate->hdr.reg_index) ptr = &(*ptr)->next;
+	if (!*ptr) { LogMsg("DNSServiceRemoveRecord - bad reference"); return mStatus_BadReferenceErr; }
+	e = *ptr;
+	*ptr = e->next; // unlink
+	
+	LogOperation("%3d: DNSServiceRemoveRecord(%#s)", rstate->sd, e->rr->resrec.name.c);	
+	shared = e->rr->resrec.RecordType == kDNSRecordTypeShared;
+	e->rr->RecordContext = NULL;
+	err = mDNS_Deregister(gmDNS, e->rr);
+	if (err)
+		{
+		LogMsg("ERROR: remove_record, mDNS_Deregister: %ld", err);
+		freeL("remove_record", e->rr);
+		freeL("remove_record", e);
+		}
+	return err;
     }
 
 
-static mStatus remove_extra(request_state *rstate, registered_service *serv)
+static mStatus remove_extra(request_state *rstate, service_instance *serv)
 	{
 	mStatus err = mStatus_BadReferenceErr;
-	extra_record_entry *ptr, *prev = NULL;
-    
-    ptr = serv->extras;
-    while (ptr)
+	ExtraResourceRecord *ptr;
+
+	for (ptr = serv->srs.Extras; ptr; ptr = ptr->next)
 		{
-		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;
+		if (ptr->ClientID == rstate->hdr.reg_index) // found match
+			return mDNS_RemoveRecordFromService(gmDNS, &serv->srs, ptr, FreeExtraRR, ptr);
 		}
 	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)
     {
@@ -1956,7 +2710,7 @@ static void handle_enum_request(request_state *rstate)
     	}
 
     // allocate context structures
-    def = mallocL("hanlde_enum_request", sizeof(domain_enum_t));
+    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)
@@ -1985,6 +2739,7 @@ static void handle_enum_request(request_state *rstate)
 	if (!InterfaceID) InterfaceID = mDNSInterface_LocalOnly;
 	
     // make the calls
+	LogOperation("%3d: DNSServiceEnumerateDomains(%X)", rstate->sd, flags);
     err = mDNS_GetDomains(gmDNS, &all->question, all->type, NULL, InterfaceID, enum_result_callback, all);
     if (err == mStatus_NoError)
         err = mDNS_GetDomains(gmDNS, &def->question, def->type, NULL, InterfaceID, enum_result_callback, def);
@@ -2013,12 +2768,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 _UNUSED, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
+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;
+    (void)m; // Unused
 
     if (answer->rrtype != kDNSType_PTR) return;
     if (AddRecord)
@@ -2028,7 +2784,10 @@ static void enum_result_callback(mDNS *const m _UNUSED, DNSQuestion *question, c
             flags |= kDNSServiceFlagsDefault;
     	}
     ConvertDomainNameToCString(&answer->rdata->u.name, domain);
-    reply = format_enumeration_reply(de->rstate, domain, flags, mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS, answer->InterfaceID), kDNSServiceErr_NoError);
+	// note that we do NOT propagate specific interface indexes to the client - for example, a domain we learn from
+	// a machine's system preferences may be discovered on the LocalOnly interface, but should be browsed on the
+	// network, so we just pass kDNSServiceInterfaceIndexAny
+    reply = format_enumeration_reply(de->rstate, domain, flags, kDNSServiceInterfaceIndexAny, kDNSServiceErr_NoError);
     if (!reply)
     	{
         LogMsg("ERROR: enum_result_callback, format_enumeration_reply");
@@ -2041,7 +2800,7 @@ static void enum_result_callback(mDNS *const m _UNUSED, DNSQuestion *question, c
 
 static reply_state *format_enumeration_reply(request_state *rstate, const char *domain, DNSServiceFlags flags, uint32_t ifi, DNSServiceErrorType err)
     {
-    int len;
+    size_t len;
     reply_state *reply;
     char *data;
     
@@ -2052,9 +2811,9 @@ static reply_state *format_enumeration_reply(request_state *rstate, const char *
     len += strlen(domain) + 1;
   
     reply = create_reply(enumeration_reply, len, rstate);
-    reply->rhdr->flags = flags;
-    reply->rhdr->ifi = ifi;  
-    reply->rhdr->error = err;
+    reply->rhdr->flags = dnssd_htonl(flags);
+    reply->rhdr->ifi = dnssd_htonl(ifi); 
+    reply->rhdr->error = dnssd_htonl(err);
     data = reply->sdata;
     put_string(domain, &data);
     return reply;
@@ -2079,6 +2838,7 @@ static void handle_reconfirm_request(request_state *rstate)
 
     rr = read_rr_from_ipc_msg(rstate->msgdata, 0, 1);
     if (!rr) return;
+	LogOperation("%3d: DNSServiceReconfirmRecord(%##s) %s", rstate->sd, RRDisplayString(gmDNS, &rr->resrec));
     mDNS_ReconfirmByValue(gmDNS, &rr->resrec);
     abort_request(rstate);
     unlink_request(rstate);
@@ -2102,7 +2862,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, int validate_flags)
+static AuthRecord *read_rr_from_ipc_msg(char *msgbuf, int GetTTL, int validate_flags)
     {
     char *rdata, name[256];
     AuthRecord *rr;
@@ -2140,25 +2900,23 @@ static AuthRecord *read_rr_from_ipc_msg(char *msgbuf, int ttl, int validate_flag
         exit(1);
         }
     bzero(rr, sizeof(AuthRecord));  // ok if oversized rdata not zero'd
-    rr->resrec.rdata = &rr->rdatastorage;
-    rr->resrec.InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS, interfaceIndex);
+    
+    mDNS_SetupResourceRecord(rr, mDNSNULL, mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS, interfaceIndex),
+		type, 0, (flags & kDNSServiceFlagsShared) ? kDNSRecordTypeShared : kDNSRecordTypeUnique, mDNSNULL, mDNSNULL);
+    
     if (!MakeDomainNameFromDNSNameString(&rr->resrec.name, name))
     	{
         LogMsg("ERROR: bad name: %s", name);
         freeL("read_rr_from_ipc_msg", rr);
         return NULL;
     	}
-    rr->resrec.rrtype = type;
-	if ((flags & kDNSServiceFlagsShared) == kDNSServiceFlagsShared)
-        rr->resrec.RecordType = kDNSRecordTypeShared;
-    if ((flags & kDNSServiceFlagsUnique) == kDNSServiceFlagsUnique)
-        rr->resrec.RecordType = kDNSRecordTypeUnique;
+    if (flags & kDNSServiceFlagsAllowRemoteQuery) rr->AllowRemoteQuery  = mDNStrue;
     rr->resrec.rrclass = class;
     rr->resrec.rdlength = rdlen;
     rr->resrec.rdata->MaxRDLength = rdlen;
     rdata = get_rdata(&msgbuf, rdlen);
     memcpy(rr->resrec.rdata->u.data, rdata, rdlen);
-    if (ttl)	
+    if (GetTTL)	
     	{
         rr->resrec.rroriginalttl = get_long(&msgbuf);
     	}
@@ -2193,14 +2951,16 @@ static mStatus gen_rr_response(domainname *servicename, mDNSInterfaceID id, requ
     len = sizeof(DNSServiceFlags);
     len += sizeof(uint32_t);  // if index
     len += sizeof(DNSServiceErrorType);
-    len += strlen(namestr) + 1;
-    len += strlen(typestr) + 1;
-    len += strlen(domstr) + 1;
+    len += (int) (strlen(namestr) + 1);
+    len += (int) (strlen(typestr) + 1);
+    len += (int) (strlen(domstr) + 1);
     
     *rep = create_reply(query_reply, len, request);
-    (*rep)->rhdr->flags = 0;
-    (*rep)->rhdr->ifi = mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS, id);
-    (*rep)->rhdr->error = kDNSServiceErr_NoError;    
+
+    (*rep)->rhdr->flags = dnssd_htonl(0);
+    (*rep)->rhdr->ifi = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS, id));
+    (*rep)->rhdr->error = dnssd_htonl(kDNSServiceErr_NoError);
+
     data = (*rep)->sdata;
     
     put_string(namestr, &data);
@@ -2279,6 +3039,16 @@ static int read_msg(request_state *rs)
         if (nread == 0)  	{ rs->ts = t_terminated;  return t_terminated;  	}
         if (nread < 0) goto rerror;
         rs->hdr_bytes += nread;
+        if (rs->hdr_bytes == sizeof(ipc_msg_hdr))
+        	{
+        	ConvertHeaderBytes(&rs->hdr);
+			if (rs->hdr.version != VERSION)
+				{
+				LogMsg("ERROR: read_msg - client version 0x%08X does not match daemon version 0x%08X", rs->hdr.version, VERSION);
+				rs->ts = t_error;
+				return t_error;
+				}
+			}
         if (rs->hdr_bytes > sizeof(ipc_msg_hdr))
             {
             LogMsg("ERROR: read_msg - read too many header bytes");
@@ -2329,7 +3099,7 @@ static int read_msg(request_state *rs)
     return rs->ts;
 
 rerror:
-    if (errno == EAGAIN || errno == EINTR) return rs->ts;	
+    if (dnssd_errno() == dnssd_EWOULDBLOCK || dnssd_errno() == dnssd_EINTR) return t_morecoming;	
     my_perror("ERROR: read_msg");
     rs->ts = t_error;
     return t_error;
@@ -2353,13 +3123,16 @@ static int send_msg(reply_state *rs)
         return t_complete;
         }
 
+	ConvertHeaderBytes(rs->mhdr);
     nwriten = send(rs->sd, rs->msgbuf + rs->nwriten, rs->len - rs->nwriten, 0);
+	ConvertHeaderBytes(rs->mhdr);
     if (nwriten < 0)
     	{
-        if (errno == EINTR || errno == EAGAIN) nwriten = 0;
+        if (dnssd_errno() == dnssd_EINTR || dnssd_errno() == dnssd_EWOULDBLOCK) nwriten = 0;
         else
             {
-            if (errno == EPIPE)
+#if !defined(PLATFORM_NO_EPIPE)
+            if (dnssd_errno() == EPIPE)
             	{
                 LogMsg("broken pipe - cleanup should be handled by run-loop read wakeup");
                 rs->ts = t_terminated;
@@ -2367,6 +3140,7 @@ static int send_msg(reply_state *rs)
                 return t_terminated;  
             	}
             else
+#endif
             	{
                 my_perror("ERROR: send\n");
                 rs->ts = t_error;
@@ -2386,7 +3160,7 @@ static int send_msg(reply_state *rs)
 
 
 
-static reply_state *create_reply(reply_op_t op, int datalen, request_state *request)
+static reply_state *create_reply(reply_op_t op, size_t datalen, request_state *request)
 {
     reply_state *reply;
     int totallen;
@@ -2398,7 +3172,7 @@ static reply_state *create_reply(reply_op_t op, int datalen, request_state *requ
         return NULL;
         }
     
-    totallen = datalen + sizeof(ipc_msg_hdr);
+    totallen = (int) (datalen + sizeof(ipc_msg_hdr));
     reply = mallocL("create_reply", sizeof(reply_state));
     if (!reply) 
         {
@@ -2421,7 +3195,7 @@ static reply_state *create_reply(reply_op_t op, int datalen, request_state *requ
     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->op = op;
     reply->mhdr->datalen = totallen - sizeof(ipc_msg_hdr);
     return reply;
     }
@@ -2432,10 +3206,11 @@ static int deliver_error(request_state *rstate, mStatus err)
     int nwritten = -1;
     undelivered_error_t *undeliv;
     
+    err = dnssd_htonl(err);
     nwritten = send(rstate->errfd, &err, sizeof(mStatus), 0);
     if (nwritten < (int)sizeof(mStatus))
         {
-        if (errno == EINTR || errno == EAGAIN)   
+        if (dnssd_errno() == dnssd_EINTR || dnssd_errno() == dnssd_EWOULDBLOCK)   
             nwritten = 0;
         if (nwritten < 0)
             {
@@ -2455,36 +3230,32 @@ static int deliver_error(request_state *rstate, mStatus err)
         rstate->u_err = undeliv;
         return 0;
     }
-    if (rstate->errfd != rstate->sd) close(rstate->errfd);
     return 0;
     
 error:
-    if (rstate->errfd != rstate->sd) close(rstate->errfd);
     return -1;
     
     }
            
 
-// returns 0 on success, -1 if send is incomplete, or on terminal failre (request is aborted)
+// returns 0 on success, -1 if send is incomplete, or on terminal failure (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);
+    nwritten = send(rs->u_err->sd, (char *)(&rs->u_err->err) + rs->u_err->nwritten, sizeof(mStatus) - rs->u_err->nwritten, 0);
     if (nwritten < 0)
         {
-        if (errno == EINTR || errno == EAGAIN)
+        if (dnssd_errno() == dnssd_EINTR || dnssd_errno() == dnssd_EWOULDBLOCK)
             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;
@@ -2506,7 +3277,7 @@ static int deliver_async_error(request_state *rs, reply_op_t op, mStatus err)
     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;
+    reply->rhdr->error = dnssd_htonl(err);
     ts = send_msg(reply);
     if (ts == t_error || ts == t_terminated)
         {
@@ -2525,10 +3296,11 @@ 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);
+	LogOperation("%3d: Removing FD", rs->sd);
     udsSupportRemoveFDFromEventLoop(rs->sd);
-    rs->sd = -1;
-    if (rs->errfd >= 0) close(rs->errfd);
-    rs->errfd = -1;
+    rs->sd = dnssd_InvalidSocket;
+    if (rs->errfd != rs->sd && rs->errfd != dnssd_InvalidSocket) dnssd_close(rs->errfd);
+    rs->errfd = dnssd_InvalidSocket;
 
     // free pending replies
     rep = rs->replies;
@@ -2572,7 +3344,7 @@ static void unlink_request(request_state *rs)
 //hack to search-replace perror's to LogMsg's
 static void my_perror(char *errmsg)
     {
-    LogMsg("%s: %s", errmsg, strerror(errno));
+    LogMsg("%s: %s", errmsg, dnssd_strerror(dnssd_errno()));
     }
 
 // check that the message delivered by the client is sufficiently long to extract the required data from the buffer
@@ -2583,7 +3355,7 @@ static int validate_message(request_state *rstate)
     {
     uint32_t min_size;
     
-    switch(rstate->hdr.op.request_op)
+    switch(rstate->hdr.op)
     	{
         case resolve_request: min_size = 	sizeof(DNSServiceFlags) +	// flags
 						sizeof(uint32_t) + 		// interface
@@ -2626,8 +3398,11 @@ static int validate_message(request_state *rstate)
 						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);	    
+			            break;
+		case setdomain_request: min_size = sizeof(DNSServiceFlags) + sizeof(char);  // flags + domain
+			break; 
+		default:
+            LogMsg("ERROR: validate_message - unsupported request type: %d", rstate->hdr.op);	    
 	    return -1;
 	}    
     
@@ -2636,3 +3411,48 @@ static int validate_message(request_state *rstate)
     }
 
 
+static uint32_t dnssd_htonl(uint32_t l)
+	{
+	uint32_t 	ret;
+	char	*	data;
+
+	data = (char*) &ret;
+
+	put_long(l, &data);
+
+	return ret;
+	}
+
+
+#if defined(_WIN32)
+
+static char * win32_strerror(int inErrorCode)
+	{
+	static char buffer[1024];
+	DWORD       n;
+
+	memset(buffer, 0, sizeof(buffer));
+
+	n = FormatMessageA( 
+			FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 
+			NULL, 
+			(DWORD) inErrorCode,
+			MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ),
+			buffer,
+			sizeof( buffer ),
+			NULL );
+
+	if( n > 0 )
+		{
+		// Remove any trailing CR's or LF's since some messages have them.
+
+		while( ( n > 0 ) && isspace( ( (unsigned char *) buffer)[ n - 1 ] ) )
+			{
+			buffer[ --n ] = '\0';
+			}
+		}
+
+	return buffer;
+	}
+
+#endif
diff --git a/mDNSShared/uds_daemon.h b/mDNSShared/uds_daemon.h
index 0e25022..0b9dfab 100644
--- a/mDNSShared/uds_daemon.h
+++ b/mDNSShared/uds_daemon.h
@@ -3,8 +3,6 @@
  *
  * @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
@@ -31,6 +29,40 @@
     Change History (most recent first):
 
 $Log: uds_daemon.h,v $
+Revision 1.13  2004/12/10 05:27:26  cheshire
+<rdar://problem/3909147> Guard against multiple autoname services of the same type on the same machine
+
+Revision 1.12  2004/12/10 04:28:28  cheshire
+<rdar://problem/3914406> User not notified of name changes for services using new UDS API
+
+Revision 1.11  2004/12/06 21:15:23  ksekar
+<rdar://problem/3884386> mDNSResponder crashed in CheckServiceRegistrations
+
+Revision 1.10  2004/10/26 04:31:44  cheshire
+Rename CountSubTypes() as ChopSubTypes()
+
+Revision 1.9  2004/09/30 00:25:00  ksekar
+<rdar://problem/3695802> Dynamically update default registration domains on config change
+
+Revision 1.8  2004/09/21 21:05:11  cheshire
+Move duplicate code out of mDNSMacOSX/daemon.c and mDNSPosix/PosixDaemon.c,
+into mDNSShared/uds_daemon.c
+
+Revision 1.7  2004/09/17 01:08:55  cheshire
+Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
+  The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
+  declared in that file are ONLY appropriate to single-address-space embedded applications.
+  For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
+
+Revision 1.6  2004/08/11 01:58:49  cheshire
+Remove "mDNS *globalInstance" parameter from udsserver_init()
+
+Revision 1.5  2004/06/18 04:44:58  rpantos
+Use platform layer for socket types
+
+Revision 1.4  2004/06/12 00:51:58  cheshire
+Changes for Windows compatibility
+
 Revision 1.3  2004/01/25 00:03:21  cheshire
 Change to use mDNSVal16() instead of private PORT_AS_NUM() macro
 
@@ -42,28 +74,43 @@ Changes necessary to support mDNSResponder on Linux.
 
 */
 
-#include "mDNSClientAPI.h"
+#include "mDNSEmbeddedAPI.h"
+#include "dnssd_ipc.h"
 
 
 /* Client interface: */
 
 #define SRS_PORT(S) mDNSVal16((S)->RR_SRV.resrec.rdata->u.srv.port)
 
-extern int udsserver_init( mDNS *globalInstance);
+extern int udsserver_init(void);
 
 // 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_info(mDNS *const m);	// print out info about current state
 
 extern void udsserver_handle_configchange(void);
 
 extern int udsserver_exit(void);	// should be called prior to app exit
 
+extern void udsserver_default_reg_domain_changed(const domainname *d, mDNSBool add);
+extern void udsserver_default_browse_domain_changed(const domainname *d, mDNSBool add);
 
 /* 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);
+extern mStatus udsSupportAddFDToEventLoop(dnssd_sock_t fd, udsEventCallback callback, void *context);
+extern mStatus udsSupportRemoveFDFromEventLoop(dnssd_sock_t fd);
+
+// RecordUpdatedNiceLabel() can be a no-op on platforms that don't care about updating the machine's
+// global default service name (was OS X calls the "Computer Name") in response to name conflicts.
+extern void RecordUpdatedNiceLabel(mDNS *const m, mDNSs32 delay);
+
+// Globals and functions defined in uds_daemon.c and also shared with the old "daemon.c" on OS X
+extern mDNS mDNSStorage;
+extern mDNSs32 ChopSubTypes(char *regtype);
+extern AuthRecord *AllocateSubTypes(mDNSs32 NumSubTypes, char *p);
+extern int CountExistingRegistrations(domainname *srv, mDNSIPPort port);
+extern void FreeExtraRR(mDNS *const m, AuthRecord *const rr, mStatus result);
+extern int CountPeerRegistrations(mDNS *const m, ServiceRecordSet *const srs);
diff --git a/mDNSVxWorks/mDNSVxWorks.c b/mDNSVxWorks/mDNSVxWorks.c
index 049f41c..c93e9cb 100644
--- a/mDNSVxWorks/mDNSVxWorks.c
+++ b/mDNSVxWorks/mDNSVxWorks.c
@@ -3,8 +3,6 @@
  *
  * @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
@@ -29,6 +27,42 @@
 	Change History (most recent first):
 
 $Log: mDNSVxWorks.c,v $
+Revision 1.26  2004/10/28 02:00:35  cheshire
+<rdar://problem/3841770> Call pipeDevDelete when disposing of commandPipe
+
+Revision 1.25  2004/10/16 00:17:01  cheshire
+<rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check
+
+Revision 1.24  2004/09/21 21:02:56  cheshire
+Set up ifname before calling mDNS_RegisterInterface()
+
+Revision 1.23  2004/09/17 01:08:57  cheshire
+Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
+  The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
+  declared in that file are ONLY appropriate to single-address-space embedded applications.
+  For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
+
+Revision 1.22  2004/09/17 00:19:11  cheshire
+For consistency with AllDNSLinkGroupv6, rename AllDNSLinkGroup to AllDNSLinkGroupv4
+
+Revision 1.21  2004/09/16 00:24:50  cheshire
+<rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
+
+Revision 1.20  2004/09/14 23:42:36  cheshire
+<rdar://problem/3801296> Need to seed random number generator from platform-layer data
+
+Revision 1.19  2004/09/14 23:16:09  cheshire
+mDNS_SetFQDNs has been renamed to mDNS_SetFQDN
+
+Revision 1.18  2004/08/14 03:22:42  cheshire
+<rdar://problem/3762579> Dynamic DNS UI <-> mDNSResponder glue
+Add GetUserSpecifiedDDNSName() routine
+Convert ServiceRegDomain to domainname instead of C string
+Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs
+
+Revision 1.17  2004/07/29 19:26:03  ksekar
+Plaform-level changes for NATPMP support
+
 Revision 1.16  2004/04/22 05:11:28  bradley
 Added mDNSPlatformUTC for TSIG signed dynamic updates.
 
@@ -54,7 +88,7 @@ Fix code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1005) instead of 2
 
 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.
+Best solution is just to combine mDNSEmbeddedAPI.h and mDNSPlatformFunctions.h into a single file.
 
 Revision 1.8  2003/10/28 10:08:27  bradley
 Removed legacy port 53 support as it is no longer needed.
@@ -63,7 +97,7 @@ Revision 1.7  2003/08/20 05:58:54  bradley
 Removed dependence on modified mDNSCore: define structures/prototypes locally.
 
 Revision 1.6  2003/08/18 23:19:05  cheshire
-<rdar://problem/3382647> mDNSResponder divide by zero in mDNSPlatformTimeNow()
+<rdar://problem/3382647> mDNSResponder divide by zero in mDNSPlatformRawTime()
 
 Revision 1.5  2003/08/15 00:05:04  bradley
 Updated to use name/InterfaceID from new AuthRecord resrec field. Added output of new record sizes.
@@ -132,7 +166,7 @@ mDNS platform plugin for VxWorks.
 	#include	"Support/MiscUtilities.h"
 #endif
 
-#include	"mDNSClientAPI.h"
+#include	"mDNSEmbeddedAPI.h"
 
 #include	"mDNSVxWorks.h"
 
@@ -284,7 +318,7 @@ mDNSlocal mStatus	TearDownTask( mDNS * const inMDNS );
 mDNSlocal void		Task( mDNS *inMDNS );
 mDNSlocal mStatus	TaskInit( mDNS *inMDNS );
 mDNSlocal void		TaskSetupReadSet( mDNS *inMDNS, fd_set *outReadSet, int *outMaxSocket );
-mDNSlocal void		TaskSetupTimeout( mDNSs32 inNextTaskTime, struct timeval *outTimeout );
+mDNSlocal void		TaskSetupTimeout( mDNS *inMDNS, mDNSs32 inNextTaskTime, struct timeval *outTimeout );
 mDNSlocal void		TaskProcessPacket( mDNS *inMDNS, MDNSInterfaceItem *inItem, MDNSSocketRef inSocketRef );
 
 // Utilities
@@ -461,7 +495,7 @@ void	mDNSPlatformClose( mDNS * const inMDNS )
 mStatus
 	mDNSPlatformSendUDP( 
 		const mDNS * const			inMDNS, 
-		const DNSMessage * const	inMsg, 
+		const void * const	        inMsg, 
 		const mDNSu8 * const		inMsgEnd, 
 		mDNSInterfaceID 			inInterfaceID, 
 		const mDNSAddr *			inDstIP, 
@@ -599,7 +633,7 @@ void	mDNSPlatformUnlock( const mDNS * const inMDNS )
 	// (a) handle immediate work (if any) resulting from this API call
 	// (b) calculate the next sleep time between now and the next interesting event
 	
-	if( ( mDNSPlatformTimeNow() - inMDNS->NextScheduledEvent ) >= 0 )
+	if( ( mDNS_TimeNow(inMDNS) - inMDNS->NextScheduledEvent ) >= 0 )
 	{
 		// We only need to send the reschedule event when called from a task other than the mDNS task since if we are 
 		// called from mDNS task, we'll loop back and call mDNS_Execute. This avoids filling up the command queue.
@@ -701,25 +735,30 @@ mDNSexport void	mDNSPlatformMemFree( void *inMem )
 	free( inMem );
 }
 
+//===========================================================================================================================
+//	mDNSPlatformRandomSeed
+//===========================================================================================================================
+
+mDNSexport mDNSu32 mDNSPlatformRandomSeed(void)
+{
+	return( tickGet() );
+}
+
 //===========================================================================================================================
 //	mDNSPlatformTimeInit
 //===========================================================================================================================
 
-mDNSexport mStatus mDNSPlatformTimeInit( mDNSs32 *outTimeNow )
+mDNSexport mStatus mDNSPlatformTimeInit( void )
 {
-	check( outTimeNow );
-	
 	// No special setup is required on VxWorks -- we just use tickGet().
-	
-	*outTimeNow = mDNSPlatformTimeNow();
 	return( mStatus_NoError );
 }
 
 //===========================================================================================================================
-//	mDNSPlatformTimeNow
+//	mDNSPlatformRawTime
 //===========================================================================================================================
 
-mDNSs32	mDNSPlatformTimeNow( void )
+mDNSs32	mDNSPlatformRawTime( void )
 {
 	return( (mDNSs32) tickGet() );
 }
@@ -921,7 +960,7 @@ mDNSlocal void	SetupNames( mDNS * const inMDNS )
 	}
 	check( inMDNS->hostlabel.c[ 0 ] > 0 );
 
-	mDNS_GenerateFQDN( inMDNS );
+	mDNS_SetFQDN( inMDNS );
 	
 	dlog( kDebugLevelInfo, DEBUG_NAME "nice name \"%.*s\"\n", inMDNS->nicelabel.c[ 0 ], &inMDNS->nicelabel.c[ 1 ] );
 	dlog( kDebugLevelInfo, DEBUG_NAME "host name \"%.*s\"\n", inMDNS->hostlabel.c[ 0 ], &inMDNS->hostlabel.c[ 1 ] );
@@ -1020,13 +1059,14 @@ mDNSlocal mStatus	SetupInterface( mDNS * const inMDNS, const struct ifaddrs *inA
 	mStatus							err;
 	MDNSInterfaceItem *				item;
 	MDNSSocketRef					socketRef;
-	const struct sockaddr_in *		ipv4;
+	const struct sockaddr_in *		ipv4, *mask;
 	
 	dlog( kDebugLevelVerbose, DEBUG_NAME "setting up interface (name=%s)\n", inAddr->ifa_name );
 	check( inMDNS );
 	check( inAddr );
 	check( inAddr->ifa_addr );
 	ipv4 = (const struct sockaddr_in *) inAddr->ifa_addr;
+	mask = (const struct sockaddr_in *) inAddr->ifa_netmask;
 	check( outItem );
 	
 	// Allocate memory for the info item.
@@ -1051,11 +1091,14 @@ mDNSlocal mStatus	SetupInterface( mDNS * const inMDNS, const struct ifaddrs *inA
 	
 	// Register this interface with mDNS.
 	
-	item->hostSet.InterfaceID 			= (mDNSInterfaceID) item;
-	item->hostSet.ip.type 				= mDNSAddrType_IPv4;
-	item->hostSet.ip.ip.v4.NotAnInteger	= ipv4->sin_addr.s_addr;
-	item->hostSet.Advertise       		= inMDNS->AdvertiseLocalAddresses;
-	item->hostSet.McastTxRx       		= mDNStrue;
+	item->hostSet.InterfaceID             = (mDNSInterfaceID) item;
+	item->hostSet.ip  .type               = mDNSAddrType_IPv4;
+	item->hostSet.ip  .ip.v4.NotAnInteger = ipv4->sin_addr.s_addr;
+	item->hostSet.mask.type               = mDNSAddrType_IPv4;
+	item->hostSet.mask.ip.v4.NotAnInteger = mask->sin_addr.s_addr;
+	item->hostSet.ifname[0]               = 0;
+	item->hostSet.Advertise               = inMDNS->AdvertiseLocalAddresses;
+	item->hostSet.McastTxRx               = mDNStrue;
 
 	err = mDNS_RegisterInterface( inMDNS, &item->hostSet );
 	require_noerr( err, exit );
@@ -1177,7 +1220,7 @@ mDNSlocal mStatus
 		// Join the all-DNS multicast group so we receive Multicast DNS packets.
 		
 		ip.NotAnInteger 			= ipv4->sin_addr.s_addr;
-		mreq.imr_multiaddr.s_addr 	= AllDNSLinkGroup.NotAnInteger;
+		mreq.imr_multiaddr.s_addr 	= AllDNSLinkGroupv4.NotAnInteger;
 		mreq.imr_interface.s_addr 	= ip.NotAnInteger;
 		err = setsockopt( socketRef, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mreq, sizeof( mreq ) );
 		check_errno( err, errno );
@@ -1187,7 +1230,7 @@ mDNSlocal mStatus
 		memset( &addr, 0, sizeof( addr ) );
 		addr.sin_family 		= AF_INET;
 		addr.sin_port 			= inPort.NotAnInteger;
-		addr.sin_addr.s_addr 	= AllDNSLinkGroup.NotAnInteger;
+		addr.sin_addr.s_addr 	= AllDNSLinkGroupv4.NotAnInteger;
 		err = bind( socketRef, (struct sockaddr *) &addr, sizeof( addr ) );
 		check_errno( err, errno );
 		
@@ -1292,6 +1335,10 @@ mDNSlocal mStatus	TearDownCommandPipe( mDNS * const inMDNS )
 	if( inMDNS->p->commandPipe != ERROR )
 	{
 		close( inMDNS->p->commandPipe );
+#ifdef _WRS_VXWORKS_5_X
+		// pipeDevDelete is not defined in older versions of VxWorks
+		pipeDevDelete( kMDNSPipeName, FALSE );
+#endif
 		inMDNS->p->commandPipe = ERROR;
 	}	
 	return( mStatus_NoError );
@@ -1511,7 +1558,7 @@ mDNSlocal void	Task( mDNS *inMDNS )
 			
 			inMDNS->p->rescheduled = 0;
 			nextTaskTime = mDNS_Execute( inMDNS );
-			TaskSetupTimeout( nextTaskTime, &timeout );
+			TaskSetupTimeout( inMDNS, nextTaskTime, &timeout );
 			
 			// Wait until something occurs (e.g. command, incoming packet, or timeout).
 			
@@ -1524,7 +1571,7 @@ mDNSlocal void	Task( mDNS *inMDNS )
 			{
 				// Next task timeout occurred. Loop back up to give mDNS core a chance to work.
 				
-				dlog( kDebugLevelChatty, DEBUG_NAME "next task timeout occurred (%ld)\n", mDNSPlatformTimeNow() );
+				dlog( kDebugLevelChatty, DEBUG_NAME "next task timeout occurred (%ld)\n", mDNS_TimeNow(inMDNS) );
 				continue;
 			}
 			
@@ -1639,13 +1686,13 @@ mDNSlocal void	TaskSetupReadSet( mDNS *inMDNS, fd_set *outReadSet, int *outMaxSo
 //	TaskSetupTimeout
 //===========================================================================================================================
 
-mDNSlocal void	TaskSetupTimeout( mDNSs32 inNextTaskTime, struct timeval *outTimeout )
+mDNSlocal void	TaskSetupTimeout( mDNS *inMDNS, mDNSs32 inNextTaskTime, struct timeval *outTimeout )
 {
 	mDNSs32		delta;
 	
 	// Calculate how long to wait before performing idle processing.
 	
-	delta = inNextTaskTime - mDNSPlatformTimeNow();
+	delta = inNextTaskTime - mDNS_TimeNow(inMDNS);
 	if( delta <= 0 )
 	{
 		// The next task time is now or in the past. Set the timeout to fire immediately.
@@ -1702,7 +1749,7 @@ mDNSlocal void	TaskProcessPacket( mDNS *inMDNS, MDNSInterfaceItem *inItem, MDNSS
 		srcAddr.ip.v4.NotAnInteger 	= addr.sin_addr.s_addr;
 		srcPort.NotAnInteger		= addr.sin_port;
 		dstAddr.type				= mDNSAddrType_IPv4;
-		dstAddr.ip.v4				= AllDNSLinkGroup;
+		dstAddr.ip.v4				= AllDNSLinkGroupv4;
 		dstPort						= MulticastDNSPort;
 		
 		dlog( kDebugLevelChatty, DEBUG_NAME "packet received\n" );
@@ -1719,7 +1766,7 @@ mDNSlocal void	TaskProcessPacket( mDNS *inMDNS, MDNSInterfaceItem *inItem, MDNSS
 		// Dispatch the packet to mDNS.
 		
 		packetEndPtr = ( (mDNSu8 *) &packet ) + n;
-		mDNSCoreReceive( inMDNS, &packet, packetEndPtr, &srcAddr, srcPort, &dstAddr, dstPort, inItem->hostSet.InterfaceID, 255 );
+		mDNSCoreReceive( inMDNS, &packet, packetEndPtr, &srcAddr, srcPort, &dstAddr, dstPort, inItem->hostSet.InterfaceID );
 	}
 	
 	// Update counters.
diff --git a/mDNSVxWorks/mDNSVxWorks.h b/mDNSVxWorks/mDNSVxWorks.h
index 537c0ee..9526ae5 100644
--- a/mDNSVxWorks/mDNSVxWorks.h
+++ b/mDNSVxWorks/mDNSVxWorks.h
@@ -3,8 +3,6 @@
  *
  * @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
@@ -29,6 +27,12 @@
 	Change History (most recent first):
 
 $Log: mDNSVxWorks.h,v $
+Revision 1.3  2004/09/17 01:08:57  cheshire
+Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
+  The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
+  declared in that file are ONLY appropriate to single-address-space embedded applications.
+  For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
+
 Revision 1.2  2003/08/12 19:56:27  cheshire
 Update to APSL 2.0
 
@@ -43,7 +47,7 @@ mDNS platform plugin for VxWorks.
 #include	"vxWorks.h"
 #include	"semLib.h"
 
-#include	"mDNSClientAPI.h"
+#include	"mDNSEmbeddedAPI.h"
 
 #ifdef	__cplusplus
 	extern "C" {
diff --git a/mDNSWindows/Applications/DNSServiceTest/ToolWin32.mcp b/mDNSWindows/Applications/DNSServiceTest/ToolWin32.mcp
deleted file mode 100644
index 21a4ed63564df5c789d5ab609f17095235e893fe..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 284642
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

diff --git a/mDNSWindows/Applications/ExplorerPlugin/ExplorerPlugin.sln b/mDNSWindows/Applications/ExplorerPlugin/ExplorerPlugin.sln
deleted file mode 100644
index 24abed3..0000000
--- a/mDNSWindows/Applications/ExplorerPlugin/ExplorerPlugin.sln
+++ /dev/null
@@ -1,21 +0,0 @@
-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/NSPTool/Tool.mcp b/mDNSWindows/Applications/NSPTool/Tool.mcp
deleted file mode 100644
index a6dcb6f918cb8f4777fa05e4ded5c27a2b0e51a0..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 306146
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
A+yDRo

diff --git a/mDNSWindows/Applications/SystemService/Service.c b/mDNSWindows/Applications/SystemService/Service.c
deleted file mode 100644
index d65fa58..0000000
--- a/mDNSWindows/Applications/SystemService/Service.c
+++ /dev/null
@@ -1,829 +0,0 @@
-/*
- * 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
deleted file mode 100644
index 0347957cafe95e43f4aebadde6e2a867f60be7dc..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 299890
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
R!F<#<x1E1ZApb`({|~hwfT#cf

diff --git a/mDNSWindows/Applications/SystemService/Service2002.sln b/mDNSWindows/Applications/SystemService/Service2002.sln
deleted file mode 100644
index bbebcf4..0000000
--- a/mDNSWindows/Applications/SystemService/Service2002.sln
+++ /dev/null
@@ -1,21 +0,0 @@
-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
deleted file mode 100644
index d7e0bed..0000000
--- a/mDNSWindows/Applications/SystemService/Service2002.vcproj
+++ /dev/null
@@ -1,196 +0,0 @@
-<?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/Tool.mcp b/mDNSWindows/Applications/SystemServiceTest/Tool.mcp
deleted file mode 100644
index 59200136c9ec33e43aa7d23997e28360bd5da598..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 398728
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

diff --git a/mDNSWindows/Applications/SystemServiceTest/Tool2002.sln b/mDNSWindows/Applications/SystemServiceTest/Tool2002.sln
deleted file mode 100644
index 1659ac6..0000000
--- a/mDNSWindows/Applications/SystemServiceTest/Tool2002.sln
+++ /dev/null
@@ -1,21 +0,0 @@
-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/mdnsNSP/NSP.c b/mDNSWindows/Applications/mdnsNSP/NSP.c
deleted file mode 100644
index faf459d..0000000
--- a/mDNSWindows/Applications/mdnsNSP/NSP.c
+++ /dev/null
@@ -1,1367 +0,0 @@
-/*
- * 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
deleted file mode 100644
index 3428a50..0000000
--- a/mDNSWindows/Applications/mdnsNSP/NSP.def
+++ /dev/null
@@ -1,36 +0,0 @@
-;
-; 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
deleted file mode 100644
index 96007ece3f0de0b3628107a5859a41336156938b..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 198118
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
X@;`ru--xjOvXe{x=M<!~KkNS=mky!7

diff --git a/mDNSWindows/Applications/mdnsNSP/ReadMe.txt b/mDNSWindows/Applications/mdnsNSP/ReadMe.txt
deleted file mode 100644
index 86de247..0000000
--- a/mDNSWindows/Applications/mdnsNSP/ReadMe.txt
+++ /dev/null
@@ -1,15 +0,0 @@
-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/CommonServices.h b/mDNSWindows/CommonServices.h
index 2c00724..75eaa2d 100644
--- a/mDNSWindows/CommonServices.h
+++ b/mDNSWindows/CommonServices.h
@@ -3,8 +3,6 @@
  *
  * @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/DLL.NET/AssemblyInfo.cpp b/mDNSWindows/DLL.NET/AssemblyInfo.cpp
new file mode 100755
index 0000000..c32676c
--- /dev/null
+++ b/mDNSWindows/DLL.NET/AssemblyInfo.cpp
@@ -0,0 +1,100 @@
+/*
+ * 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: AssemblyInfo.cpp,v $
+Revision 1.4  2004/07/26 21:03:00  shersche
+enable strong naming for dnssd.NET assembly
+
+Revision 1.3  2004/07/14 19:54:57  shersche
+use version file to get version numbers
+
+Revision 1.2  2004/07/14 15:42:47  shersche
+remove entries for strong authentication
+
+Revision 1.1  2004/06/26 04:01:22  shersche
+Initial revision
+
+
+ */
+    
+#include "stdafx.h"
+#include "WinVersRes.h"
+
+using namespace System::Reflection;
+using namespace System::Runtime::CompilerServices;
+
+//
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+//
+[assembly:AssemblyTitleAttribute("dnssd.NET")];
+[assembly:AssemblyDescriptionAttribute(".NET wrapper for DNS-SD services")];
+[assembly:AssemblyConfigurationAttribute("")];
+[assembly:AssemblyCompanyAttribute("Apple Computer, Inc.")];
+[assembly:AssemblyProductAttribute("")];
+[assembly:AssemblyCopyrightAttribute("Apple Computer, Inc.")];
+[assembly:AssemblyTrademarkAttribute("")];
+[assembly:AssemblyCultureAttribute("")];		
+
+//
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+// You can specify all the value or you can default the Revision and Build Numbers 
+// by using the '*' as shown below:
+
+[assembly:AssemblyVersionAttribute(MASTER_PROD_VERS_STR2)];
+
+//
+// In order to sign your assembly you must specify a key to use. Refer to the
+// Microsoft .NET Framework documentation for more information on assembly
+// signing.
+//
+// Use the attributes below to control which key is used for signing.
+//
+// Notes:
+//   (*) If no key is specified, the assembly is not signed.
+//   (*) KeyName refers to a key that has been installed in the Crypto Service
+//       Provider (CSP) on your machine. KeyFile refers to a file which contains
+//       a key.
+//   (*) If the KeyFile and the KeyName values are both specified, the
+//       following processing occurs:
+//       (1) If the KeyName can be found in the CSP, that key is used.
+//       (2) If the KeyName does not exist and the KeyFile does exist, the key
+//           in the KeyFile is installed into the CSP and used.
+//   (*) In order to create a KeyFile, you can use the sn.exe (Strong Name)
+//       utility
+//        When specifying the KeyFile, the location of the KeyFile should be
+//        relative to the project directory.
+//   (*) Delay Signing is an advanced option - see the Microsoft .NET Framework
+//       documentation for more information on this.
+//
+[assembly:AssemblyDelaySignAttribute(false)];
+[assembly:AssemblyKeyFileAttribute("dnssd_NET.snk")];
+[assembly:AssemblyKeyNameAttribute("")];
diff --git a/mDNSWindows/DLL.NET/PString.h b/mDNSWindows/DLL.NET/PString.h
new file mode 100755
index 0000000..f64b951
--- /dev/null
+++ b/mDNSWindows/DLL.NET/PString.h
@@ -0,0 +1,86 @@
+/*
+ * 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: PString.h,v $
+Revision 1.2  2004/07/19 16:08:56  shersche
+fix problems in UTF8/Unicode string translations
+
+Revision 1.1  2004/06/26 04:01:22  shersche
+Initial revision
+
+
+ */
+    
+#pragma once
+
+using namespace System;
+using namespace System::Text;
+
+namespace Apple
+{
+	__gc class PString
+	{
+	public:
+
+		PString(String* string)
+		{
+			if (string != NULL)
+			{
+				Byte unicodeBytes[] = Encoding::Unicode->GetBytes(string);
+				Byte utf8Bytes[] = Encoding::Convert(Encoding::Unicode, Encoding::UTF8, unicodeBytes);
+				m_p = Marshal::AllocHGlobal(utf8Bytes->Length + 1);
+				Byte __pin * p = &utf8Bytes[0];
+				char * hBytes = static_cast<char*>(m_p.ToPointer());
+				memcpy(hBytes, p, utf8Bytes->Length);
+				hBytes[utf8Bytes->Length] = '\0';
+			}
+			else
+			{
+				m_p = NULL;
+			}
+		}
+
+		~PString()
+		{
+			Marshal::FreeHGlobal(m_p);
+		}
+
+		const char*
+		c_str()
+		{
+			if (m_p != NULL)
+			{
+				return static_cast<const char*>(m_p.ToPointer());
+			}
+			else
+			{
+				return NULL;
+			}
+		}
+		
+	protected:
+
+		IntPtr m_p;
+	};
+}
diff --git a/mDNSWindows/Applications/SystemService/Resource.h b/mDNSWindows/DLL.NET/Stdafx.cpp
old mode 100644
new mode 100755
similarity index 76%
rename from mDNSWindows/Applications/SystemService/Resource.h
rename to mDNSWindows/DLL.NET/Stdafx.cpp
index 50064bd..7014ab0
--- a/mDNSWindows/Applications/SystemService/Resource.h
+++ b/mDNSWindows/DLL.NET/Stdafx.cpp
@@ -1,33 +1,36 @@
-/*
- * 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
+/*
+ * 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: Stdafx.cpp,v $
+Revision 1.1  2004/06/26 04:01:22  shersche
+Initial revision
+
+
+ */
+    
+// stdafx.cpp : source file that includes just the standard includes
+// dotNET.pch will be the pre-compiled header
+// stdafx.obj will contain the pre-compiled type information
+
+#include "stdafx.h"
diff --git a/mDNSWindows/DLL.NET/Stdafx.h b/mDNSWindows/DLL.NET/Stdafx.h
new file mode 100755
index 0000000..397a0d1
--- /dev/null
+++ b/mDNSWindows/DLL.NET/Stdafx.h
@@ -0,0 +1,40 @@
+/*
+ * 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: Stdafx.h,v $
+Revision 1.1  2004/06/26 04:01:22  shersche
+Initial revision
+
+
+ */
+    
+// stdafx.h : include file for standard system include files,
+// or project specific include files that are used frequently,
+// but are changed infrequently
+
+#pragma once
+
+#using <mscorlib.dll>
+#using <System.dll>
+
diff --git a/mDNSWindows/DLL.NET/dnssd_NET.cpp b/mDNSWindows/DLL.NET/dnssd_NET.cpp
new file mode 100755
index 0000000..3aee79c
--- /dev/null
+++ b/mDNSWindows/DLL.NET/dnssd_NET.cpp
@@ -0,0 +1,1276 @@
+/*
+ * 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_NET.cpp,v $
+Revision 1.9  2004/09/16 18:17:13  shersche
+Use background threads, cleanup to parameter names.
+Submitted by: prepin@gmail.com
+
+Revision 1.8  2004/09/13 19:35:58  shersche
+<rdar://problem/3798941> Add Apple.DNSSD namespace to MC++ wrapper class
+<rdar://problem/3798950> Change all instances of unsigned short to int
+Bug #: 3798941, 3798950
+
+Revision 1.7  2004/09/11 00:36:40  shersche
+<rdar://problem/3786226> Modified .NET shim code to use host byte order for ports in APIs and callbacks
+Bug #: 3786226
+
+Revision 1.6  2004/09/02 21:20:56  cheshire
+<rdar://problem/3774871> Rendezvous DLL.NET crashes on null record
+
+Revision 1.5  2004/07/27 07:12:56  shersche
+make TextRecord an instantiable class object
+
+Revision 1.4  2004/07/26 06:19:05  shersche
+Treat byte arrays of zero-length as null arrays
+
+Revision 1.3  2004/07/19 16:08:56  shersche
+fix problems in UTF8/Unicode string translations
+
+Revision 1.2  2004/07/19 07:48:34  shersche
+fix bug in DNSService.Register when passing in NULL text record, add TextRecord APIs
+
+Revision 1.1  2004/06/26 04:01:22  shersche
+Initial revision
+
+
+ */
+    
+// This is the main DLL file.
+
+#include "stdafx.h"
+
+#include "dnssd_NET.h"
+#include "DebugServices.h"
+#include "PString.h"
+
+
+using namespace System::Net::Sockets;
+using namespace System::Diagnostics;
+using namespace Apple;
+using namespace Apple::DNSSD;
+
+
+//===========================================================================================================================
+//	Constants
+//===========================================================================================================================
+
+#define	DEBUG_NAME	"[dnssd.NET] "
+
+//
+// ConvertToString
+//
+static String*
+ConvertToString(const char * utf8String)
+{
+	return __gc new String(utf8String, 0, strlen(utf8String), __gc new UTF8Encoding(true, true));
+}
+
+
+//
+// class ServiceRef
+//
+// ServiceRef serves as the base class for all DNSService operations.
+//
+// It manages the DNSServiceRef, and implements processing the
+// result
+//
+ServiceRef::ServiceRef(Object * callback)
+:
+	m_bDisposed(false),
+	m_callback(callback),
+	m_thread(NULL)
+{
+	m_impl = new ServiceRefImpl(this);
+}
+
+
+ServiceRef::~ServiceRef()
+{
+}
+
+
+//
+// StartThread
+//
+// Starts the main processing thread
+//
+void
+ServiceRef::StartThread()
+{
+	check( m_impl != NULL );
+
+	m_impl->SetupEvents();
+
+	m_thread		=	new Thread(new ThreadStart(this, ProcessingThread));
+	m_thread->Name	=	S"DNSService Thread";
+	m_thread->IsBackground = true;
+	
+	m_thread->Start();
+}
+
+
+//
+// ProcessingThread
+//
+// The Thread class can only invoke methods in MC++ types.  So we
+// make a ProcessingThread method that forwards to the impl
+//
+void
+ServiceRef::ProcessingThread()
+{
+	m_impl->ProcessingThread();
+}
+
+
+//
+// Dispose
+//
+// Calls impl-Dispose().  This ultimately will call DNSServiceRefDeallocate()
+//
+void
+ServiceRef::Dispose()
+{
+	check(m_impl != NULL);
+	check(m_bDisposed == false);
+
+	if (!m_bDisposed)
+	{
+		m_bDisposed = true;
+
+		//
+		// Call Dispose.  This won't call DNSServiceRefDeallocate()
+		// necessarily. It depends on what thread this is being
+		// called in.
+		//
+		m_impl->Dispose();
+		m_impl = NULL;
+
+		m_thread = NULL;
+
+		GC::SuppressFinalize(this);  
+	}
+}
+
+
+//
+// EnumerateDomainsDispatch
+//
+// Dispatch a reply to the delegate.
+//
+void
+ServiceRef::EnumerateDomainsDispatch
+						(
+						ServiceFlags	flags,
+						int				interfaceIndex,
+						ErrorCode		errorCode,
+						String		*	replyDomain
+						)
+{
+	if ((m_callback != NULL) && (m_impl != NULL))
+	{
+		DNSService::EnumerateDomainsReply * OnEnumerateDomainsReply = static_cast<DNSService::EnumerateDomainsReply*>(m_callback);
+		OnEnumerateDomainsReply(this, flags, interfaceIndex, errorCode, replyDomain);
+	}
+}
+
+
+//
+// RegisterDispatch
+//
+// Dispatch a reply to the delegate.
+//
+void
+ServiceRef::RegisterDispatch
+				(
+				ServiceFlags	flags,
+				ErrorCode		errorCode,
+ 				String		*	name,
+				String		*	regtype,
+				String		*	domain
+				)
+{
+	if ((m_callback != NULL) && (m_impl != NULL))
+	{
+		DNSService::RegisterReply * OnRegisterReply = static_cast<DNSService::RegisterReply*>(m_callback);
+		OnRegisterReply(this, flags, errorCode, name, regtype, domain);
+	}
+}
+
+
+//
+// BrowseDispatch
+//
+// Dispatch a reply to the delegate.
+//
+void
+ServiceRef::BrowseDispatch
+			(
+			ServiceFlags	flags,
+			int				interfaceIndex,
+			ErrorCode		errorCode,
+			String		*	serviceName,
+			String		*	regtype,
+			String		*	replyDomain
+			)
+{
+	if ((m_callback != NULL) && (m_impl != NULL))
+	{
+		DNSService::BrowseReply * OnBrowseReply = static_cast<DNSService::BrowseReply*>(m_callback);
+		OnBrowseReply(this, flags, interfaceIndex, errorCode, serviceName, regtype, replyDomain);
+	}
+}
+
+
+//
+// ResolveDispatch
+//
+// Dispatch a reply to the delegate.
+//
+void
+ServiceRef::ResolveDispatch
+			(
+			ServiceFlags	flags,
+			int				interfaceIndex,
+			ErrorCode		errorCode,
+			String		*	fullname,
+			String		*	hosttarget,
+			int				port,
+			Byte			txtRecord[]
+			)
+{
+	if ((m_callback != NULL) && (m_impl != NULL))
+	{
+		DNSService::ResolveReply * OnResolveReply = static_cast<DNSService::ResolveReply*>(m_callback);
+		OnResolveReply(this, flags, interfaceIndex, errorCode, fullname, hosttarget, port, txtRecord);
+	}
+}
+
+
+//
+// RegisterRecordDispatch
+//
+// Dispatch a reply to the delegate.
+//
+void
+ServiceRef::RegisterRecordDispatch
+				(
+				ServiceFlags	flags,
+				ErrorCode		errorCode,
+				RecordRef	*	record
+				)
+{
+	if ((m_callback != NULL) && (m_impl != NULL))
+	{
+		DNSService::RegisterRecordReply * OnRegisterRecordReply = static_cast<DNSService::RegisterRecordReply*>(m_callback);
+		OnRegisterRecordReply(this, flags, errorCode, record);
+	}
+}
+
+
+//
+// QueryRecordDispatch
+//
+// Dispatch a reply to the delegate.
+//
+void
+ServiceRef::QueryRecordDispatch
+					(
+					ServiceFlags	flags,
+					int				interfaceIndex,
+					ErrorCode		errorCode,
+					String		*	fullname,
+					int				rrtype,
+					int				rrclass,
+					Byte			rdata[],
+					int				ttl
+					)
+{
+	if ((m_callback != NULL) && (m_impl != NULL))
+	{
+		DNSService::QueryRecordReply * OnQueryRecordReply = static_cast<DNSService::QueryRecordReply*>(m_callback);
+		OnQueryRecordReply(this, flags, interfaceIndex, errorCode, fullname, rrtype, rrclass, rdata, ttl);
+	}
+}
+
+
+//
+// ServiceRefImpl::ServiceRefImpl()
+//
+// Constructs a new ServiceRefImpl.  We save the pointer to our enclosing
+// class in a gcroot handle.  This satisfies the garbage collector as
+// the outer class is a managed type
+//
+ServiceRef::ServiceRefImpl::ServiceRefImpl(ServiceRef * outer)
+:
+	m_socketEvent(NULL),
+	m_stopEvent(NULL),
+	m_disposed(false),
+	m_outer(outer),
+	m_ref(NULL)
+{
+	m_threadId = GetCurrentThreadId();
+}
+
+
+//
+// ServiceRefImpl::~ServiceRefImpl()
+//
+// Deallocate all resources associated with the ServiceRefImpl
+//
+ServiceRef::ServiceRefImpl::~ServiceRefImpl()
+{
+	if (m_socketEvent != NULL)
+	{
+		CloseHandle(m_socketEvent);
+		m_socketEvent = NULL;
+	}
+
+	if (m_stopEvent != NULL)
+	{
+		CloseHandle(m_stopEvent);
+		m_stopEvent = NULL;
+	}
+
+	if (m_ref != NULL)
+	{
+		DNSServiceRefDeallocate(m_ref);
+		m_ref = NULL;
+	}
+}
+
+
+//
+// ServiceRefImpl::SetupEvents()
+//
+// Setup the events necessary to manage multi-threaded dispatch
+// of DNSService Events
+//
+void
+ServiceRef::ServiceRefImpl::SetupEvents()
+{
+	check(m_ref != NULL);
+
+	m_socket		=	(SOCKET) DNSServiceRefSockFD(m_ref);
+	check(m_socket != INVALID_SOCKET);
+
+	m_socketEvent	=	CreateEvent(NULL, 0, 0, NULL);
+
+	if (m_socketEvent == NULL)
+	{
+		throw new DNSServiceException(Unknown);
+	}
+
+	int err = WSAEventSelect(m_socket, m_socketEvent, FD_READ|FD_CLOSE);
+
+	if (err != 0)
+	{
+		throw new DNSServiceException(Unknown);
+	}
+
+	m_stopEvent = CreateEvent(NULL, 0, 0, NULL);
+
+	if (m_stopEvent == NULL)
+	{
+		throw new DNSServiceException(Unknown);
+	}
+}
+
+
+//
+// ServiceRefImpl::ProcessingThread()
+//
+// Wait for socket events on the DNSServiceRefSockFD().  Also wait
+// for stop events
+//
+void
+ServiceRef::ServiceRefImpl::ProcessingThread()
+{
+	check( m_socketEvent != NULL );
+	check( m_stopEvent != NULL );
+	check( m_ref != NULL );
+	
+	HANDLE handles[2];
+
+	handles[0] = m_socketEvent;
+	handles[1] = m_stopEvent;
+
+	while (m_disposed == false)
+	{
+		int ret = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
+
+		//
+		// it's a socket event
+		//
+		if (ret == WAIT_OBJECT_0)
+		{
+			DNSServiceProcessResult(m_ref);
+		}
+		//
+		// else it's a stop event
+		//
+		else if (ret == WAIT_OBJECT_0 + 1)
+		{
+			break;
+		}
+		else
+		{
+			//
+			// unexpected wait result
+			//
+			dlog( kDebugLevelWarning, DEBUG_NAME "%s: unexpected wait result (result=0x%08X)\n", __ROUTINE__, ret );
+		}
+	}
+
+	delete this;
+}
+
+
+//
+// ServiceRefImpl::Dispose()
+//
+// Calls DNSServiceRefDeallocate()
+//
+void
+ServiceRef::ServiceRefImpl::Dispose()
+{
+	OSStatus	err;
+	BOOL		ok;
+
+	check(m_disposed == false);
+
+	m_disposed = true;
+
+	ok = SetEvent(m_stopEvent);
+	err = translate_errno( ok, (OSStatus) GetLastError(), kUnknownErr );
+	require_noerr( err, exit );
+
+exit:
+
+	return;
+}
+
+
+//
+// ServiceRefImpl::EnumerateDomainsCallback()
+//
+// This is the callback from dnssd.dll.  We pass this up to our outer, managed type
+//
+void DNSSD_API
+ServiceRef::ServiceRefImpl::EnumerateDomainsCallback
+											(
+											DNSServiceRef			sdRef,
+											DNSServiceFlags			flags,
+											uint32_t				interfaceIndex,
+											DNSServiceErrorType		errorCode,
+											const char			*	replyDomain,
+											void				*	context
+											)
+{
+	ServiceRef::ServiceRefImpl * self = static_cast<ServiceRef::ServiceRefImpl*>(context);
+
+	check( self != NULL );
+	check( self->m_outer != NULL );
+
+	if (self->m_disposed == false)
+	{
+		self->m_outer->EnumerateDomainsDispatch((ServiceFlags) flags, interfaceIndex, (ErrorCode) errorCode, ConvertToString(replyDomain));
+	}
+}
+
+
+//
+// ServiceRefImpl::RegisterCallback()
+//
+// This is the callback from dnssd.dll.  We pass this up to our outer, managed type
+//
+void DNSSD_API
+ServiceRef::ServiceRefImpl::RegisterCallback
+							(
+							DNSServiceRef			sdRef,
+							DNSServiceFlags			flags,
+							DNSServiceErrorType		errorCode,
+							const char			*	name,
+							const char			*	regtype,
+							const char			*	domain,
+							void				*	context
+							)
+{
+	ServiceRef::ServiceRefImpl * self = static_cast<ServiceRef::ServiceRefImpl*>(context);
+
+	check( self != NULL );
+	check( self->m_outer != NULL );
+	
+	if (self->m_disposed == false)
+	{
+		self->m_outer->RegisterDispatch((ServiceFlags) flags, (ErrorCode) errorCode, ConvertToString(name), ConvertToString(regtype), ConvertToString(domain));
+	}
+}
+
+
+//
+// ServiceRefImpl::BrowseCallback()
+//
+// This is the callback from dnssd.dll.  We pass this up to our outer, managed type
+//
+void DNSSD_API
+ServiceRef::ServiceRefImpl::BrowseCallback
+							(
+							DNSServiceRef			sdRef,
+   							DNSServiceFlags			flags,
+							uint32_t				interfaceIndex,
+							DNSServiceErrorType		errorCode,
+							const char			*	serviceName,
+							const char			*	regtype,
+							const char			*	replyDomain,
+							void				*	context
+							)
+{
+	ServiceRef::ServiceRefImpl * self = static_cast<ServiceRef::ServiceRefImpl*>(context);
+
+	check( self != NULL );
+	check( self->m_outer != NULL );
+	
+	if (self->m_disposed == false)
+	{
+		self->m_outer->BrowseDispatch((ServiceFlags) flags, interfaceIndex, (ErrorCode) errorCode, ConvertToString(serviceName), ConvertToString(regtype), ConvertToString(replyDomain));
+	}
+}
+
+
+//
+// ServiceRefImpl::ResolveCallback()
+//
+// This is the callback from dnssd.dll.  We pass this up to our outer, managed type
+//
+void DNSSD_API
+ServiceRef::ServiceRefImpl::ResolveCallback
+							(
+							DNSServiceRef			sdRef,
+							DNSServiceFlags			flags,
+							uint32_t				interfaceIndex,
+							DNSServiceErrorType		errorCode,
+							const char			*	fullname,
+							const char			*	hosttarget,
+							uint16_t				notAnIntPort,
+							uint16_t				txtLen,
+							const char			*	txtRecord,
+							void				*	context
+							)
+{
+	ServiceRef::ServiceRefImpl * self = static_cast<ServiceRef::ServiceRefImpl*>(context);
+
+	check( self != NULL );
+	check( self->m_outer != NULL );
+	
+	if (self->m_disposed == false)
+	{
+		Byte txtRecordBytes[];
+
+		txtRecordBytes = NULL;
+
+		if (txtLen > 0)
+		{
+			//
+			// copy raw memory into managed byte array
+			//
+			txtRecordBytes		=	new Byte[txtLen];
+			Byte __pin	*	p	=	&txtRecordBytes[0];
+			memcpy(p, txtRecord, txtLen);
+		}
+
+		self->m_outer->ResolveDispatch((ServiceFlags) flags, interfaceIndex, (ErrorCode) errorCode, ConvertToString(fullname), ConvertToString(hosttarget), ntohs(notAnIntPort), txtRecordBytes);
+	}	
+}
+
+
+//
+// ServiceRefImpl::RegisterRecordCallback()
+//
+// This is the callback from dnssd.dll.  We pass this up to our outer, managed type
+//
+void DNSSD_API
+ServiceRef::ServiceRefImpl::RegisterRecordCallback
+								(
+								DNSServiceRef		sdRef,
+								DNSRecordRef		rrRef,
+								DNSServiceFlags		flags,
+								DNSServiceErrorType	errorCode,
+								void			*	context
+								)
+{
+	ServiceRef::ServiceRefImpl * self = static_cast<ServiceRef::ServiceRefImpl*>(context);
+
+	check( self != NULL );
+	check( self->m_outer != NULL );
+	
+	if (self->m_disposed == false)
+	{
+		RecordRef * record = NULL;
+
+		if (errorCode == 0)
+		{
+			record = new RecordRef;
+
+			record->m_impl->m_ref = rrRef;
+		}
+
+		self->m_outer->RegisterRecordDispatch((ServiceFlags) flags, (ErrorCode) errorCode, record);
+	}
+}
+
+
+//
+// ServiceRefImpl::QueryRecordCallback()
+//
+// This is the callback from dnssd.dll.  We pass this up to our outer, managed type
+//
+void DNSSD_API
+ServiceRef::ServiceRefImpl::QueryRecordCallback
+								(
+								DNSServiceRef			DNSServiceRef,
+								DNSServiceFlags			flags,
+								uint32_t				interfaceIndex,
+								DNSServiceErrorType		errorCode,
+								const char			*	fullname,
+								uint16_t				rrtype,
+								uint16_t				rrclass,
+								uint16_t				rdlen,
+								const void			*	rdata,
+								uint32_t				ttl,
+								void				*	context
+								)
+{
+	ServiceRef::ServiceRefImpl * self = static_cast<ServiceRef::ServiceRefImpl*>(context);
+
+	check( self != NULL );
+	check( self->m_outer != NULL );
+	
+	if (self->m_disposed == false)
+	{
+		Byte rdataBytes[];
+
+		if (rdlen)
+		{
+			rdataBytes			=	new Byte[rdlen];
+			Byte __pin * p		=	&rdataBytes[0];
+			memcpy(p, rdata, rdlen);
+		}
+
+		self->m_outer->QueryRecordDispatch((ServiceFlags) flags, (int) interfaceIndex, (ErrorCode) errorCode, ConvertToString(fullname), rrtype, rrclass, rdataBytes, ttl);
+	}
+}
+
+
+/*
+ * EnumerateDomains()
+ *
+ * This maps to DNSServiceEnumerateDomains().  Returns an
+ * initialized ServiceRef on success, throws an exception
+ * on failure.
+ */
+ServiceRef*
+DNSService::EnumerateDomains
+		(
+		int							flags,
+		int							interfaceIndex,
+		EnumerateDomainsReply	*	callback
+		)
+{
+	ServiceRef * sdRef = new ServiceRef(callback);
+	int			 err;
+
+	err = DNSServiceEnumerateDomains(&sdRef->m_impl->m_ref, flags, interfaceIndex, ServiceRef::ServiceRefImpl::EnumerateDomainsCallback, sdRef->m_impl);
+
+	if (err != 0)
+	{
+		throw new DNSServiceException(err);
+	}
+
+	sdRef->StartThread();
+
+	return sdRef;
+}
+
+
+/*
+ * Register()
+ *
+ * This maps to DNSServiceRegister().  Returns an
+ * initialized ServiceRef on success, throws an exception
+ * on failure.
+ */
+ServiceRef*
+DNSService::Register
+				(
+				int					flags,
+				int					interfaceIndex,
+				String			*	name,
+				String			*	regtype,
+				String			*	domain,
+				String			*	host,
+				int					port,
+				Byte				txtRecord[],
+				RegisterReply	*	callback
+				)
+{
+	ServiceRef	*	sdRef	=	new ServiceRef(callback);
+	PString		*	pName	=	new PString(name);
+	PString		*	pType	=	new PString(regtype);
+	PString		*	pDomain =	new PString(domain);
+	PString		*	pHost	=	new PString(host);
+	int				len		=	0;
+	Byte __pin	*	p		=	NULL;
+	void		*	v		=	NULL;
+
+	if ((txtRecord != NULL) && (txtRecord->Length > 0))
+	{
+		len		= txtRecord->Length;
+		p		= &txtRecord[0];
+		v		= (void*) p;
+	}
+
+	int err = DNSServiceRegister(&sdRef->m_impl->m_ref, flags, interfaceIndex, pName->c_str(), pType->c_str(), pDomain->c_str(), pHost->c_str(), htons(port), len, v, ServiceRef::ServiceRefImpl::RegisterCallback, sdRef->m_impl );
+
+	if (err != 0)
+	{
+		throw new DNSServiceException(err);
+	}
+
+	sdRef->StartThread();
+
+	return sdRef;
+}
+
+
+/*
+ * AddRecord()
+ *
+ * This maps to DNSServiceAddRecord().  Returns an
+ * initialized ServiceRef on success, throws an exception
+ * on failure.
+ */
+RecordRef*
+DNSService::AddRecord
+				(
+				ServiceRef	*	sdRef,
+				int				flags,
+				int				rrtype,
+				Byte			rdata[],
+				int				ttl
+				)
+{
+	int				len		=	0;
+	Byte __pin	*	p		=	NULL;
+	void		*	v		=	NULL;
+
+	if ((rdata != NULL) && (rdata->Length > 0))
+	{
+		len = rdata->Length;
+		p	= &rdata[0];
+		v	= (void*) p;
+	}
+
+	RecordRef * record = new RecordRef;
+
+	int err = DNSServiceAddRecord(sdRef->m_impl->m_ref, &record->m_impl->m_ref, flags, rrtype, len, v, ttl);
+
+	if (err != 0)
+	{
+		throw new DNSServiceException(err);
+	}
+
+	return record;
+}
+
+
+/*
+ * UpdateRecord()
+ *
+ * This maps to DNSServiceUpdateRecord().  Returns an
+ * initialized ServiceRef on success, throws an exception
+ * on failure.
+ */
+void
+DNSService::UpdateRecord
+				(
+				ServiceRef	*	sdRef,
+				RecordRef	*	record,
+				int				flags,
+				Byte			rdata[],
+				int				ttl
+				)
+{
+	int				len		=	0;
+	Byte __pin	*	p		=	NULL;
+	void		*	v		=	NULL;
+
+	if ((rdata != NULL) && (rdata->Length > 0))
+	{
+		len	= rdata->Length;
+		p	= &rdata[0];
+		v	= (void*) p;
+	}
+
+	int err = DNSServiceUpdateRecord(sdRef->m_impl->m_ref, record ? record->m_impl->m_ref : NULL, flags, len, v, ttl);
+
+	if (err != 0)
+	{
+		throw new DNSServiceException(err);
+	}
+}
+
+
+/*
+ * RemoveRecord()
+ *
+ * This maps to DNSServiceRemoveRecord().  Returns an
+ * initialized ServiceRef on success, throws an exception
+ * on failure.
+ */
+void
+DNSService::RemoveRecord
+		(
+		ServiceRef	*	sdRef,
+		RecordRef	*	record,
+		int				flags
+		)
+{
+	int err = DNSServiceRemoveRecord(sdRef->m_impl->m_ref, record->m_impl->m_ref, flags);
+
+	if (err != 0)
+	{
+		throw new DNSServiceException(err);
+	}
+}	
+
+
+/*
+ * Browse()
+ *
+ * This maps to DNSServiceBrowse().  Returns an
+ * initialized ServiceRef on success, throws an exception
+ * on failure.
+ */
+ServiceRef*
+DNSService::Browse
+	(
+	int				flags,
+	int				interfaceIndex,
+	String		*	regtype,
+	String		*	domain,
+	BrowseReply	*	callback
+	)
+{
+	ServiceRef	*	sdRef	= new ServiceRef(callback);
+	PString		*	pType	= new PString(regtype);
+	PString		*	pDomain	= new PString(domain);
+
+	int err = DNSServiceBrowse(&sdRef->m_impl->m_ref, flags, interfaceIndex, pType->c_str(), pDomain->c_str(),(DNSServiceBrowseReply) ServiceRef::ServiceRefImpl::BrowseCallback, sdRef->m_impl);
+
+	if (err != 0)
+	{
+		throw new DNSServiceException(err);
+	}
+
+	sdRef->StartThread();
+
+	return sdRef;
+}
+
+
+/*
+ * Resolve()
+ *
+ * This maps to DNSServiceResolve().  Returns an
+ * initialized ServiceRef on success, throws an exception
+ * on failure.
+ */
+ServiceRef*
+DNSService::Resolve
+	(
+	int					flags,
+	int					interfaceIndex,
+	String			*	name,
+	String			*	regtype,
+	String			*	domain,
+	ResolveReply	*	callback	
+	)
+{
+	ServiceRef	*	sdRef	= new ServiceRef(callback);
+	PString		*	pName	= new PString(name);
+	PString		*	pType	= new PString(regtype);
+	PString		*	pDomain	= new PString(domain);
+
+	int err = DNSServiceResolve(&sdRef->m_impl->m_ref, flags, interfaceIndex, pName->c_str(), pType->c_str(), pDomain->c_str(),(DNSServiceResolveReply) ServiceRef::ServiceRefImpl::ResolveCallback, sdRef->m_impl);
+
+	if (err != 0)
+	{
+		throw new DNSServiceException(err);
+	}
+
+	sdRef->StartThread();
+
+	return sdRef;
+}
+
+
+/*
+ * CreateConnection()
+ *
+ * This maps to DNSServiceCreateConnection().  Returns an
+ * initialized ServiceRef on success, throws an exception
+ * on failure.
+ */
+ServiceRef*
+DNSService::CreateConnection
+			(
+			RegisterRecordReply * callback
+			)
+{
+	ServiceRef * sdRef = new ServiceRef(callback);
+
+	int err = DNSServiceCreateConnection(&sdRef->m_impl->m_ref);
+
+	if (err != 0)
+	{
+		throw new DNSServiceException(err);
+	}
+
+	sdRef->StartThread();
+
+	return sdRef;
+}
+
+
+/*
+ * RegisterRecord()
+ *
+ * This maps to DNSServiceRegisterRecord().  Returns an
+ * initialized ServiceRef on success, throws an exception
+ * on failure.
+ */
+
+RecordRef*
+DNSService::RegisterRecord
+			(
+			ServiceRef			*	sdRef,
+			ServiceFlags			flags,
+			int						interfaceIndex,
+			String				*	fullname,
+			int						rrtype,
+			int						rrclass,
+			Byte					rdata[],
+			int						ttl
+			)
+{
+	RecordRef	*	record	= new RecordRef;
+	int				len		= 0;
+	Byte __pin	*	p		= NULL;
+	void		*	v		= NULL;
+
+	PString * pFullname = new PString(fullname);
+
+	if ((rdata != NULL) && (rdata->Length > 0))
+	{
+		len		= rdata->Length;
+		p		= &rdata[0];
+		v		= (void*) p;
+	}
+
+	int err = DNSServiceRegisterRecord(sdRef->m_impl->m_ref, &record->m_impl->m_ref, flags, interfaceIndex, pFullname->c_str(), rrtype, rrclass, len, v, ttl, (DNSServiceRegisterRecordReply) ServiceRef::ServiceRefImpl::RegisterRecordCallback, sdRef->m_impl);
+
+	if (err != 0)
+	{
+		throw new DNSServiceException(err);
+	}
+
+	return record;
+}
+
+/*
+ * QueryRecord()
+ *
+ * This maps to DNSServiceQueryRecord().  Returns an
+ * initialized ServiceRef on success, throws an exception
+ * on failure.
+ */
+ServiceRef*
+DNSService::QueryRecord
+		(
+		ServiceFlags			flags,
+		int						interfaceIndex,
+		String				*	fullname,
+		int						rrtype,
+		int						rrclass,
+		QueryRecordReply	*	callback
+		)
+{
+	ServiceRef	*	sdRef		= new ServiceRef(callback);
+	PString		*	pFullname	= new PString(fullname);
+
+	int err = DNSServiceQueryRecord(&sdRef->m_impl->m_ref, flags, interfaceIndex, pFullname->c_str(), rrtype, rrclass, (DNSServiceQueryRecordReply) ServiceRef::ServiceRefImpl::QueryRecordCallback, sdRef->m_impl);
+
+	if (err != 0)
+	{
+		throw new DNSServiceException(err);
+	}
+
+	sdRef->StartThread();
+
+	return sdRef;
+}
+
+
+/*
+ * ReconfirmRecord()
+ *
+ * This maps to DNSServiceReconfirmRecord().  Returns an
+ * initialized ServiceRef on success, throws an exception
+ * on failure.
+ */
+void
+DNSService::ReconfirmRecord
+		(
+		ServiceFlags	flags,
+		int				interfaceIndex,
+		String		*	fullname,
+		int				rrtype,
+		int				rrclass,
+		Byte			rdata[]
+		)
+{
+	int				len	= 0;
+	Byte __pin	*	p	= NULL;
+	void		*	v	= NULL;
+
+	PString * pFullname = new PString(fullname);
+
+	if ((rdata != NULL) && (rdata->Length > 0))
+	{
+		len	= rdata->Length;
+		p	= &rdata[0];
+		v	= (void*) p;
+	}
+
+	DNSServiceReconfirmRecord(flags, interfaceIndex, pFullname->c_str(), rrtype, rrclass, len, v);
+}
+
+
+void
+TextRecord::SetValue
+		(
+		String	*	key,
+		Byte		value[]            /* may be NULL */
+		)
+{
+	PString			*	pKey = new PString(key);
+	int					len		=	0;
+	Byte __pin		*	p		=	NULL;
+	void			*	v		=	NULL;
+	DNSServiceErrorType	err;
+
+	if (value && (value->Length > 0))
+	{
+		len	=	value->Length;
+		p	=	&value[0];
+		v	=	(void*) p;
+	}
+
+	err = TXTRecordSetValue(&m_impl->m_ref, pKey->c_str(), len, v);
+
+	if (err != 0)
+	{
+		throw new DNSServiceException(err);
+	}
+}
+
+
+void
+TextRecord::RemoveValue
+		(
+		String	*	key
+		)
+{
+	PString			*	pKey = new PString(key);
+	DNSServiceErrorType	err;
+
+	err = TXTRecordRemoveValue(&m_impl->m_ref, pKey->c_str());
+
+	if (err != 0)
+	{
+		throw new DNSServiceException(err);
+	}
+}
+
+
+int
+TextRecord::GetLength
+		(
+		)
+{
+	return TXTRecordGetLength(&m_impl->m_ref);
+}
+
+
+Byte
+TextRecord::GetBytes
+		(
+		) __gc[]
+{
+	const void	*	noGCBytes = NULL;
+	Byte			gcBytes[] = NULL;		
+
+	noGCBytes		=	TXTRecordGetBytesPtr(&m_impl->m_ref);
+	int			len	=	GetLength();
+
+	if (noGCBytes && len)
+	{
+		gcBytes				=	new Byte[len];
+		Byte __pin	*	p	=	&gcBytes[0];
+		memcpy(p, noGCBytes, len);
+	}
+
+	return gcBytes;
+}
+
+
+bool
+TextRecord::ContainsKey
+		(
+		Byte		txtRecord[],
+		String	*	key
+		)
+{
+	PString		*	pKey	= new PString(key);
+	Byte __pin	*	p		= &txtRecord[0];
+	
+	return (TXTRecordContainsKey(txtRecord->Length, p, pKey->c_str()) > 0) ? true : false;
+}
+
+
+Byte
+TextRecord::GetValueBytes
+		(
+		Byte		txtRecord[],
+		String	*	key
+		) __gc[]
+{
+	uint8_t			valueLen;
+	Byte			ret[]	= NULL;
+	PString		*	pKey	= new PString(key);
+	Byte __pin	*	p1		= &txtRecord[0];
+	const void	*	v;
+
+	v = TXTRecordGetValuePtr(txtRecord->Length, p1, pKey->c_str(), &valueLen);
+
+	if (v != NULL)
+	{
+		ret					= new Byte[valueLen];
+		Byte __pin	*	p2	= &ret[0];
+
+		memcpy(p2, v, valueLen);
+	}
+
+	return ret;
+}
+
+
+int
+TextRecord::GetCount
+		(
+		Byte txtRecord[]
+		)
+{
+	Byte __pin	*	p	= &txtRecord[0];
+
+	return TXTRecordGetCount(txtRecord->Length, p);
+}
+
+
+Byte
+TextRecord::GetItemAtIndex
+		(
+		Byte				txtRecord[],
+		int					index,
+		[Out] String	**	key
+		) __gc[]
+{
+	char				keyBuf[255];
+	uint8_t				keyBufLen = 255;
+	uint8_t				valueLen;
+	void			*	value;
+	Byte				ret[]	= NULL;
+	DNSServiceErrorType	err;
+	Byte __pin		*	p1		= &txtRecord[0];
+	
+
+	err = TXTRecordGetItemAtIndex(txtRecord->Length, p1, index, keyBufLen, keyBuf, &valueLen, (const void**) &value);
+
+	if (err != 0)
+	{
+		throw new DNSServiceException(err);
+	}
+
+	*key = ConvertToString(keyBuf);
+
+	if (valueLen)
+	{
+		ret					= new Byte[valueLen];
+		Byte __pin	*	p2	= &ret[0];
+
+		memcpy(p2, value, valueLen);
+	}
+
+	return ret;
+}
+
+
+//
+// DNSServiceException::DNSServiceException()
+//
+// Constructs an exception with an error code
+//
+DNSServiceException::DNSServiceException
+				(
+				int _err
+				)
+:
+	err(_err)
+{
+}
+
+
+//
+// This version of the constructor is useful for instances in which
+// an inner exception is thrown, caught, and then a new exception
+// is thrown in it's place
+//
+DNSServiceException::DNSServiceException
+				(	
+				String				*	message,
+				System::Exception	*	innerException
+				)
+{
+}
diff --git a/mDNSWindows/DLL.NET/dnssd_NET.h b/mDNSWindows/DLL.NET/dnssd_NET.h
new file mode 100755
index 0000000..565286f
--- /dev/null
+++ b/mDNSWindows/DLL.NET/dnssd_NET.h
@@ -0,0 +1,1424 @@
+/*
+ * 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@
+
+ * 
+ * NOTE:
+ * 
+ * These .Net APIs are a work in progress, currently being discussed and refined.
+ * If you plan to build an application based on these APIs, you may wish to
+ * statically link this code into your application, or otherwise distribute
+ * the DLL so that it installs into the same folder as your application
+ * (not into any common system area where it might interfere with other
+ * applications using a future completed version of these APIs).
+ * If you plan to do this, please be sure to inform us by sending email
+ * to rendezvous@apple.com to let us know.
+ * You may want to discuss what you're doing on the Rendezvous mailing
+ * list to see if others in similar positions have any suggestions for you:
+ * 
+ * <http://lists.apple.com/mailman/listinfo/rendezvous-dev/>
+ * 
+
+    Change History (most recent first):
+
+$Log: dnssd_NET.h,v $
+Revision 1.6  2004/09/20 22:47:06  cheshire
+Add cautionary comment
+
+Revision 1.5  2004/09/16 18:16:27  shersche
+Cleanup to parameter names
+Submitted by: prepin@gmail.com
+
+Revision 1.4  2004/09/13 19:35:57  shersche
+<rdar://problem/3798941> Add Apple.DNSSD namespace to MC++ wrapper class
+<rdar://problem/3798950> Change all instances of unsigned short to int
+Bug #: 3798941, 3798950
+
+Revision 1.3  2004/07/27 07:12:10  shersche
+make TextRecord an instantiable class object
+
+Revision 1.2  2004/07/19 07:48:34  shersche
+fix bug in DNSService.Register when passing in NULL text record, add TextRecord APIs
+
+Revision 1.1  2004/06/26 04:01:22  shersche
+Initial revision
+
+
+ */
+    
+#pragma once
+
+#include <dns_sd.h>
+#include <vcclr.h>
+#include <memory>
+#include <winsock2.h>
+
+using namespace System;
+using namespace System::Net;
+using namespace System::Runtime::InteropServices;
+using namespace System::Threading;
+using namespace System::Collections;
+
+
+namespace Apple
+{
+	namespace DNSSD
+	{
+		public __gc class ServiceRef;
+
+		public __value enum ServiceFlags : int
+		{
+			MoreComing			=	1,
+			/* MoreComing indicates to a callback that at least one more result is
+				* queued and will be delivered following immediately after this one.
+				* Applications should not update their UI to display browse
+				* results when the MoreComing flag is set, because this would
+				* result in a great deal of ugly flickering on the screen.
+				* Applications should instead wait until until MoreComing is not set,
+				* and then update their UI.
+				* When MoreComing is not set, that doesn't mean there will be no more
+				* answers EVER, just that there are no more answers immediately
+				* available right now at this instant. If more answers become available
+				* in the future they will be delivered as usual.
+				*/
+
+			Add					=	2,
+			Default				=	4,
+			/* Flags for domain enumeration and browse/query reply callbacks.
+				* "Default" applies only to enumeration and is only valid in
+				* conjuction with "Add".  An enumeration callback with the "Add"
+				* flag NOT set indicates a "Remove", i.e. the domain is no longer
+				* valid.
+				*/
+
+			NoAutoRename		=	8,
+			/* Flag for specifying renaming behavior on name conflict when registering
+				* non-shared records. By default, name conflicts are automatically handled
+				* by renaming the service.  NoAutoRename overrides this behavior - with this
+				* flag set, name conflicts will result in a callback.  The NoAutorename flag
+				* is only valid if a name is explicitly specified when registering a service
+				* (ie the default name is not used.)
+				*/
+
+			Shared				=	16,
+			Unique				=	32,
+			/* Flag for registering individual records on a connected
+				* DNSServiceRef.  Shared indicates that there may be multiple records
+				* with this name on the network (e.g. PTR records).  Unique indicates that
+	the
+				* record's name is to be unique on the network (e.g. SRV records).
+				*/
+
+			BrowseDomains		=	64,
+			RegistrationDomains	=	128,
+			/* Flags for specifying domain enumeration type in DNSServiceEnumerateDomain
+	s.
+				* BrowseDomains enumerates domains recommended for browsing, RegistrationDo
+	mains
+				* enumerates domains recommended for registration.
+				*/
+		};
+
+
+		public __value enum ErrorCode : int
+		{
+			NoError				=	0,
+			Unknown				=	-65537,
+			NoSuchName			=	-65538,
+			NoMemory			=	-65539,
+			BadParam			=	-65540,
+			BadReference		=	-65541,
+			BadState			=	-65542,
+			BadFlags			=	-65543,
+			Unsupported			=	-65544,
+			AlreadyRegistered	=	-65547,
+			NameConflict		=	-65548,
+			Invalid				=	-65549,
+			Incompatible		=	-65551,
+			BadinterfaceIndex	=	-65552
+
+			/*
+				* mDNS Error codes are in the range
+				* FFFE FF00 (-65792) to FFFE FFFF (-65537)
+				*/
+		};
+
+		public __gc class DNSServiceException
+		:
+			public Exception
+		{
+		public:
+
+			DNSServiceException
+				(
+				int err
+				);
+
+			DNSServiceException
+				(	
+				String				*	message,
+				System::Exception	*	innerException
+				);
+
+			int err;
+		};
+
+
+		/*
+		* class RecordRef
+		*
+		* This is a thin MC++ class facade on top of a DNSRecordRef
+		*/
+		public __gc class RecordRef
+		{
+		public:
+
+			RecordRef()
+			{
+				m_impl = new RecordRefImpl;
+				m_impl->m_ref = NULL;
+			}
+
+			~RecordRef()
+			{
+				delete m_impl;
+			}
+
+			__nogc class RecordRefImpl
+			{
+			public:
+
+				DNSRecordRef m_ref;
+			};
+
+			RecordRefImpl * m_impl;
+		};			
+
+
+		/*
+		* class ServiceRef
+		*
+		* This is a thin MC++ class facade on top of a DNSServiceRef
+		*/
+		public __gc class ServiceRef : public IDisposable
+		{
+		public:
+
+			ServiceRef(Object * callback);
+
+			~ServiceRef();
+
+			/*
+			* This does an underlying DNSServiceRefDeallocate().  After
+			* calling Dispose, the ServiceRef is no longer usable.
+			*/
+			void
+			Dispose();
+
+			/*
+			* Internal - Dispatch an EnumerateDomains callback
+			*/
+			void
+			EnumerateDomainsDispatch
+				(
+				ServiceFlags	flags,
+				int				interfaceIndex,
+				ErrorCode		errorCode,
+				String		*	replyDomain
+				);
+
+			/*
+			* Internal - Dispatch a Register callback
+			*/
+			void
+			RegisterDispatch
+				(
+				ServiceFlags	flags,
+				ErrorCode		errorCode,
+ 				String		*	name,
+				String		*	regtype,
+				String		*	domain
+				);
+
+			/*
+			* Internal - Dispatch a Browse callback
+			*/
+			void
+			BrowseDispatch
+				(
+				ServiceFlags	flags,
+				int				interfaceIndex,
+				ErrorCode		errorCode,
+				String		*	serviceName,
+				String		*	regtype,
+				String		*	replyDomain
+				);
+
+			/*
+			* Internal - Dispatch a Resolve callback
+			*/
+			void
+			ResolveDispatch
+				(
+				ServiceFlags	flags,
+				int				interfaceIndex,
+				ErrorCode		errorCode,
+				String		*	fullname,
+				String		*	hosttarget,
+				int				port,
+				Byte			txtRecord[]
+				);
+			
+			/*
+			* Internal - Dispatch a RegisterRecord callback
+			*/
+			void
+			RegisterRecordDispatch
+				(
+				ServiceFlags	flags,
+				ErrorCode		errorCode,
+				RecordRef	*	record
+				);
+
+			/*
+			* Internal - Dispatch a QueryRecord callback
+			*/
+			void
+			QueryRecordDispatch
+				(
+				ServiceFlags	flags,
+				int				interfaceIndex,
+				ErrorCode		errorCode,
+				String		*	fullname,
+				int				rrtype,
+				int				rrclass,
+				Byte			rdata[],
+				int				ttl
+				);
+
+			/*
+			* Internal - A non managed class to wrap a DNSServiceRef
+			*/
+			__nogc class ServiceRefImpl
+			{
+			public:
+
+				ServiceRefImpl
+					(
+					ServiceRef * outer
+					);
+
+				~ServiceRefImpl();
+
+				/*
+				* Sets up events for threaded operation
+				*/
+				void
+				SetupEvents();
+
+				/*
+				* Main processing thread
+				*/
+				void
+				ProcessingThread();
+
+				/*
+				* Calls DNSServiceRefDeallocate()
+				*/
+				void
+				Dispose();
+
+				/*
+				* Called from dnssd.dll
+				*/
+				static void DNSSD_API
+				EnumerateDomainsCallback
+					(
+					DNSServiceRef			sdRef,
+					DNSServiceFlags			flags,
+					uint32_t				interfaceIndex,
+					DNSServiceErrorType		errorCode,
+					const char			*	replyDomain,
+					void				*	context
+					);
+
+				static void DNSSD_API
+				RegisterCallback
+					(
+					DNSServiceRef			ref,
+					DNSServiceFlags			flags,
+					DNSServiceErrorType		errorCode,
+ 					const char			*	name,
+					const char			*	regtype,
+					const char			*	domain,
+					void				*	context
+					);
+
+				static void DNSSD_API
+				BrowseCallback
+					(
+					DNSServiceRef			sdRef,
+   					DNSServiceFlags			flags,
+					uint32_t				interfaceIndex,
+					DNSServiceErrorType		errorCode,
+					const char			*	serviceName,
+					const char			*	regtype,
+					const char			*	replyDomain,
+					void				*	context
+					);
+
+				static void DNSSD_API
+				ResolveCallback
+					(
+					DNSServiceRef			sdRef,
+					DNSServiceFlags			flags,
+					uint32_t				interfaceIndex,
+					DNSServiceErrorType		errorCode,
+					const char			*	fullname,
+					const char			*	hosttarget,
+					uint16_t				notAnIntPort,
+					uint16_t				txtLen,
+					const char			*	txtRecord,
+					void				*	context
+					);
+
+				static void DNSSD_API
+				RegisterRecordCallback
+					( 
+					DNSServiceRef		sdRef,
+					DNSRecordRef		RecordRef,
+					DNSServiceFlags		flags,
+					DNSServiceErrorType	errorCode,
+					void			*	context
+					);
+
+				static void DNSSD_API
+				QueryRecordCallback
+					(
+					DNSServiceRef			DNSServiceRef,
+					DNSServiceFlags			flags,
+					uint32_t				interfaceIndex,
+					DNSServiceErrorType		errorCode,
+					const char			*	fullname,
+					uint16_t				rrtype,
+					uint16_t				rrclass,
+					uint16_t				rdlen,
+					const void			*	rdata,
+					uint32_t				ttl,
+					void				*	context
+					);
+
+				SOCKET				m_socket;
+				HANDLE				m_socketEvent;
+				HANDLE				m_stopEvent;
+				DWORD				m_threadId;
+				bool				m_disposed;
+				DNSServiceRef		m_ref;
+				gcroot<ServiceRef*> m_outer;
+			};
+
+			void
+			StartThread();
+
+			void
+			ProcessingThread();
+
+			bool				m_bDisposed;
+			Object			*	m_callback;
+			Thread			*	m_thread;
+			ServiceRefImpl	*	m_impl;
+		};
+			
+		/*********************************************************************************************
+		*
+		*   TXT Record Construction Functions
+		*
+		*********************************************************************************************/
+
+		/*
+		* A typical calling sequence for TXT record construction is something like:
+		*
+		* DNSService.TextRecord tr = new DNSService.TextRecord(1024);
+		* tr.SetValue();
+		* tr.SetValue();
+		* tr.SetValue();
+		* ...
+		* DNSServiceRegister( ... tr.GetLength(), tr.GetBytes() ... );
+		*/
+
+
+		/* TextRecord
+		*
+		* Opaque internal data type.
+		* Note: Represents a DNS-SD TXT record.
+		*/
+
+
+		/* TextRecord::TextRecord()
+		*
+		* Creates a new empty TextRecord .
+		*
+		*/
+
+		public __gc class TextRecord
+		{
+		public:
+
+			TextRecord()
+			{
+				m_impl = new TextRecordImpl();
+				TXTRecordCreate(&m_impl->m_ref, 0, NULL);
+			}
+
+			~TextRecord()
+			{
+				TXTRecordDeallocate(&m_impl->m_ref);
+				delete m_impl;
+			}
+
+			__nogc class TextRecordImpl
+			{
+			public:
+
+				TXTRecordRef m_ref;
+			};
+
+			TextRecordImpl * m_impl;
+
+
+			/* SetValue()
+			*
+			* Adds a key (optionally with value) to a TextRecord. If the "key" already
+			* exists in the TextRecord, then the current value will be replaced with
+			* the new value.
+			* Keys may exist in four states with respect to a given TXT record:
+			*  - Absent (key does not appear at all)
+			*  - Present with no value ("key" appears alone)
+			*  - Present with empty value ("key=" appears in TXT record)
+			*  - Present with non-empty value ("key=value" appears in TXT record)
+			* For more details refer to "Data Syntax for DNS-SD TXT Records" in
+			* <http://files.dns-sd.org/draft-cheshire-dnsext-dns-sd.txt>
+			*
+			* key:             A null-terminated string which only contains printable ASCII
+			*                  values (0x20-0x7E), excluding '=' (0x3D). Keys should be
+			*                  14 characters or less (not counting the terminating null).
+			*
+			* value:           Any binary value. For values that represent
+			*                  textual data, UTF-8 is STRONGLY recommended.
+			*                  For values that represent textual data, valueSize
+			*                  should NOT include the terminating null (if any)
+			*                  at the end of the string.
+			*                  If NULL, then "key" will be added with no value.
+			*                  If non-NULL but valueSize is zero, then "key=" will be
+			*                  added with empty value.
+			*
+			* exceptions:      Throws kDNSServiceErr_Invalid if the "key" string contains
+			*                  illegal characters.
+			*                  Throws kDNSServiceErr_NoMemory if adding this key would
+			*                  exceed the available storage.
+			*/
+
+			void
+			SetValue
+				(
+				String	*	key,
+				Byte		value[]  /* may be NULL */
+				);
+
+
+			/* RemoveValue()
+			*
+			* Removes a key from a TextRecord.  The "key" must be an
+			* ASCII string which exists in the TextRecord.
+			*
+			* key:             A key name which exists in the TextRecord.
+			*
+			* exceptions:      Throws kDNSServiceErr_NoSuchKey if the "key" does not
+			*                  exist in the TextRecord.
+			*
+			*/
+
+			void
+			RemoveValue
+				(
+				String	*	key
+				);
+
+
+			/* GetLength()
+			*
+			* Allows you to determine the length of the raw bytes within a TextRecord.
+			*
+			* return value :     Returns the size of the raw bytes inside a TextRecord
+			*                  which you can pass directly to DNSServiceRegister() or
+			*                  to DNSServiceUpdateRecord().
+			*                  Returns 0 if the TextRecord is empty.
+			*
+			*/
+
+			int
+			GetLength
+				(
+				);
+
+
+			/* GetBytes()
+			*
+			* Allows you to retrieve a pointer to the raw bytes within a TextRecord.
+			*
+			* return value:    Returns a pointer to the bytes inside the TextRecord
+			*                  which you can pass directly to DNSServiceRegister() or
+			*                  to DNSServiceUpdateRecord().
+			*
+			*/
+
+			Byte
+			GetBytes
+				(
+				) __gc[];
+
+
+			/*********************************************************************************************
+			*
+			*   TXT Record Parsing Functions
+			*
+			*********************************************************************************************/
+
+			/*
+			* A typical calling sequence for TXT record parsing is something like:
+			*
+			* Receive TXT record data in DNSServiceResolve() callback
+			* if (TXTRecordContainsKey(txtLen, txtRecord, "key")) then do something
+			* val1ptr = DNSService.TextService.GetValue(txtRecord, "key1", &len1);
+			* val2ptr = DNSService.TextService.GetValue(txtRecord, "key2", &len2);
+			* ...
+			* return;
+			*
+			*/
+
+			/* ContainsKey()
+			*
+			* Allows you to determine if a given TXT Record contains a specified key.
+			*
+			* txtRecord:       Pointer to the received TXT Record bytes.
+			*
+			* key:             A null-terminated ASCII string containing the key name.
+			*
+			* return value:    Returns 1 if the TXT Record contains the specified key.
+			*                  Otherwise, it returns 0.
+			*
+			*/
+
+			static public bool
+			ContainsKey
+				(
+				Byte		txtRecord[],
+				String	*	key
+				);
+
+
+			/* GetValueBytes()
+			*
+			* Allows you to retrieve the value for a given key from a TXT Record.
+			*
+			* txtRecord:       Pointer to the received TXT Record bytes.
+			*
+			* key:             A null-terminated ASCII string containing the key name.
+			*
+			* return value:    Returns NULL if the key does not exist in this TXT record,
+			*                  or exists with no value (to differentiate between
+			*                  these two cases use ContainsKey()).
+			*                  Returns byte array 
+			*                  if the key exists with empty or non-empty value.
+			*                  For empty value, length of byte array will be zero.
+			*                  For non-empty value, it will be the length of value data.
+			*/
+
+			static public Byte
+			GetValueBytes
+				(
+				Byte		txtRecord[],
+				String	*	key
+				) __gc[];
+
+
+			/* GetCount()
+			*
+			* Returns the number of keys stored in the TXT Record.  The count
+			* can be used with TXTRecordGetItemAtIndex() to iterate through the keys.
+			*
+			* txtRecord:       Pointer to the received TXT Record bytes.
+			*
+			* return value:    Returns the total number of keys in the TXT Record.
+			*
+			*/
+
+			static public int
+			GetCount
+				(
+				Byte	txtRecord[]
+				);
+
+
+			/* GetItemAtIndex()
+			*
+			* Allows you to retrieve a key name and value pointer, given an index into
+			* a TXT Record.  Legal index values range from zero to TXTRecordGetCount()-1.
+			* It's also possible to iterate through keys in a TXT record by simply
+			* calling TXTRecordGetItemAtIndex() repeatedly, beginning with index zero
+			* and increasing until TXTRecordGetItemAtIndex() returns kDNSServiceErr_Invalid.
+			*
+			* On return:
+			* For keys with no value, *value is set to NULL and *valueLen is zero.
+			* For keys with empty value, *value is non-NULL and *valueLen is zero.
+			* For keys with non-empty value, *value is non-NULL and *valueLen is non-zero.
+			*
+			* txtRecord:       Pointer to the received TXT Record bytes.
+			*
+			* index:           An index into the TXT Record.
+			*
+			* key:             A string buffer used to store the key name.
+			*                  On return, the buffer contains a string
+			*                  giving the key name. DNS-SD TXT keys are usually
+			*                  14 characters or less. 
+			*
+			* return value:    Record bytes that holds the value data.
+			*
+			* exceptions:      Throws kDNSServiceErr_Invalid if index is greater than
+			*                  GetCount()-1.
+			*/
+
+			static public Byte
+			GetItemAtIndex
+				(
+				Byte				txtRecord[],
+				int					index,
+				[Out] String	**	key
+				) __gc[];
+		};
+
+
+		public __abstract __gc class DNSService
+		{
+		public:
+
+			/*********************************************************************************************
+			*
+			* Domain Enumeration
+			*
+			*********************************************************************************************/
+
+			/* DNSServiceEnumerateDomains()
+			*
+			* Asynchronously enumerate domains available for browsing and registration.
+			* Currently, the only domain returned is "local.", but other domains will be returned in future.
+			*
+			* The enumeration MUST be cancelled via DNSServiceRefDeallocate() when no more domains
+			* are to be found.
+			*
+			*
+			* EnumerateDomainsReply Delegate
+			*
+			* This Delegate is invoked upon a reply from an EnumerateDomains call.
+			*
+			* sdRef:           The DNSServiceRef initialized by DNSServiceEnumerateDomains().
+			*
+			* flags:           Possible values are:
+			*                  MoreComing
+			*                  Add
+			*                  Default
+			*
+			* interfaceIndex:  Specifies the interface on which the domain exists.  (The index for a given
+			*                  interface is determined via the if_nametoindex() family of calls.)
+			*
+			* errorCode:       Will be NoError (0) on success, otherwise indicates
+			*                  the failure that occurred (other parameters are undefined if errorCode is nonzero).
+			*
+			* replyDomain:     The name of the domain.
+			*
+			*/
+
+			__delegate void
+			EnumerateDomainsReply
+				(
+				ServiceRef	*	sdRef,
+				ServiceFlags	flags,
+				int				interfaceIndex,
+				ErrorCode		errorCode,
+				String		*	replyDomain
+				);
+
+			/* DNSServiceEnumerateDomains() Parameters:
+			*
+			*
+			* flags:           Possible values are:
+			*                  BrowseDomains to enumerate domains recommended for browsing.
+			*                  RegistrationDomains to enumerate domains recommended
+			*                  for registration.
+			*
+			* interfaceIndex:  If non-zero, specifies the interface on which to look for domains.
+			*                  (the index for a given interface is determined via the if_nametoindex()
+			*                  family of calls.)  Most applications will pass 0 to enumerate domains on
+			*                  all interfaces.
+			*
+			* callback:        The delegate to be called when a domain is found or the call asynchronously
+			*                  fails.
+			*
+			*
+			* return value:    Returns initialize ServiceRef on succeses (any subsequent, asynchronous
+			*                  errors are delivered to the delegate), otherwise throws an exception indicating
+			*                  the error that occurred (the callback is not invoked and the ServiceRef
+			*                  is not initialized.)
+			*/
+
+			static public ServiceRef*
+			EnumerateDomains
+				(
+				int							flags,
+				int							interfaceIndex,
+				EnumerateDomainsReply	*	callback
+				);
+
+			/*********************************************************************************************
+			*
+			*  Service Registration
+			*
+			*********************************************************************************************/
+
+			/* Register a service that is discovered via Browse() and Resolve() calls.
+			* 
+			* RegisterReply() Callback Parameters:
+			*
+			* sdRef:           The ServiceRef initialized by Register().
+			*
+			* flags:           Currently unused, reserved for future use.
+			*
+			* errorCode:       Will be NoError on success, otherwise will
+			*                  indicate the failure that occurred (including name conflicts, if the
+			*                  NoAutoRename flag was passed to the
+			*                  callout.)  Other parameters are undefined if errorCode is nonzero.
+			*
+			* name:            The service name registered (if the application did not specify a name in
+			*                  DNSServiceRegister(), this indicates what name was automatically chosen).
+			*
+			* regtype:         The type of service registered, as it was passed to the callout.
+			*
+			* domain:          The domain on which the service was registered (if the application did not
+			*                  specify a domain in Register(), this indicates the default domain
+			*                  on which the service was registered).
+			*
+			*/
+
+			__delegate void
+			RegisterReply
+				(
+				ServiceRef	*	sdRef,
+				ServiceFlags	flags,
+				ErrorCode		errorCode,
+				String		*	name,
+				String		*	regtype,
+				String		*	domain
+				);
+
+			/* Register()  Parameters:
+			*
+			* flags:           Indicates the renaming behavior on name conflict (most applications
+			*                  will pass 0).  See flag definitions above for details.
+			*
+			* interfaceIndex:  If non-zero, specifies the interface on which to register the service
+			*                  (the index for a given interface is determined via the if_nametoindex()
+			*                  family of calls.)  Most applications will pass 0 to register on all
+			*                  available interfaces.  Pass -1 to register a service only on the local
+			*                  machine (service will not be visible to remote hosts.)
+			*
+			* name:            If non-NULL, specifies the service name to be registered.
+			*                  Most applications will not specify a name, in which case the
+			*                  computer name is used (this name is communicated to the client via
+			*                  the callback).
+			*
+			* regtype:         The service type followed by the protocol, separated by a dot
+			*                  (e.g. "_ftp._tcp").  The transport protocol must be "_tcp" or "_udp".
+			*                  New service types should be registered at htp://www.dns-sd.org/ServiceTypes.html.
+			*
+			* domain:          If non-NULL, specifies the domain on which to advertise the service.
+			*                  Most applications will not specify a domain, instead automatically
+			*                  registering in the default domain(s).
+			*
+			* host:            If non-NULL, specifies the SRV target host name.  Most applications
+			*                  will not specify a host, instead automatically using the machine's
+			*                  default host name(s).  Note that specifying a non-NULL host does NOT
+			*                  create an address record for that host - the application is responsible
+			*                  for ensuring that the appropriate address record exists, or creating it
+			*                  via DNSServiceRegisterRecord().
+			*
+			* port:            The port, in host byte order, on which the service accepts connections.
+			*                  Pass 0 for a "placeholder" service (i.e. a service that will not be discovered
+			*                  by browsing, but will cause a name conflict if another client tries to
+			*                  register that same name).  Most clients will not use placeholder services.
+			*
+			* txtRecord:       The txt record rdata.  May be NULL.  Note that a non-NULL txtRecord
+			*                  MUST be a properly formatted DNS TXT record, i.e. <length byte> <data>
+			*                  <length byte> <data> ...
+			*
+			* callback:        The delegate to be called when the registration completes or asynchronously
+			*                  fails.  The client MAY pass NULL for the callback -  The client will NOT be notified
+			*                  of the default values picked on its behalf, and the client will NOT be notified of any
+			*                  asynchronous errors (e.g. out of memory errors, etc.) that may prevent the registration
+			*                  of the service.  The client may NOT pass the NoAutoRename flag if the callback is NULL.
+			*                  The client may still deregister the service at any time via DNSServiceRefDeallocate().
+			*
+			* return value:    Returns initialize ServiceRef (any subsequent, asynchronous
+			*                  errors are delivered to the callback), otherwise throws an exception indicating
+			*                  the error that occurred (the callback is never invoked and the DNSServiceRef
+			*                  is not initialized.)
+			*
+			*/
+			static public ServiceRef*
+			Register
+				(
+				int					flags,
+				int					interfaceIndex,
+				String			*	name,
+				String			*	regtype,
+				String			*	domain,
+				String			*	host,
+				int					port,
+				Byte				txtRecord[],
+				RegisterReply	*	callback
+				);
+
+			/* AddRecord()
+			*
+			* Add a record to a registered service.  The name of the record will be the same as the
+			* registered service's name.
+			* The record can later be updated or deregistered by passing the RecordRef initialized
+			* by this function to UpdateRecord() or RemoveRecord().
+			*
+			*
+			* Parameters;
+			*
+			* sdRef:           A ServiceRef initialized by Register().
+			*
+			* RecordRef:       A pointer to an uninitialized RecordRef.  Upon succesfull completion of this
+			*                  call, this ref may be passed to UpdateRecord() or RemoveRecord().
+			*                  If the above ServiceRef is disposed, RecordRef is also
+			*                  invalidated and may not be used further.
+			*
+			* flags:           Currently ignored, reserved for future use.
+			*
+			* rrtype:          The type of the record (e.g. TXT, SRV, etc), as defined in nameser.h.
+			*
+			* rdata:           The raw rdata to be contained in the added resource record.
+			*
+			* ttl:             The time to live of the resource record, in seconds.
+			*
+			* return value:    Returns initialized RecordRef, otherwise throws
+			*                  an exception indicating the error that occurred (the RecordRef is not initialized).
+			*/
+
+			static public RecordRef*
+			AddRecord
+				(
+				ServiceRef	*	sref,
+				int				flags,
+				int				rrtype,
+				Byte			rdata[],
+				int				ttl
+				);
+
+			/* UpdateRecord
+			*
+			* Update a registered resource record.  The record must either be:
+			*   - The primary txt record of a service registered via Register()
+			*   - A record added to a registered service via AddRecord()
+			*   - An individual record registered by RegisterRecord()
+			*
+			*
+			* Parameters:
+			*
+			* sdRef:           A ServiceRef that was initialized by Register()
+			*                  or CreateConnection().
+			*
+			* RecordRef:       A RecordRef initialized by AddRecord, or NULL to update the
+			*                  service's primary txt record.
+			*
+			* flags:           Currently ignored, reserved for future use.
+			*
+			* rdata:           The new rdata to be contained in the updated resource record.
+			*
+			* ttl:             The time to live of the updated resource record, in seconds.
+			*
+			* return value:    No return value on success, otherwise throws an exception
+			*                  indicating the error that occurred.
+			*/
+			static public void
+			UpdateRecord
+				(
+				ServiceRef	*	sref,
+				RecordRef	*	record,
+				int				flags,
+				Byte			rdata[],
+				int				ttl
+				);
+
+			/* RemoveRecord
+			*
+			* Remove a record previously added to a service record set via AddRecord(), or deregister
+			* an record registered individually via RegisterRecord().
+			*
+			* Parameters:
+			*
+			* sdRef:           A ServiceRef initialized by Register() (if the
+			*                  record being removed was registered via AddRecord()) or by
+			*                  CreateConnection() (if the record being removed was registered via
+			*                  RegisterRecord()).
+			*
+			* recordRef:       A RecordRef initialized by a successful call to AddRecord()
+			*                  or RegisterRecord().
+			*
+			* flags:           Currently ignored, reserved for future use.
+			*
+			* return value:    Nothing on success, otherwise throws an
+			*                  exception indicating the error that occurred.
+			*/
+
+			static public void
+			RemoveRecord
+							(
+							ServiceRef	*	sref,
+							RecordRef	*	record,	
+							int				flags
+							);
+
+			/*********************************************************************************************
+			*
+			*  Service Discovery
+			*
+			*********************************************************************************************/
+
+			/* Browse for instances of a service.
+			*
+			*
+			* BrowseReply() Parameters:
+			*
+			* sdRef:           The DNSServiceRef initialized by Browse().
+			*
+			* flags:           Possible values are MoreComing and Add.
+			*                  See flag definitions for details.
+			*
+			* interfaceIndex:  The interface on which the service is advertised.  This index should
+			*                  be passed to Resolve() when resolving the service.
+			*
+			* errorCode:       Will be NoError (0) on success, otherwise will
+			*                  indicate the failure that occurred.  Other parameters are undefined if
+			*                  the errorCode is nonzero.
+			*
+			* serviceName:     The service name discovered.
+			*
+			* regtype:         The service type, as passed in to Browse().
+			* 
+			* domain:          The domain on which the service was discovered (if the application did not
+			*                  specify a domain in Browse(), this indicates the domain on which the
+			*                  service was discovered.)
+			*
+			*/
+
+			__delegate void
+			BrowseReply
+				(
+				ServiceRef	*	sdRef,
+				ServiceFlags	flags,
+				int				interfaceIndex,
+				ErrorCode		errorCode,
+				String		*	name,
+				String		*	type,
+				String		*	domain
+				);
+
+			/* DNSServiceBrowse() Parameters:
+			*
+			* sdRef:           A pointer to an uninitialized ServiceRef.  Call ServiceRef.Dispose()
+			*                  to terminate the browse.
+			*
+			* flags:           Currently ignored, reserved for future use.
+			*
+			* interfaceIndex:  If non-zero, specifies the interface on which to browse for services
+			*                  (the index for a given interface is determined via the if_nametoindex()
+			*                  family of calls.)  Most applications will pass 0 to browse on all available
+			*                  interfaces.  Pass -1 to only browse for services provided on the local host.
+			*
+			* regtype:         The service type being browsed for followed by the protocol, separated by a
+			*                  dot (e.g. "_ftp._tcp").  The transport protocol must be "_tcp" or "_udp".
+			*
+			* domain:          If non-NULL, specifies the domain on which to browse for services.
+			*                  Most applications will not specify a domain, instead browsing on the
+			*                  default domain(s).
+			*
+			* callback:        The delegate to be called when an instance of the service being browsed for
+			*                  is found, or if the call asynchronously fails.
+			*
+			* return value:    Returns initialized ServiceRef on succeses (any subsequent, asynchronous
+			*                  errors are delivered to the callback), otherwise throws an exception indicating
+			*                  the error that occurred (the callback is not invoked and the ServiceRef
+			*                  is not initialized.)
+			*/
+
+			static public ServiceRef*
+			Browse
+				(
+				int				flags,
+				int				interfaceIndex,
+				String		*	regtype,
+				String		*	domain,
+				BrowseReply	*	callback
+				);
+
+			/* ResolveReply() Parameters:
+			*
+			* Resolve a service name discovered via Browse() to a target host name, port number, and
+			* txt record.
+			*
+			* Note: Applications should NOT use Resolve() solely for txt record monitoring - use
+			* QueryRecord() instead, as it is more efficient for this task.
+			*
+			* Note: When the desired results have been returned, the client MUST terminate the resolve by calling
+			* ServiceRef.Dispose().
+			*
+			* Note: Resolve() behaves correctly for typical services that have a single SRV record and
+			* a single TXT record (the TXT record may be empty.)  To resolve non-standard services with multiple
+			* SRV or TXT records, QueryRecord() should be used.
+			*
+			* ResolveReply Callback Parameters:
+			*
+			* sdRef:           The DNSServiceRef initialized by Resolve().
+			*
+			* flags:           Currently unused, reserved for future use.
+			*
+			* interfaceIndex:  The interface on which the service was resolved.
+			*
+			* errorCode:       Will be NoError (0) on success, otherwise will
+			*                  indicate the failure that occurred.  Other parameters are undefined if
+			*                  the errorCode is nonzero.
+			*
+			* fullname:        The full service domain name, in the form <servicename>.<protocol>.<domain>.
+			*                  (Any literal dots (".") are escaped with a backslash ("\."), and literal
+			*                  backslashes are escaped with a second backslash ("\\"), e.g. a web server
+			*                  named "Dr. Pepper" would have the fullname  "Dr\.\032Pepper._http._tcp.local.").
+			*                  This is the appropriate format to pass to standard system DNS APIs such as
+			*                  res_query(), or to the special-purpose functions included in this API that
+			*                  take fullname parameters.
+			*
+			* hosttarget:      The target hostname of the machine providing the service.  This name can
+			*                  be passed to functions like gethostbyname() to identify the host's IP address.
+			*
+			* port:            The port, in host byte order, on which connections are accepted for this service.
+			*
+			* txtRecord:       The service's primary txt record, in standard txt record format.
+			*
+			*/
+
+			__delegate void
+			ResolveReply
+				(	
+				ServiceRef	*	sdRef,  
+				ServiceFlags	flags,
+				int				interfaceIndex,
+				ErrorCode		errorCode,
+				String		*	fullName,
+				String		*	hostName,
+				int				port,
+				Byte			txtRecord[]
+				);
+
+			/* Resolve() Parameters
+			*
+			* flags:           Currently ignored, reserved for future use.
+			*
+			* interfaceIndex:  The interface on which to resolve the service.  The client should
+			*                  pass the interface on which the servicename was discovered, i.e.
+			*                  the interfaceIndex passed to the DNSServiceBrowseReply callback,
+			*                  or 0 to resolve the named service on all available interfaces.
+			*
+			* name:            The servicename to be resolved.
+			*
+			* regtype:         The service type being resolved followed by the protocol, separated by a
+			*                  dot (e.g. "_ftp._tcp").  The transport protocol must be "_tcp" or "_udp".
+			*
+			* domain:          The domain on which the service is registered, i.e. the domain passed
+			*                  to the DNSServiceBrowseReply callback.
+			*
+			* callback:        The delegate to be called when a result is found, or if the call
+			*                  asynchronously fails.
+			*
+			*
+			* return value:    Returns initialized ServiceRef on succeses (any subsequent, asynchronous
+			*                  errors are delivered to the callback), otherwise throws an exception indicating
+			*                  the error that occurred (the callback is never invoked and the DNSServiceRef
+			*                  is not initialized.)
+			*/
+
+			static public ServiceRef*
+			Resolve
+				(
+				int					flags,
+				int					interfaceIndex,
+				String			*	name,
+				String			*	regtype,
+				String			*	domain,
+				ResolveReply	*	callback
+				);
+
+			/*********************************************************************************************
+			*
+			*  Special Purpose Calls (most applications will not use these)
+			*
+			*********************************************************************************************/
+
+			/* CreateConnection/RegisterRecord
+			*
+			* Register an individual resource record on a connected ServiceRef.
+			*
+			* Note that name conflicts occurring for records registered via this call must be handled
+			* by the client in the callback.
+			*
+			*
+			* RecordReply() parameters:
+			*
+			* sdRef:           The connected ServiceRef initialized by
+			*                  CreateConnection().
+			*
+			* RecordRef:       The RecordRef initialized by RegisterRecord().  If the above
+			*                  ServiceRef.Dispose is called, this RecordRef is
+			*                  invalidated, and may not be used further.
+			*
+			* flags:           Currently unused, reserved for future use.
+			*
+			* errorCode:       Will be NoError on success, otherwise will
+			*                  indicate the failure that occurred (including name conflicts.)
+			*                  Other parameters are undefined if errorCode is nonzero.
+			*
+			*/
+
+			__delegate void
+			RegisterRecordReply
+				(
+				ServiceRef	*	sdRef,
+				ServiceFlags	flags,
+				ErrorCode		errorCode,
+				RecordRef	*	record
+				);
+
+			/* CreateConnection()
+			*
+			* Create a connection to the daemon allowing efficient registration of
+			* multiple individual records.
+			*
+			*
+			* Parameters:
+			*
+			* callback:        The delegate to be called when a result is found, or if the call
+			*                  asynchronously fails (e.g. because of a name conflict.)
+			*
+			* return value:    Returns initialize ServiceRef on success, otherwise throws
+			*                  an exception indicating the specific failure that occurred (in which
+			*                  case the ServiceRef is not initialized).
+			*/
+
+			static public ServiceRef*
+			CreateConnection
+				(
+				RegisterRecordReply * callback
+				);
+
+
+			/* RegisterRecord() Parameters:
+			*
+			* sdRef:           A ServiceRef initialized by CreateConnection().
+			*
+			* RecordRef:       A pointer to an uninitialized RecordRef.  Upon succesfull completion of this
+			*                  call, this ref may be passed to UpdateRecord() or RemoveRecord().
+			*                  (To deregister ALL records registered on a single connected ServiceRef
+			*                  and deallocate each of their corresponding RecordRefs, call
+			*                  ServiceRef.Dispose()).
+			*
+			* flags:           Possible values are Shared or Unique
+			*                  (see flag type definitions for details).
+			*
+			* interfaceIndex:  If non-zero, specifies the interface on which to register the record
+			*                  (the index for a given interface is determined via the if_nametoindex()
+			*                  family of calls.)  Passing 0 causes the record to be registered on all interfaces.
+			*                  Passing -1 causes the record to only be visible on the local host.
+			*
+			* fullname:        The full domain name of the resource record.
+			*
+			* rrtype:          The numerical type of the resource record (e.g. PTR, SRV, etc), as defined
+			*                  in nameser.h.
+			*
+			* rrclass:         The class of the resource record, as defined in nameser.h (usually 1 for the
+			*                  Internet class).
+			*
+			* rdata:           A pointer to the raw rdata, as it is to appear in the DNS record.
+			*
+			* ttl:             The time to live of the resource record, in seconds.
+			*
+			*
+			* return value:    Returns initialize RecordRef on succeses (any subsequent, asynchronous
+			*                  errors are delivered to the callback), otherwise throws an exception indicating
+			*                  the error that occurred (the callback is never invoked and the RecordRef is
+			*                  not initialized.)
+			*/
+			static public RecordRef*
+			RegisterRecord
+				(
+				ServiceRef			*	sdRef,
+				ServiceFlags			flags,
+				int						interfaceIndex,
+				String				*	fullname,
+				int						rrtype,
+				int						rrclass,
+				Byte					rdata[],
+				int						ttl
+				);
+
+
+			/* DNSServiceQueryRecord
+			*
+			* Query for an arbitrary DNS record.
+			*
+			*
+			* QueryRecordReply() Delegate Parameters:
+			*
+			* sdRef:           The ServiceRef initialized by QueryRecord().
+			*
+			* flags:           Possible values are MoreComing and
+			*                  Add.  The Add flag is NOT set for PTR records
+			*                  with a ttl of 0, i.e. "Remove" events.
+			*
+			* interfaceIndex:  The interface on which the query was resolved (the index for a given
+			*                  interface is determined via the if_nametoindex() family of calls).
+			*
+			* errorCode:       Will be kDNSServiceErr_NoError on success, otherwise will
+			*                  indicate the failure that occurred.  Other parameters are undefined if
+			*                  errorCode is nonzero.
+			*
+			* fullname:        The resource record's full domain name.
+			*
+			* rrtype:          The resource record's type (e.g. PTR, SRV, etc) as defined in nameser.h.
+			*
+			* rrclass:         The class of the resource record, as defined in nameser.h (usually 1).
+			*
+			* rdata:           The raw rdata of the resource record.
+			*
+			* ttl:             The resource record's time to live, in seconds.
+			*
+			*/
+
+			__delegate void
+			QueryRecordReply
+				(
+				ServiceRef	*	sdRef,
+				ServiceFlags	flags,
+				int				interfaceIndex,
+				ErrorCode		errorCode,	
+				String		*	fullName,
+				int				rrtype,
+				int				rrclass,
+				Byte			rdata[],
+				int				ttl
+				);
+
+			/* QueryRecord() Parameters:
+			*
+			* flags:           Pass LongLivedQuery to create a "long-lived" unicast
+			*                  query in a non-local domain.  Without setting this flag, unicast queries
+			*                  will be one-shot - that is, only answers available at the time of the call
+			*                  will be returned.  By setting this flag, answers (including Add and Remove
+			*                  events) that become available after the initial call is made will generate
+			*                  callbacks.  This flag has no effect on link-local multicast queries.
+			*
+			* interfaceIndex:  If non-zero, specifies the interface on which to issue the query
+			*                  (the index for a given interface is determined via the if_nametoindex()
+			*                  family of calls.)  Passing 0 causes the name to be queried for on all
+			*                  interfaces.  Passing -1 causes the name to be queried for only on the
+			*                  local host.
+			*
+			* fullname:        The full domain name of the resource record to be queried for.
+			*
+			* rrtype:          The numerical type of the resource record to be queried for (e.g. PTR, SRV, etc)
+			*                  as defined in nameser.h.
+			*
+			* rrclass:         The class of the resource record, as defined in nameser.h
+			*                  (usually 1 for the Internet class).
+			*
+			* callback:        The delegate to be called when a result is found, or if the call
+			*                  asynchronously fails.
+			*
+			*
+			* return value:    Returns initialized ServiceRef on succeses (any subsequent, asynchronous
+			*                  errors are delivered to the callback), otherwise throws an exception indicating
+			*                  the error that occurred (the callback is never invoked and the ServiceRef
+			*                  is not initialized.)
+			*/
+
+			static public ServiceRef*
+			QueryRecord
+				(
+				ServiceFlags			flags,
+				int						interfaceIndex,
+				String				*	fullname,
+				int						rrtype,
+				int						rrclass,
+				QueryRecordReply	*	callback
+				);
+
+			/* ReconfirmRecord
+			*
+			* Instruct the daemon to verify the validity of a resource record that appears to
+			* be out of date (e.g. because tcp connection to a service's target failed.)
+			* Causes the record to be flushed from the daemon's cache (as well as all other
+			* daemons' caches on the network) if the record is determined to be invalid.
+			*
+			* Parameters:
+			*
+			* flags:           Currently unused, reserved for future use.
+			*
+			* fullname:        The resource record's full domain name.
+			*
+			* rrtype:          The resource record's type (e.g. PTR, SRV, etc) as defined in nameser.h.
+			*
+			* rrclass:         The class of the resource record, as defined in nameser.h (usually 1).
+			*
+			* rdata:           The raw rdata of the resource record.
+			*
+			*/
+			static public void
+			ReconfirmRecord
+				(
+				ServiceFlags	flags,
+				int				interfaceIndex,
+				String		*	fullname,
+				int				rrtype,
+				int				rrclass,
+				Byte			rdata[]
+				);
+		};
+	}
+}
diff --git a/mDNSWindows/DLL.NET/dnssd_NET.ico b/mDNSWindows/DLL.NET/dnssd_NET.ico
new file mode 100755
index 0000000000000000000000000000000000000000..3a5525fd794f7a7c5c8e6187f470ea3af38cd2b6
GIT binary patch
literal 1078
zcmeHHJr05}7=1t!Hp3A*8IHkVf+j?-!eHY14Gtcw1Eb*_9>Bq^zETJ@GKj{_2j4$w
zo9}xCh!8{T3=X##Skq>ikMjsvB|y%crWBM2iW(4pI}c%z6%lW!=~4v77#3{z!dmB1
z__&l)-{KUYR+|8|;wB^R|9ET$J@(@=#rd^=)qs85?vAy(PSF5CyNkus435LVkZ$rj
zNw|JG-P7^hF<(;#o*Vk}5R#e|^13tBbQkeF?djULtvqyxd3<cQetc!+$5J+aVZ&1f
Qa92%&%o_p!1^%7_Ps0Y#2><{9

literal 0
HcmV?d00001

diff --git a/mDNSWindows/DLL.NET/dnssd_NET.rc b/mDNSWindows/DLL.NET/dnssd_NET.rc
new file mode 100755
index 0000000..f3c3dd4
--- /dev/null
+++ b/mDNSWindows/DLL.NET/dnssd_NET.rc
@@ -0,0 +1,113 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+#include "WinVersRes.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+1                       ICON                    "dnssd_NET.ico"
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE 
+BEGIN
+    "resource.h\0"
+    "\0"
+END
+
+2 TEXTINCLUDE 
+BEGIN
+    "#include ""afxres.h""\r\n"
+    "\0"
+END
+
+3 TEXTINCLUDE 
+BEGIN
+    "\r\n"
+    "\0"
+END
+
+#endif    // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION MASTER_PROD_VERS
+ PRODUCTVERSION MASTER_PROD_VERS
+ FILEFLAGSMASK 0x17L
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+    BLOCK "StringFileInfo"
+    BEGIN
+        BLOCK "040904b0"
+        BEGIN
+            VALUE "CompanyName", "Apple Computer, Inc."
+            VALUE "FileDescription", "dnssd.NET Dynamic Link Library"
+            VALUE "FileVersion", MASTER_PROD_VERS_STR
+            VALUE "InternalName", "dnssd.NET"
+            VALUE "LegalCopyright", "Copyright (C) 2004"
+            VALUE "OriginalFilename", "dnssd.NET.dll"
+            VALUE "ProductName", MASTER_PROD_NAME
+            VALUE "ProductVersion", MASTER_PROD_VERS_STR
+        END
+    END
+    BLOCK "VarFileInfo"
+    BEGIN
+        VALUE "Translation", 0x409, 1200
+    END
+END
+
+#endif    // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif    // not APSTUDIO_INVOKED
+
diff --git a/mDNSWindows/DLL.NET/dnssd_NET.vcproj b/mDNSWindows/DLL.NET/dnssd_NET.vcproj
new file mode 100755
index 0000000..f2145d9
--- /dev/null
+++ b/mDNSWindows/DLL.NET/dnssd_NET.vcproj
@@ -0,0 +1,154 @@
+<?xml version="1.0" encoding = "Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="7.00"
+	Name="DLL.NET"
+	ProjectGUID="{9C6701E2-82B7-44B7-9B5E-3897D9153F79}"
+	Keyword="ManagedCProj">
+	<Platforms>
+		<Platform
+			Name="Win32"/>
+	</Platforms>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory=".\Debug"
+			IntermediateDirectory=".\Debug"
+			ConfigurationType="2"
+			CharacterSet="2"
+			ManagedExtensions="TRUE">
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="../;../../mDNSShared"
+				PreprocessorDefinitions="WIN32;_WIN32;_DEBUG;WIN32_LEAN_AND_MEAN"
+				MinimalRebuild="FALSE"
+				BasicRuntimeChecks="0"
+				RuntimeLibrary="1"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				DebugInformationFormat="3"
+				CallingConvention="2"/>
+			<Tool
+				Name="VCCustomBuildTool"/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalOptions="/noentry"
+				AdditionalDependencies="../DLL/Debug/dnssd.lib mscoree.lib ws2_32.lib msvcrtd.lib"
+				OutputFile="$(OutDir)\dnssd.NET.dll"
+				LinkIncremental="2"
+				AdditionalLibraryDirectories=""
+				GenerateDebugInformation="TRUE"/>
+			<Tool
+				Name="VCMIDLTool"/>
+			<Tool
+				Name="VCPostBuildEventTool"/>
+			<Tool
+				Name="VCPreBuildEventTool"
+				Description="Generating keypair..."
+				CommandLine="sn -k dnssd_NET.snk"/>
+			<Tool
+				Name="VCPreLinkEventTool"/>
+			<Tool
+				Name="VCResourceCompilerTool"
+				AdditionalIncludeDirectories="../"/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"/>
+			<Tool
+				Name="VCWebDeploymentTool"/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory=".\Release"
+			IntermediateDirectory=".\Release"
+			ConfigurationType="2"
+			CharacterSet="2"
+			ManagedExtensions="TRUE">
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalOptions="/Zl"
+				AdditionalIncludeDirectories="../;../../mDNSShared"
+				PreprocessorDefinitions="WIN32;NDEBUG;WIN32_LEAN_AND_MEAN"
+				MinimalRebuild="FALSE"
+				RuntimeLibrary="0"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				DebugInformationFormat="3"/>
+			<Tool
+				Name="VCCustomBuildTool"/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalOptions="/noentry"
+				AdditionalDependencies="../DLL/Release/dnssd.lib mscoree.lib ws2_32.lib msvcrt.lib"
+				OutputFile="$(OutDir)\dnssd.NET.dll"
+				LinkIncremental="1"
+				GenerateDebugInformation="TRUE"/>
+			<Tool
+				Name="VCMIDLTool"/>
+			<Tool
+				Name="VCPostBuildEventTool"/>
+			<Tool
+				Name="VCPreBuildEventTool"
+				Description="Generating keypair..."
+				CommandLine="sn -k dnssd_NET.snk"/>
+			<Tool
+				Name="VCPreLinkEventTool"/>
+			<Tool
+				Name="VCResourceCompilerTool"
+				AdditionalIncludeDirectories="../"/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"/>
+			<Tool
+				Name="VCWebDeploymentTool"/>
+		</Configuration>
+	</Configurations>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
+			<File
+				RelativePath=".\AssemblyInfo.cpp">
+			</File>
+			<File
+				RelativePath=".\Stdafx.cpp">
+			</File>
+			<File
+				RelativePath=".\dnssd_NET.cpp">
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
+			<File
+				RelativePath="PString.h">
+			</File>
+			<File
+				RelativePath=".\Stdafx.h">
+			</File>
+			<File
+				RelativePath=".\dnssd_NET.h">
+			</File>
+			<File
+				RelativePath=".\resource.h">
+			</File>
+		</Filter>
+		<Filter
+			Name="Resource Files"
+			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
+			UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">
+			<File
+				RelativePath="dnssd_NET.ico">
+			</File>
+			<File
+				RelativePath="dnssd_NET.rc">
+			</File>
+		</Filter>
+		<File
+			RelativePath=".\ReadMe.txt">
+		</File>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
diff --git a/mDNSWindows/DLL.NET/resource.h b/mDNSWindows/DLL.NET/resource.h
new file mode 100755
index 0000000..29338aa
--- /dev/null
+++ b/mDNSWindows/DLL.NET/resource.h
@@ -0,0 +1,3 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by dnssd_NET.rc
diff --git a/mDNSWindows/DLL/dll.aps b/mDNSWindows/DLL/dll.aps
new file mode 100644
index 0000000000000000000000000000000000000000..31b4787e30c720c038d88ca0ba13b5332374ac8b
GIT binary patch
literal 18692
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

literal 0
HcmV?d00001

diff --git a/mDNSWindows/DLL/dll.rc b/mDNSWindows/DLL/dll.rc
new file mode 100644
index 0000000..70b4839
--- /dev/null
+++ b/mDNSWindows/DLL/dll.rc
@@ -0,0 +1,102 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+#include "WinVersRes.h"
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE 
+BEGIN
+    "resource.h\0"
+END
+
+2 TEXTINCLUDE 
+BEGIN
+    "#include ""afxres.h""\r\n"
+    "#include ""WinVersRes.h""\0"
+END
+
+3 TEXTINCLUDE 
+BEGIN
+    "\r\n"
+    "\0"
+END
+
+#endif    // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION MASTER_PROD_VERS
+ PRODUCTVERSION MASTER_PROD_VERS
+ FILEFLAGSMASK 0x17L
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+    BLOCK "StringFileInfo"
+    BEGIN
+        BLOCK "040904b0"
+        BEGIN
+            VALUE "CompanyName", "Apple Computer, Inc."
+            VALUE "FileDescription", "dnssd Dynamic Link Library"
+            VALUE "FileVersion", MASTER_PROD_VERS_STR
+            VALUE "InternalName", "dnssd"
+            VALUE "LegalCopyright", "Copyright (C) 2004"
+            VALUE "OriginalFilename", "dnssd.dll"
+            VALUE "ProductName", MASTER_PROD_NAME
+            VALUE "ProductVersion", MASTER_PROD_VERS_STR
+        END
+    END
+    BLOCK "VarFileInfo"
+    BEGIN
+        VALUE "Translation", 0x409, 1200
+    END
+END
+
+#endif    // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif    // not APSTUDIO_INVOKED
+
diff --git a/mDNSWindows/Applications/DLL/dllmain.c b/mDNSWindows/DLL/dllmain.c
similarity index 91%
rename from mDNSWindows/Applications/DLL/dllmain.c
rename to mDNSWindows/DLL/dllmain.c
index db9906e..a15aedf 100644
--- a/mDNSWindows/Applications/DLL/dllmain.c
+++ b/mDNSWindows/DLL/dllmain.c
@@ -3,8 +3,6 @@
  *
  * @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
@@ -25,12 +23,15 @@
     Change History (most recent first):
     
 $Log: dllmain.c,v $
+Revision 1.1  2004/06/18 03:55:11  rpantos
+Move DLL up to main level; additional integration from Scott.
+
 Revision 1.1  2004/02/21 04:16:50  bradley
 DLL wrapper for DNS-SD API.
 
 */
 
-#include	"DNSSD.h"
+#include <windows.h>
 
 BOOL APIENTRY	DllMain( HANDLE inModule, DWORD inReason, LPVOID inReserved )
 {
diff --git a/mDNSWindows/Applications/DLL/dnssd.def b/mDNSWindows/DLL/dnssd.def
similarity index 79%
rename from mDNSWindows/Applications/DLL/dnssd.def
rename to mDNSWindows/DLL/dnssd.def
index 587489e..6249046 100644
--- a/mDNSWindows/Applications/DLL/dnssd.def
+++ b/mDNSWindows/DLL/dnssd.def
@@ -23,6 +23,12 @@
 ;	Change History (most recent first):
 ;    
 ; $Log: dnssd.def,v $
+; Revision 1.2  2004/07/19 07:43:59  shersche
+; export TXTRecord APIs
+;
+; Revision 1.1  2004/06/18 03:55:11  rpantos
+; Move DLL up to main level; additional integration from Scott.
+;
 ; Revision 1.2  2004/03/19 10:07:14  bradley
 ; Export all DNS-SD API symbols from the DLL so they can be used by clients.
 ;
@@ -32,14 +38,9 @@
 ;
 ;
 
-LIBRARY		DNSSD
+LIBRARY		dnssd
 
 EXPORTS
-	DNSServiceInitialize
-	DNSServiceFinalize
-	DNSServiceCheckVersion
-	DNSServiceCopyProperty
-	DNSServiceReleaseProperty
 	DNSServiceRefSockFD
 	DNSServiceProcessResult
 	DNSServiceRefDeallocate
@@ -55,3 +56,13 @@ EXPORTS
 	DNSServiceRegisterRecord
 	DNSServiceQueryRecord
 	DNSServiceReconfirmRecord
+	TXTRecordCreate
+	TXTRecordDeallocate
+	TXTRecordSetValue
+	TXTRecordRemoveValue
+	TXTRecordContainsKey
+	TXTRecordGetCount
+	TXTRecordGetLength
+	TXTRecordGetBytesPtr
+	TXTRecordGetValuePtr
+	TXTRecordGetItemAtIndex
diff --git a/mDNSWindows/DLL/dnssd.vcproj b/mDNSWindows/DLL/dnssd.vcproj
new file mode 100644
index 0000000..01e412b
--- /dev/null
+++ b/mDNSWindows/DLL/dnssd.vcproj
@@ -0,0 +1,178 @@
+<?xml version="1.0" encoding = "Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="7.00"
+	Name="DLL"
+	ProjectGUID="{AB581101-18F0-46F6-B56A-83A6B1EA657E}"
+	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;../../mDNSShared;../"
+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;DEBUG=1;MDNS_DEBUGMSGS=0;WIN32_LEAN_AND_MEAN;USE_TCP_LOOPBACK"
+				StringPooling="TRUE"
+				MinimalRebuild="TRUE"
+				ExceptionHandling="FALSE"
+				BasicRuntimeChecks="3"
+				SmallerTypeCheck="TRUE"
+				RuntimeLibrary="1"
+				BufferSecurityCheck="TRUE"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				Detect64BitPortabilityProblems="TRUE"
+				DebugInformationFormat="4"
+				CallingConvention="2"
+				CompileAs="0"/>
+			<Tool
+				Name="VCCustomBuildTool"/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="ws2_32.lib iphlpapi.lib"
+				OutputFile="$(OutDir)/dnssd.dll"
+				LinkIncremental="2"
+				ModuleDefinitionFile="dnssd.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"
+				AdditionalIncludeDirectories="../"/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"/>
+			<Tool
+				Name="VCWebDeploymentTool"/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="Release"
+			IntermediateDirectory="Release"
+			ConfigurationType="2"
+			CharacterSet="2">
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories="../../mDNSCore;../../mDNSShared;../"
+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MDNS_DEBUGMSGS=0;WIN32_LEAN_AND_MEAN;USE_TCP_LOOPBACK"
+				RuntimeLibrary="0"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				Detect64BitPortabilityProblems="TRUE"
+				DebugInformationFormat="3"
+				CallingConvention="2"
+				CompileAs="0"/>
+			<Tool
+				Name="VCCustomBuildTool"/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="ws2_32.lib iphlpapi.lib"
+				OutputFile="$(OutDir)/dnssd.dll"
+				LinkIncremental="1"
+				ModuleDefinitionFile="dnssd.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"
+				AdditionalIncludeDirectories="../"/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"/>
+			<Tool
+				Name="VCWebDeploymentTool"/>
+		</Configuration>
+	</Configurations>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
+			<File
+				RelativePath="..\DebugServices.c">
+			</File>
+			<File
+				RelativePath="..\..\mDNSShared\GenLinkedList.c">
+			</File>
+			<File
+				RelativePath=".\dllmain.c">
+			</File>
+			<File
+				RelativePath=".\dnssd.def">
+			</File>
+			<File
+				RelativePath="..\..\mDNSShared\dnssd_clientlib.c">
+			</File>
+			<File
+				RelativePath="..\..\mDNSShared\dnssd_clientstub.c">
+			</File>
+			<File
+				RelativePath="..\..\mDNSShared\dnssd_ipc.c">
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
+			<File
+				RelativePath="..\CommonServices.h">
+			</File>
+			<File
+				RelativePath="..\DebugServices.h">
+			</File>
+			<File
+				RelativePath="..\..\mDNSShared\GenLinkedList.h">
+			</File>
+			<File
+				RelativePath="..\..\mDNSShared\dns_sd.h">
+			</File>
+			<File
+				RelativePath="..\..\mDNSShared\dnssd_ipc.h">
+			</File>
+			<File
+				RelativePath="..\..\mDNSShared\dnssd_sock.h">
+			</File>
+			<File
+				RelativePath=".\resource.h">
+			</File>
+		</Filter>
+		<Filter
+			Name="Resource Files"
+			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
+			UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">
+			<File
+				RelativePath=".\dll.rc">
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
diff --git a/mDNSWindows/DLL/resource.h b/mDNSWindows/DLL/resource.h
new file mode 100644
index 0000000..bdea251
--- /dev/null
+++ b/mDNSWindows/DLL/resource.h
@@ -0,0 +1,27 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by dll.rc
+//
+#define IDS_PROJNAME                    100
+#define IDR_WMDMLOGGER                  101
+#define IDS_LOG_SEV_INFO                201
+#define IDS_LOG_SEV_WARN                202
+#define IDS_LOG_SEV_ERROR               203
+#define IDS_LOG_DATETIME                204
+#define IDS_LOG_SRCNAME                 205
+#define IDS_DEF_LOGFILE                 301
+#define IDS_DEF_MAXSIZE                 302
+#define IDS_DEF_SHRINKTOSIZE            303
+#define IDS_DEF_LOGENABLED              304
+#define IDS_MUTEX_TIMEOUT               401
+
+// Next default values for new objects
+// 
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE        201
+#define _APS_NEXT_COMMAND_VALUE         32768
+#define _APS_NEXT_CONTROL_VALUE         201
+#define _APS_NEXT_SYMED_VALUE           101
+#endif
+#endif
diff --git a/mDNSWindows/DNSSD.c b/mDNSWindows/DNSSD.c
deleted file mode 100644
index 24bc560..0000000
--- a/mDNSWindows/DNSSD.c
+++ /dev/null
@@ -1,1720 +0,0 @@
-/*
- * 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
deleted file mode 100644
index 11cd6e3..0000000
--- a/mDNSWindows/DNSSD.h
+++ /dev/null
@@ -1,1689 +0,0 @@
-/*
- * 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
deleted file mode 100644
index c20a97e..0000000
--- a/mDNSWindows/DNSSDDirect.c
+++ /dev/null
@@ -1,1863 +0,0 @@
-/*
- * 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
deleted file mode 100644
index be7acb0..0000000
--- a/mDNSWindows/DNSSDDirect.h
+++ /dev/null
@@ -1,285 +0,0 @@
-/*
- * 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__
diff --git a/mDNSWindows/Applications/DNSServiceBrowser/Windows/ApplicationVS2002.sln b/mDNSWindows/DNSServiceBrowser/Windows/ApplicationVS2002.sln
similarity index 100%
rename from mDNSWindows/Applications/DNSServiceBrowser/Windows/ApplicationVS2002.sln
rename to mDNSWindows/DNSServiceBrowser/Windows/ApplicationVS2002.sln
diff --git a/mDNSWindows/Applications/DNSServiceBrowser/Windows/ApplicationVS2002.vcproj b/mDNSWindows/DNSServiceBrowser/Windows/ApplicationVS2002.vcproj
similarity index 98%
rename from mDNSWindows/Applications/DNSServiceBrowser/Windows/ApplicationVS2002.vcproj
rename to mDNSWindows/DNSServiceBrowser/Windows/ApplicationVS2002.vcproj
index 5d72e30..c1a2424 100644
--- a/mDNSWindows/Applications/DNSServiceBrowser/Windows/ApplicationVS2002.vcproj
+++ b/mDNSWindows/DNSServiceBrowser/Windows/ApplicationVS2002.vcproj
@@ -50,7 +50,7 @@
 				Name="VCLinkerTool"
 				AdditionalOptions="/MACHINE:I386 /IGNORE:4089"
 				AdditionalDependencies="ws2_32.lib"
-				OutputFile="Rendezvous Browser Debug.exe"
+				OutputFile="DNSServiceBrowser Debug.exe"
 				LinkIncremental="1"
 				SuppressStartupBanner="TRUE"
 				IgnoreDefaultLibraryNames="wsock32.lib"
@@ -122,7 +122,7 @@
 				Name="VCLinkerTool"
 				AdditionalOptions="/MACHINE:I386 /IGNORE:4089"
 				AdditionalDependencies="ws2_32.lib"
-				OutputFile="Rendezvous Browser.exe"
+				OutputFile="DNSServiceBrowser.exe"
 				LinkIncremental="1"
 				SuppressStartupBanner="TRUE"
 				IgnoreDefaultLibraryNames="wsock32.lib"
diff --git a/mDNSWindows/Applications/DNSServiceBrowser/Windows/ApplicationVS2003.sln b/mDNSWindows/DNSServiceBrowser/Windows/ApplicationVS2003.sln
similarity index 100%
rename from mDNSWindows/Applications/DNSServiceBrowser/Windows/ApplicationVS2003.sln
rename to mDNSWindows/DNSServiceBrowser/Windows/ApplicationVS2003.sln
diff --git a/mDNSWindows/Applications/DNSServiceBrowser/Windows/ApplicationVS2003.vcproj b/mDNSWindows/DNSServiceBrowser/Windows/ApplicationVS2003.vcproj
similarity index 98%
rename from mDNSWindows/Applications/DNSServiceBrowser/Windows/ApplicationVS2003.vcproj
rename to mDNSWindows/DNSServiceBrowser/Windows/ApplicationVS2003.vcproj
index f3b4e9a..3c8cb1c 100644
--- a/mDNSWindows/Applications/DNSServiceBrowser/Windows/ApplicationVS2003.vcproj
+++ b/mDNSWindows/DNSServiceBrowser/Windows/ApplicationVS2003.vcproj
@@ -50,7 +50,7 @@
 				Name="VCLinkerTool"
 				AdditionalOptions="/MACHINE:I386 /IGNORE:4089"
 				AdditionalDependencies="ws2_32.lib"
-				OutputFile="Rendezvous Browser Debug.exe"
+				OutputFile="DNSServiceBrowser Debug.exe"
 				LinkIncremental="1"
 				SuppressStartupBanner="TRUE"
 				IgnoreDefaultLibraryNames="wsock32.lib"
@@ -128,7 +128,7 @@
 				Name="VCLinkerTool"
 				AdditionalOptions="/MACHINE:I386 /IGNORE:4089"
 				AdditionalDependencies="ws2_32.lib"
-				OutputFile="Rendezvous Browser.exe"
+				OutputFile="DNSServiceBrowser.exe"
 				LinkIncremental="1"
 				SuppressStartupBanner="TRUE"
 				IgnoreDefaultLibraryNames="wsock32.lib"
diff --git a/mDNSWindows/Applications/DNSServiceBrowser/Windows/Resources/Application.ico b/mDNSWindows/DNSServiceBrowser/Windows/Resources/Application.ico
similarity index 100%
rename from mDNSWindows/Applications/DNSServiceBrowser/Windows/Resources/Application.ico
rename to mDNSWindows/DNSServiceBrowser/Windows/Resources/Application.ico
diff --git a/mDNSWindows/Applications/DNSServiceBrowser/Windows/Resources/Application.rc b/mDNSWindows/DNSServiceBrowser/Windows/Resources/Application.rc
similarity index 95%
rename from mDNSWindows/Applications/DNSServiceBrowser/Windows/Resources/Application.rc
rename to mDNSWindows/DNSServiceBrowser/Windows/Resources/Application.rc
index cf2f292..3943139 100644
--- a/mDNSWindows/Applications/DNSServiceBrowser/Windows/Resources/Application.rc
+++ b/mDNSWindows/DNSServiceBrowser/Windows/Resources/Application.rc
@@ -77,7 +77,7 @@ 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"
+CAPTION "DNSServiceBrowser"
 MENU IDR_CHOOSER_DIALOG_MENU
 FONT 8, "MS Shell Dlg", 0, 0, 0x0
 BEGIN
@@ -111,11 +111,11 @@ END
 
 IDD_ABOUT_DIALOG DIALOGEX 0, 0, 244, 73
 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION
-CAPTION "About Rendezvous Browser"
+CAPTION "About DNSServiceBrowser"
 FONT 8, "MS Shell Dlg", 0, 0, 0x0
 BEGIN
     ICON            IDR_MAIN_ICON,IDC_ABOUT_APP_ICON,12,12,20,20
-    LTEXT           "Rendezvous Browser",IDC_ABOUT_APP_NAME_TEXT,44,11,192,
+    LTEXT           "DNSServiceBrowser",IDC_ABOUT_APP_NAME_TEXT,44,11,192,
                     12
     LTEXT           "Version 1.2d1",IDC_ABOUT_APP_VERSION_TEXT,44,25,192,8
     LTEXT           "Copyright (C) 2002-2004 Apple Computer, Inc.",
@@ -163,12 +163,12 @@ BEGIN
         BLOCK "040904b0"
         BEGIN
             VALUE "CompanyName", "Apple Computer, Inc."
-            VALUE "FileDescription", "Rendezvous Browser for Windows"
+            VALUE "FileDescription", "DNSServiceBrowser for Windows"
             VALUE "FileVersion", "1, 0, 0, 1"
-            VALUE "InternalName", "Rendezvous Browser for Windows"
+            VALUE "InternalName", "DNSServiceBrowser for Windows"
             VALUE "LegalCopyright", "Copyright (C) 2002-2004 Apple Computer, Inc."
-            VALUE "OriginalFilename", "RendezvousBrowser.exe"
-            VALUE "ProductName", "Rendezvous Browser for Windows"
+            VALUE "OriginalFilename", "DNSServiceBrowser.exe"
+            VALUE "ProductName", "DNSServiceBrowser for Windows"
             VALUE "ProductVersion", "1, 0, 0, 1"
         END
     END
@@ -194,7 +194,7 @@ BEGIN
     END
     POPUP "Help"
     BEGIN
-        MENUITEM "About Rendezvous Browser...", ID_HELP_ABOUT
+        MENUITEM "About DNSServiceBrowser...", ID_HELP_ABOUT
     END
 END
 
@@ -285,7 +285,7 @@ END
 
 STRINGTABLE 
 BEGIN
-    IDS_ABOUTBOX            "&About Rendezvous Browser"
+    IDS_ABOUTBOX            "&About DNSServiceBrowser"
     IDS_CHOOSER_DOMAIN_COLUMN_NAME "Domains"
     IDP_SOCKETS_INIT_FAILED "Windows sockets initialization failed."
     IDS_CHOOSER_SERVICE_COLUMN_TYPE "Services"
diff --git a/mDNSWindows/Applications/DNSServiceBrowser/Windows/Resources/Application.rc2 b/mDNSWindows/DNSServiceBrowser/Windows/Resources/Application.rc2
similarity index 86%
rename from mDNSWindows/Applications/DNSServiceBrowser/Windows/Resources/Application.rc2
rename to mDNSWindows/DNSServiceBrowser/Windows/Resources/Application.rc2
index 9c76766..ce71791 100644
--- a/mDNSWindows/Applications/DNSServiceBrowser/Windows/Resources/Application.rc2
+++ b/mDNSWindows/DNSServiceBrowser/Windows/Resources/Application.rc2
@@ -23,17 +23,23 @@
     Change History (most recent first):
 
 $Log: Application.rc2,v $
+Revision 1.2  2004/07/13 21:24:26  rpantos
+Fix for <rdar://problem/3701120>.
+
+Revision 1.1  2004/06/18 04:04:35  rpantos
+Move up one level
+
 Revision 1.2  2004/01/30 02:56:33  bradley
 Updated to support full Unicode display. Added support for all services on www.dns-sd.org.
 
 Revision 1.1  2003/08/21 02:06:46  bradley
-Moved Rendezvous Browser for non-Windows CE into Windows sub-folder.
+Moved DNSServiceBrowser for non-Windows CE into Windows sub-folder.
 
 Revision 1.2  2003/08/20 07:06:34  bradley
 Update to APSL 2.0. Updated change history to match other mDNSResponder files.
 
 Revision 1.1  2002/09/20 06:12:48  bradley
-Rendezvous Browser for Windows
+DNSServiceBrowser for Windows
 
 */
 
diff --git a/mDNSWindows/Applications/DNSServiceBrowser/Windows/Resources/Resource.h b/mDNSWindows/DNSServiceBrowser/Windows/Resources/Resource.h
similarity index 100%
rename from mDNSWindows/Applications/DNSServiceBrowser/Windows/Resources/Resource.h
rename to mDNSWindows/DNSServiceBrowser/Windows/Resources/Resource.h
diff --git a/mDNSWindows/Applications/DNSServiceBrowser/Windows/Sources/AboutDialog.cpp b/mDNSWindows/DNSServiceBrowser/Windows/Sources/AboutDialog.cpp
similarity index 93%
rename from mDNSWindows/Applications/DNSServiceBrowser/Windows/Sources/AboutDialog.cpp
rename to mDNSWindows/DNSServiceBrowser/Windows/Sources/AboutDialog.cpp
index 50142c2..5984f33 100644
--- a/mDNSWindows/Applications/DNSServiceBrowser/Windows/Sources/AboutDialog.cpp
+++ b/mDNSWindows/DNSServiceBrowser/Windows/Sources/AboutDialog.cpp
@@ -3,8 +3,6 @@
  *
  * @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
@@ -25,11 +23,17 @@
     Change History (most recent first):
     
 $Log: AboutDialog.cpp,v $
+Revision 1.2  2004/07/13 21:24:26  rpantos
+Fix for <rdar://problem/3701120>.
+
+Revision 1.1  2004/06/18 04:04:36  rpantos
+Move up one level
+
 Revision 1.2  2004/01/30 02:56:32  bradley
 Updated to support full Unicode display. Added support for all services on www.dns-sd.org.
 
 Revision 1.1  2003/08/21 02:06:47  bradley
-Moved Rendezvous Browser for non-Windows CE into Windows sub-folder.
+Moved DNSServiceBrowser for non-Windows CE into Windows sub-folder.
 
 Revision 1.4  2003/08/12 19:56:28  cheshire
 Update to APSL 2.0
@@ -41,7 +45,7 @@ Revision 1.2  2002/09/21 20:44:55  zarzycki
 Added APSL info
 
 Revision 1.1  2002/09/20 06:12:49  bradley
-Rendezvous Browser for Windows
+DNSServiceBrowser for Windows
 
 */
 
diff --git a/mDNSWindows/Applications/DNSServiceBrowser/Windows/Sources/AboutDialog.h b/mDNSWindows/DNSServiceBrowser/Windows/Sources/AboutDialog.h
similarity index 92%
rename from mDNSWindows/Applications/DNSServiceBrowser/Windows/Sources/AboutDialog.h
rename to mDNSWindows/DNSServiceBrowser/Windows/Sources/AboutDialog.h
index ee97731..8263432 100644
--- a/mDNSWindows/Applications/DNSServiceBrowser/Windows/Sources/AboutDialog.h
+++ b/mDNSWindows/DNSServiceBrowser/Windows/Sources/AboutDialog.h
@@ -3,8 +3,6 @@
  *
  * @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
@@ -25,11 +23,17 @@
     Change History (most recent first):
     
 $Log: AboutDialog.h,v $
+Revision 1.2  2004/07/13 21:24:26  rpantos
+Fix for <rdar://problem/3701120>.
+
+Revision 1.1  2004/06/18 04:04:36  rpantos
+Move up one level
+
 Revision 1.2  2004/01/30 02:56:32  bradley
 Updated to support full Unicode display. Added support for all services on www.dns-sd.org.
 
 Revision 1.1  2003/08/21 02:06:47  bradley
-Moved Rendezvous Browser for non-Windows CE into Windows sub-folder.
+Moved DNSServiceBrowser for non-Windows CE into Windows sub-folder.
 
 Revision 1.4  2003/08/12 19:56:28  cheshire
 Update to APSL 2.0
@@ -41,7 +45,7 @@ Revision 1.2  2002/09/21 20:44:55  zarzycki
 Added APSL info
 
 Revision 1.1  2002/09/20 06:12:50  bradley
-Rendezvous Browser for Windows
+DNSServiceBrowser for Windows
 
 */
 
diff --git a/mDNSWindows/Applications/DNSServiceBrowser/Windows/Sources/Application.cpp b/mDNSWindows/DNSServiceBrowser/Windows/Sources/Application.cpp
similarity index 94%
rename from mDNSWindows/Applications/DNSServiceBrowser/Windows/Sources/Application.cpp
rename to mDNSWindows/DNSServiceBrowser/Windows/Sources/Application.cpp
index 1fb0723..8d1dcfd 100644
--- a/mDNSWindows/Applications/DNSServiceBrowser/Windows/Sources/Application.cpp
+++ b/mDNSWindows/DNSServiceBrowser/Windows/Sources/Application.cpp
@@ -3,8 +3,6 @@
  *
  * @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
@@ -25,11 +23,17 @@
     Change History (most recent first):
     
 $Log: Application.cpp,v $
+Revision 1.2  2004/07/13 21:24:26  rpantos
+Fix for <rdar://problem/3701120>.
+
+Revision 1.1  2004/06/18 04:04:36  rpantos
+Move up one level
+
 Revision 1.2  2004/01/30 02:56:32  bradley
 Updated to support full Unicode display. Added support for all services on www.dns-sd.org.
 
 Revision 1.1  2003/08/21 02:06:47  bradley
-Moved Rendezvous Browser for non-Windows CE into Windows sub-folder.
+Moved DNSServiceBrowser for non-Windows CE into Windows sub-folder.
 
 Revision 1.5  2003/08/12 19:56:28  cheshire
 Update to APSL 2.0
@@ -44,7 +48,7 @@ Revision 1.2  2002/09/20 08:37:34  bradley
 Increased the DNS record cache from the default of 64 to 512 entries for larger networks.
 
 Revision 1.1  2002/09/20 06:12:51  bradley
-Rendezvous Browser for Windows
+DNSServiceBrowser for Windows
 
 */
 
diff --git a/mDNSWindows/Applications/DNSServiceBrowser/Windows/Sources/Application.h b/mDNSWindows/DNSServiceBrowser/Windows/Sources/Application.h
similarity index 92%
rename from mDNSWindows/Applications/DNSServiceBrowser/Windows/Sources/Application.h
rename to mDNSWindows/DNSServiceBrowser/Windows/Sources/Application.h
index 30705d3..498dd07 100644
--- a/mDNSWindows/Applications/DNSServiceBrowser/Windows/Sources/Application.h
+++ b/mDNSWindows/DNSServiceBrowser/Windows/Sources/Application.h
@@ -3,8 +3,6 @@
  *
  * @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
@@ -25,11 +23,17 @@
     Change History (most recent first):
     
 $Log: Application.h,v $
+Revision 1.2  2004/07/13 21:24:26  rpantos
+Fix for <rdar://problem/3701120>.
+
+Revision 1.1  2004/06/18 04:04:36  rpantos
+Move up one level
+
 Revision 1.2  2004/01/30 02:56:32  bradley
 Updated to support full Unicode display. Added support for all services on www.dns-sd.org.
 
 Revision 1.1  2003/08/21 02:06:47  bradley
-Moved Rendezvous Browser for non-Windows CE into Windows sub-folder.
+Moved DNSServiceBrowser for non-Windows CE into Windows sub-folder.
 
 Revision 1.4  2003/08/12 19:56:28  cheshire
 Update to APSL 2.0
@@ -41,7 +45,7 @@ Revision 1.2  2002/09/21 20:44:55  zarzycki
 Added APSL info
 
 Revision 1.1  2002/09/20 06:12:51  bradley
-Rendezvous Browser for Windows
+DNSServiceBrowser for Windows
 
 */
 
diff --git a/mDNSWindows/Applications/DNSServiceBrowser/Windows/Sources/ChooserDialog.cpp b/mDNSWindows/DNSServiceBrowser/Windows/Sources/ChooserDialog.cpp
similarity index 99%
rename from mDNSWindows/Applications/DNSServiceBrowser/Windows/Sources/ChooserDialog.cpp
rename to mDNSWindows/DNSServiceBrowser/Windows/Sources/ChooserDialog.cpp
index 162acda..0435f61 100644
--- a/mDNSWindows/Applications/DNSServiceBrowser/Windows/Sources/ChooserDialog.cpp
+++ b/mDNSWindows/DNSServiceBrowser/Windows/Sources/ChooserDialog.cpp
@@ -3,8 +3,6 @@
  *
  * @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
@@ -25,6 +23,12 @@
     Change History (most recent first):
     
 $Log: ChooserDialog.cpp,v $
+Revision 1.2  2004/07/13 21:24:26  rpantos
+Fix for <rdar://problem/3701120>.
+
+Revision 1.1  2004/06/18 04:04:36  rpantos
+Move up one level
+
 Revision 1.10  2004/04/23 01:19:41  bradley
 Changed TXT record new line delimiter from \n to \r\n so it works now that it is an edit text.
 
@@ -56,7 +60,7 @@ from Andrew van der Stock for the addition of an _rfb._tcp service type for a VN
 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.
+Moved DNSServiceBrowser for non-Windows CE into Windows sub-folder.
 
 Revision 1.7  2003/08/20 06:45:56  bradley
 Updated for IP address changes in DNSServices. Added support for browsing for Xserve RAID.
@@ -78,7 +82,7 @@ Make sure each resolved item matches the selected service type to handle resolve
 been queued up on the Windows Message Loop. Reduce column to fit when scrollbar is present.
 
 Revision 1.1  2002/09/20 06:12:52  bradley
-Rendezvous Browser for Windows
+DNSServiceBrowser for Windows
 
 */
 
diff --git a/mDNSWindows/Applications/DNSServiceBrowser/Windows/Sources/ChooserDialog.h b/mDNSWindows/DNSServiceBrowser/Windows/Sources/ChooserDialog.h
similarity index 95%
rename from mDNSWindows/Applications/DNSServiceBrowser/Windows/Sources/ChooserDialog.h
rename to mDNSWindows/DNSServiceBrowser/Windows/Sources/ChooserDialog.h
index a98e5b6..8bda96c 100644
--- a/mDNSWindows/Applications/DNSServiceBrowser/Windows/Sources/ChooserDialog.h
+++ b/mDNSWindows/DNSServiceBrowser/Windows/Sources/ChooserDialog.h
@@ -3,8 +3,6 @@
  *
  * @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
@@ -25,6 +23,12 @@
     Change History (most recent first):
     
 $Log: ChooserDialog.h,v $
+Revision 1.2  2004/07/13 21:24:26  rpantos
+Fix for <rdar://problem/3701120>.
+
+Revision 1.1  2004/06/18 04:04:36  rpantos
+Move up one level
+
 Revision 1.3  2004/01/30 02:56:32  bradley
 Updated to support full Unicode display. Added support for all services on www.dns-sd.org.
 
@@ -32,7 +36,7 @@ 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.
+Moved DNSServiceBrowser for non-Windows CE into Windows sub-folder.
 
 Revision 1.4  2003/08/12 19:56:28  cheshire
 Update to APSL 2.0
@@ -44,7 +48,7 @@ Revision 1.2  2002/09/21 20:44:55  zarzycki
 Added APSL info
 
 Revision 1.1  2002/09/20 06:12:52  bradley
-Rendezvous Browser for Windows
+DNSServiceBrowser for Windows
 
 */
 
diff --git a/mDNSWindows/Applications/DNSServiceBrowser/Windows/Sources/LoginDialog.cpp b/mDNSWindows/DNSServiceBrowser/Windows/Sources/LoginDialog.cpp
similarity index 98%
rename from mDNSWindows/Applications/DNSServiceBrowser/Windows/Sources/LoginDialog.cpp
rename to mDNSWindows/DNSServiceBrowser/Windows/Sources/LoginDialog.cpp
index b35e76b..c3869e7 100644
--- a/mDNSWindows/Applications/DNSServiceBrowser/Windows/Sources/LoginDialog.cpp
+++ b/mDNSWindows/DNSServiceBrowser/Windows/Sources/LoginDialog.cpp
@@ -3,8 +3,6 @@
  *
  * @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
@@ -25,6 +23,9 @@
     Change History (most recent first):
     
 $Log: LoginDialog.cpp,v $
+Revision 1.1  2004/06/18 04:04:36  rpantos
+Move up one level
+
 Revision 1.2  2004/01/30 02:56:32  bradley
 Updated to support full Unicode display. Added support for all services on www.dns-sd.org.
 
diff --git a/mDNSWindows/Applications/DNSServiceBrowser/Windows/Sources/LoginDialog.h b/mDNSWindows/DNSServiceBrowser/Windows/Sources/LoginDialog.h
similarity index 96%
rename from mDNSWindows/Applications/DNSServiceBrowser/Windows/Sources/LoginDialog.h
rename to mDNSWindows/DNSServiceBrowser/Windows/Sources/LoginDialog.h
index 2b31e6a..caf641a 100644
--- a/mDNSWindows/Applications/DNSServiceBrowser/Windows/Sources/LoginDialog.h
+++ b/mDNSWindows/DNSServiceBrowser/Windows/Sources/LoginDialog.h
@@ -3,8 +3,6 @@
  *
  * @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
@@ -25,6 +23,9 @@
     Change History (most recent first):
     
 $Log: LoginDialog.h,v $
+Revision 1.1  2004/06/18 04:04:36  rpantos
+Move up one level
+
 Revision 1.2  2004/01/30 02:56:32  bradley
 Updated to support full Unicode display. Added support for all services on www.dns-sd.org.
 
diff --git a/mDNSWindows/Applications/DNSServiceBrowser/Windows/Sources/StdAfx.cpp b/mDNSWindows/DNSServiceBrowser/Windows/Sources/StdAfx.cpp
similarity index 86%
rename from mDNSWindows/Applications/DNSServiceBrowser/Windows/Sources/StdAfx.cpp
rename to mDNSWindows/DNSServiceBrowser/Windows/Sources/StdAfx.cpp
index f1932eb..1ccc754 100644
--- a/mDNSWindows/Applications/DNSServiceBrowser/Windows/Sources/StdAfx.cpp
+++ b/mDNSWindows/DNSServiceBrowser/Windows/Sources/StdAfx.cpp
@@ -3,8 +3,6 @@
  *
  * @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
@@ -25,11 +23,17 @@
     Change History (most recent first):
     
 $Log: StdAfx.cpp,v $
+Revision 1.2  2004/07/13 21:24:26  rpantos
+Fix for <rdar://problem/3701120>.
+
+Revision 1.1  2004/06/18 04:04:36  rpantos
+Move up one level
+
 Revision 1.2  2004/01/30 02:56:32  bradley
 Updated to support full Unicode display. Added support for all services on www.dns-sd.org.
 
 Revision 1.1  2003/08/21 02:06:47  bradley
-Moved Rendezvous Browser for non-Windows CE into Windows sub-folder.
+Moved DNSServiceBrowser for non-Windows CE into Windows sub-folder.
 
 Revision 1.4  2003/08/12 19:56:28  cheshire
 Update to APSL 2.0
@@ -41,7 +45,7 @@ Revision 1.2  2002/09/21 20:44:55  zarzycki
 Added APSL info
 
 Revision 1.1  2002/09/20 06:12:53  bradley
-Rendezvous Browser for Windows
+DNSServiceBrowser for Windows
 
 */
 
diff --git a/mDNSWindows/Applications/DNSServiceBrowser/Windows/Sources/StdAfx.h b/mDNSWindows/DNSServiceBrowser/Windows/Sources/StdAfx.h
similarity index 91%
rename from mDNSWindows/Applications/DNSServiceBrowser/Windows/Sources/StdAfx.h
rename to mDNSWindows/DNSServiceBrowser/Windows/Sources/StdAfx.h
index 35fee48..cb8031e 100644
--- a/mDNSWindows/Applications/DNSServiceBrowser/Windows/Sources/StdAfx.h
+++ b/mDNSWindows/DNSServiceBrowser/Windows/Sources/StdAfx.h
@@ -3,8 +3,6 @@
  *
  * @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
@@ -25,6 +23,12 @@
     Change History (most recent first):
     
 $Log: StdAfx.h,v $
+Revision 1.2  2004/07/13 21:24:26  rpantos
+Fix for <rdar://problem/3701120>.
+
+Revision 1.1  2004/06/18 04:04:36  rpantos
+Move up one level
+
 Revision 1.3  2004/01/30 02:56:32  bradley
 Updated to support full Unicode display. Added support for all services on www.dns-sd.org.
 
@@ -32,7 +36,7 @@ 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.
+Moved DNSServiceBrowser for non-Windows CE into Windows sub-folder.
 
 Revision 1.4  2003/08/12 19:56:28  cheshire
 Update to APSL 2.0
@@ -44,7 +48,7 @@ Revision 1.2  2002/09/21 20:44:56  zarzycki
 Added APSL info
 
 Revision 1.1  2002/09/20 06:12:53  bradley
-Rendezvous Browser for Windows
+DNSServiceBrowser for Windows
 
 */
 
diff --git a/mDNSWindows/Applications/DNSServiceBrowser/WindowsCE/Application.vcc b/mDNSWindows/DNSServiceBrowser/WindowsCE/Application.vcc
similarity index 100%
rename from mDNSWindows/Applications/DNSServiceBrowser/WindowsCE/Application.vcc
rename to mDNSWindows/DNSServiceBrowser/WindowsCE/Application.vcc
diff --git a/mDNSWindows/Applications/DNSServiceBrowser/WindowsCE/Application.vcp b/mDNSWindows/DNSServiceBrowser/WindowsCE/Application.vcp
similarity index 100%
rename from mDNSWindows/Applications/DNSServiceBrowser/WindowsCE/Application.vcp
rename to mDNSWindows/DNSServiceBrowser/WindowsCE/Application.vcp
diff --git a/mDNSWindows/Applications/DNSServiceBrowser/WindowsCE/Application.vcw b/mDNSWindows/DNSServiceBrowser/WindowsCE/Application.vcw
similarity index 100%
rename from mDNSWindows/Applications/DNSServiceBrowser/WindowsCE/Application.vcw
rename to mDNSWindows/DNSServiceBrowser/WindowsCE/Application.vcw
diff --git a/mDNSWindows/Applications/DNSServiceBrowser/WindowsCE/Resources/Application.ico b/mDNSWindows/DNSServiceBrowser/WindowsCE/Resources/Application.ico
similarity index 100%
rename from mDNSWindows/Applications/DNSServiceBrowser/WindowsCE/Resources/Application.ico
rename to mDNSWindows/DNSServiceBrowser/WindowsCE/Resources/Application.ico
diff --git a/mDNSWindows/Applications/DNSServiceBrowser/WindowsCE/Resources/Application.rc b/mDNSWindows/DNSServiceBrowser/WindowsCE/Resources/Application.rc
similarity index 96%
rename from mDNSWindows/Applications/DNSServiceBrowser/WindowsCE/Resources/Application.rc
rename to mDNSWindows/DNSServiceBrowser/WindowsCE/Resources/Application.rc
index 71af68d..c153326 100644
--- a/mDNSWindows/Applications/DNSServiceBrowser/WindowsCE/Resources/Application.rc
+++ b/mDNSWindows/DNSServiceBrowser/WindowsCE/Resources/Application.rc
@@ -79,7 +79,7 @@ IDR_MAINFRAME           ICON    DISCARDABLE     "Application.ico"
 IDD_APPLICATION_DIALOG DIALOG DISCARDABLE  0, 0, 139, 153
 STYLE WS_POPUP | WS_VISIBLE | WS_CAPTION
 EXSTYLE WS_EX_APPWINDOW | 0x80000000L
-CAPTION "Rendezvous Browser"
+CAPTION "DNSServiceBrowser"
 FONT 8, "System"
 BEGIN
     CONTROL         "List1",IDC_BROWSE_LIST,"SysListView32",LVS_REPORT | 
@@ -113,14 +113,14 @@ BEGIN
         BEGIN
             VALUE "Comments", "\0"
             VALUE "CompanyName", "Apple Computer, Inc.\0"
-            VALUE "FileDescription", "Rendezvous Browser for Windows CE\0"
+            VALUE "FileDescription", "DNSServiceBrowser for Windows CE\0"
             VALUE "FileVersion", "1, 0, 0, 1\0"
             VALUE "InternalName", "Application\0"
             VALUE "LegalCopyright", "Copyright (C) 2003-2004 Apple Computer, Inc.\0"
             VALUE "LegalTrademarks", "\0"
             VALUE "OriginalFilename", "Application.exe\0"
             VALUE "PrivateBuild", "\0"
-            VALUE "ProductName", "Rendezvous Browser for Windows CE\0"
+            VALUE "ProductName", "DNSServiceBrowser for Windows CE\0"
             VALUE "ProductVersion", "1, 0, 0, 1\0"
             VALUE "SpecialBuild", "\0"
         END
diff --git a/mDNSWindows/Applications/DNSServiceBrowser/WindowsCE/Resources/Application.rc2 b/mDNSWindows/DNSServiceBrowser/WindowsCE/Resources/Application.rc2
similarity index 100%
rename from mDNSWindows/Applications/DNSServiceBrowser/WindowsCE/Resources/Application.rc2
rename to mDNSWindows/DNSServiceBrowser/WindowsCE/Resources/Application.rc2
diff --git a/mDNSWindows/Applications/DNSServiceBrowser/WindowsCE/Resources/newres.h b/mDNSWindows/DNSServiceBrowser/WindowsCE/Resources/newres.h
similarity index 100%
rename from mDNSWindows/Applications/DNSServiceBrowser/WindowsCE/Resources/newres.h
rename to mDNSWindows/DNSServiceBrowser/WindowsCE/Resources/newres.h
diff --git a/mDNSWindows/Applications/DNSServiceBrowser/WindowsCE/Resources/resource.h b/mDNSWindows/DNSServiceBrowser/WindowsCE/Resources/resource.h
similarity index 100%
rename from mDNSWindows/Applications/DNSServiceBrowser/WindowsCE/Resources/resource.h
rename to mDNSWindows/DNSServiceBrowser/WindowsCE/Resources/resource.h
diff --git a/mDNSWindows/Applications/DNSServiceBrowser/WindowsCE/Sources/Application.cpp b/mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/Application.cpp
similarity index 94%
rename from mDNSWindows/Applications/DNSServiceBrowser/WindowsCE/Sources/Application.cpp
rename to mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/Application.cpp
index 9bcde04..39bb529 100644
--- a/mDNSWindows/Applications/DNSServiceBrowser/WindowsCE/Sources/Application.cpp
+++ b/mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/Application.cpp
@@ -3,8 +3,6 @@
  *
  * @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
@@ -25,11 +23,17 @@
     Change History (most recent first):
     
 $Log: Application.cpp,v $
+Revision 1.2  2004/07/13 21:24:27  rpantos
+Fix for <rdar://problem/3701120>.
+
+Revision 1.1  2004/06/18 04:04:37  rpantos
+Move up one level
+
 Revision 1.2  2004/01/30 02:56:33  bradley
 Updated to support full Unicode display. Added support for all services on www.dns-sd.org.
 
 Revision 1.1  2003/08/21 02:16:10  bradley
-Rendezvous Browser for HTTP services for Windows CE/PocketPC.
+DNSServiceBrowser for HTTP services for Windows CE/PocketPC.
 
 */
 
diff --git a/mDNSWindows/Applications/DNSServiceBrowser/WindowsCE/Sources/Application.h b/mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/Application.h
similarity index 92%
rename from mDNSWindows/Applications/DNSServiceBrowser/WindowsCE/Sources/Application.h
rename to mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/Application.h
index 5e5b507..08409b1 100644
--- a/mDNSWindows/Applications/DNSServiceBrowser/WindowsCE/Sources/Application.h
+++ b/mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/Application.h
@@ -3,8 +3,6 @@
  *
  * @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
@@ -25,11 +23,17 @@
     Change History (most recent first):
     
 $Log: Application.h,v $
+Revision 1.2  2004/07/13 21:24:27  rpantos
+Fix for <rdar://problem/3701120>.
+
+Revision 1.1  2004/06/18 04:04:37  rpantos
+Move up one level
+
 Revision 1.2  2004/01/30 02:56:33  bradley
 Updated to support full Unicode display. Added support for all services on www.dns-sd.org.
 
 Revision 1.1  2003/08/21 02:16:10  bradley
-Rendezvous Browser for HTTP services for Windows CE/PocketPC.
+DNSServiceBrowser for HTTP services for Windows CE/PocketPC.
 
 */
 
diff --git a/mDNSWindows/Applications/DNSServiceBrowser/WindowsCE/Sources/BrowserDialog.cpp b/mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/BrowserDialog.cpp
similarity index 98%
rename from mDNSWindows/Applications/DNSServiceBrowser/WindowsCE/Sources/BrowserDialog.cpp
rename to mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/BrowserDialog.cpp
index 63208aa..2bdd05b 100644
--- a/mDNSWindows/Applications/DNSServiceBrowser/WindowsCE/Sources/BrowserDialog.cpp
+++ b/mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/BrowserDialog.cpp
@@ -3,8 +3,6 @@
  *
  * @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
@@ -25,6 +23,12 @@
     Change History (most recent first):
     
 $Log: BrowserDialog.cpp,v $
+Revision 1.2  2004/07/13 21:24:27  rpantos
+Fix for <rdar://problem/3701120>.
+
+Revision 1.1  2004/06/18 04:04:37  rpantos
+Move up one level
+
 Revision 1.5  2004/01/30 02:56:33  bradley
 Updated to support full Unicode display. Added support for all services on www.dns-sd.org.
 
@@ -39,7 +43,7 @@ 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.
+DNSServiceBrowser for HTTP services for Windows CE/PocketPC.
 
 */
 
diff --git a/mDNSWindows/Applications/DNSServiceBrowser/WindowsCE/Sources/BrowserDialog.h b/mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/BrowserDialog.h
similarity index 94%
rename from mDNSWindows/Applications/DNSServiceBrowser/WindowsCE/Sources/BrowserDialog.h
rename to mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/BrowserDialog.h
index e2f56c9..e0a7723 100644
--- a/mDNSWindows/Applications/DNSServiceBrowser/WindowsCE/Sources/BrowserDialog.h
+++ b/mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/BrowserDialog.h
@@ -3,8 +3,6 @@
  *
  * @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
@@ -25,6 +23,12 @@
     Change History (most recent first):
     
 $Log: BrowserDialog.h,v $
+Revision 1.2  2004/07/13 21:24:27  rpantos
+Fix for <rdar://problem/3701120>.
+
+Revision 1.1  2004/06/18 04:04:37  rpantos
+Move up one level
+
 Revision 1.4  2004/01/30 02:56:33  bradley
 Updated to support full Unicode display. Added support for all services on www.dns-sd.org.
 
@@ -36,7 +40,7 @@ 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.
+DNSServiceBrowser for HTTP services for Windows CE/PocketPC.
 
 */
 
diff --git a/mDNSWindows/Applications/DNSServiceBrowser/WindowsCE/Sources/StdAfx.cpp b/mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/StdAfx.cpp
similarity index 86%
rename from mDNSWindows/Applications/DNSServiceBrowser/WindowsCE/Sources/StdAfx.cpp
rename to mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/StdAfx.cpp
index 33ea0a3..919256e 100644
--- a/mDNSWindows/Applications/DNSServiceBrowser/WindowsCE/Sources/StdAfx.cpp
+++ b/mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/StdAfx.cpp
@@ -3,8 +3,6 @@
  *
  * @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
@@ -25,11 +23,17 @@
     Change History (most recent first):
     
 $Log: StdAfx.cpp,v $
+Revision 1.2  2004/07/13 21:24:27  rpantos
+Fix for <rdar://problem/3701120>.
+
+Revision 1.1  2004/06/18 04:04:37  rpantos
+Move up one level
+
 Revision 1.2  2004/01/30 02:56:33  bradley
 Updated to support full Unicode display. Added support for all services on www.dns-sd.org.
 
 Revision 1.1  2003/08/21 02:16:10  bradley
-Rendezvous Browser for HTTP services for Windows CE/PocketPC.
+DNSServiceBrowser for HTTP services for Windows CE/PocketPC.
 
 */
 
diff --git a/mDNSWindows/Applications/DNSServiceBrowser/WindowsCE/Sources/StdAfx.h b/mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/StdAfx.h
similarity index 91%
rename from mDNSWindows/Applications/DNSServiceBrowser/WindowsCE/Sources/StdAfx.h
rename to mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/StdAfx.h
index e3be196..f598c26 100644
--- a/mDNSWindows/Applications/DNSServiceBrowser/WindowsCE/Sources/StdAfx.h
+++ b/mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/StdAfx.h
@@ -3,8 +3,6 @@
  *
  * @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
@@ -25,11 +23,17 @@
     Change History (most recent first):
     
 $Log: StdAfx.h,v $
+Revision 1.2  2004/07/13 21:24:27  rpantos
+Fix for <rdar://problem/3701120>.
+
+Revision 1.1  2004/06/18 04:04:37  rpantos
+Move up one level
+
 Revision 1.2  2004/01/30 02:56:33  bradley
 Updated to support full Unicode display. Added support for all services on www.dns-sd.org.
 
 Revision 1.1  2003/08/21 02:16:10  bradley
-Rendezvous Browser for HTTP services for Windows CE/PocketPC.
+DNSServiceBrowser for HTTP services for Windows CE/PocketPC.
 
 */
 
diff --git a/mDNSWindows/Applications/DNSServiceTest/Tool.c b/mDNSWindows/DNSServiceTest/Tool.c
similarity index 95%
rename from mDNSWindows/Applications/DNSServiceTest/Tool.c
rename to mDNSWindows/DNSServiceTest/Tool.c
index 46e8e0c..258363e 100644
--- a/mDNSWindows/Applications/DNSServiceTest/Tool.c
+++ b/mDNSWindows/DNSServiceTest/Tool.c
@@ -3,8 +3,6 @@
  *
  * @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
@@ -25,6 +23,15 @@
     Change History (most recent first):
 	
 $Log: Tool.c,v $
+Revision 1.3  2004/09/16 01:58:25  cheshire
+Fix compiler warnings
+
+Revision 1.2  2004/07/13 21:24:28  rpantos
+Fix for <rdar://problem/3701120>.
+
+Revision 1.1  2004/06/18 04:07:54  rpantos
+Move up one level
+
 Revision 1.12  2004/04/09 21:03:15  bradley
 Changed port numbers to use network byte order for consistency with other platforms.
 
@@ -44,7 +51,7 @@ Revision 1.7  2003/08/20 07:06:34  bradley
 Update to APSL 2.0. Updated change history to match other mDNSResponder files.
 
 Revision 1.6  2003/08/20 06:50:55  bradley
-Updated to latest internal version of the Rendezvous for Windows code: Re-did everything to support
+Updated to latest internal version of the mDNSCore code: Re-did everything to support
 the latest DNSServices APIs (proxies, record updates, etc.); Added support for testing the platform
 neutral DNSServices-based emulation layer for the Mac OS X DNSServiceDiscovery API.
 
@@ -214,14 +221,14 @@ struct	PresetData
 
 static const PresetData		gPresets[] = 
 {
-	/* 01 */	{ 2, { "rendezvous", "-bbd" } },
-	/* 02 */	{ 4, { "rendezvous", "-bs",  "_airport._tcp", 		"local."  } }, 
-	/* 03 */	{ 4, { "rendezvous", "-bs",  "_xserveraid._tcp", 	"local."  } }, 
-	/* 04 */	{ 3, { "rendezvous", "-rdb", "apple.com" } }, 
-	/* 05 */	{ 7, { "rendezvous", "-rs",  "My Fake AirPort", 	"_airport._tcp", 	"local.", 	"1234", "My Fake Info"  } }, 
-	/* 06 */	{ 7, { "rendezvous", "-rs",  "My Fake Xserve RAID", "_xserveraid._tcp", "local.", 	"1234", "My Fake Info"  } }, 
-	/* 07 */	{ 7, { "rendezvous", "-rs",  "My Fake Web Server", 	"_http._tcp", 		"local.",	"8080", "index.html"  } }, 
-	/* 08 */	{ 9, { "rendezvous", "-rps", "www.apple.com", "17.254.0.91", "Apple Web Server", "_http._tcp", "local.", "80", "index.html"  } }, 
+	/* 01 */	{ 2, { "DNSServiceTest", "-bbd" } },
+	/* 02 */	{ 4, { "DNSServiceTest", "-bs",  "_airport._tcp", 		"local."  } }, 
+	/* 03 */	{ 4, { "DNSServiceTest", "-bs",  "_xserveraid._tcp", 	"local."  } }, 
+	/* 04 */	{ 3, { "DNSServiceTest", "-rdb", "apple.com" } }, 
+	/* 05 */	{ 7, { "DNSServiceTest", "-rs",  "My Fake AirPort", 	"_airport._tcp", 	"local.", 	"1234", "My Fake Info"  } }, 
+	/* 06 */	{ 7, { "DNSServiceTest", "-rs",  "My Fake Xserve RAID", "_xserveraid._tcp", "local.", 	"1234", "My Fake Info"  } }, 
+	/* 07 */	{ 7, { "DNSServiceTest", "-rs",  "My Fake Web Server", 	"_http._tcp", 		"local.",	"8080", "index.html"  } }, 
+	/* 08 */	{ 9, { "DNSServiceTest", "-rps", "www.apple.com", "17.254.0.91", "Apple Web Server", "_http._tcp", "local.", "80", "index.html"  } }, 
 };
 
 const int 					gPresetsCount = sizeof( gPresets ) / sizeof( gPresets[ 0 ] );
@@ -241,7 +248,7 @@ int main( int argc, char* argv[] )
 	// Set up DNS Services and install a Console Control Handler to handle things like control-c signals.
 	
 	err = DNSServicesInitialize( kDNSFlagAdvertise, 0 );
-	require_noerr_string( err, exit, "could not initialize Rendezvous" );
+	require_noerr_string( err, exit, "could not initialize DNSServiceTest" );
 
 #if( __MACH__ )
 	signal( SIGINT, SigIntHandler );
@@ -265,7 +272,7 @@ exit:
 static void	Usage( void )
 {
 	fprintf( stderr, "\n" );
-	fprintf( stderr, "rendezvous - Rendezvous Tool 1.0d1\n" );
+	fprintf( stderr, "DNSServiceTest - DNS-SD Test Tool 1.0d1\n" );
 	fprintf( stderr, "\n" );
 	fprintf( stderr, "  -bbd                                                    'b'rowse for 'b'rowsing 'd'omains\n" );
 	fprintf( stderr, "  -brd                                                    'b'rowse for 'r'egistration 'd'omains\n" );
@@ -285,13 +292,13 @@ static void	Usage( void )
 	fprintf( stderr, "  -h[elp]                                                 'h'elp\n" );
 	fprintf( stderr, "\n" );
 	
-	fprintf( stderr, "  -1 Preset 1 (browse for browsing domains)    rendezvous -bbd\n" );
-	fprintf( stderr, "  -2 Preset 2 (browse for AirPort)             rendezvous -bs \"_airport._tcp\" \"local.\"\n" );
-	fprintf( stderr, "  -3 Preset 3 (browse for Xserve RAID)         rendezvous -bs \"_xserveraid._tcp\" \"local.\"\n" );
-	fprintf( stderr, "  -4 Preset 4 (register apple.com domain)      rendezvous -rdb \"apple.com\"\n" );
-	fprintf( stderr, "  -5 Preset 5 (register fake AirPort)          rendezvous -rs \"My Fake AirPort\" \"_airport._tcp\" \"local.\" 1234 \"My Fake Info\"\n" );
-	fprintf( stderr, "  -6 Preset 6 (register fake Xserve RAID)      rendezvous -rs \"My Fake Xserve RAID\" \"_xserveraid._tcp\" \"local.\" 1234 \"My Fake Info\"\n" );	
-	fprintf( stderr, "  -7 Preset 7 (register fake web server)       rendezvous -rs \"My Fake Web Server\" \"_http._tcp\" \"local.\" 8080 \"index.html\"\n" );
+	fprintf( stderr, "  -1 Preset 1 (browse for browsing domains)    DNSServiceTest -bbd\n" );
+	fprintf( stderr, "  -2 Preset 2 (browse for AirPort)             DNSServiceTest -bs \"_airport._tcp\" \"local.\"\n" );
+	fprintf( stderr, "  -3 Preset 3 (browse for Xserve RAID)         DNSServiceTest -bs \"_xserveraid._tcp\" \"local.\"\n" );
+	fprintf( stderr, "  -4 Preset 4 (register apple.com domain)      DNSServiceTest -rdb \"apple.com\"\n" );
+	fprintf( stderr, "  -5 Preset 5 (register fake AirPort)          DNSServiceTest -rs \"My Fake AirPort\" \"_airport._tcp\" \"local.\" 1234 \"My Fake Info\"\n" );
+	fprintf( stderr, "  -6 Preset 6 (register fake Xserve RAID)      DNSServiceTest -rs \"My Fake Xserve RAID\" \"_xserveraid._tcp\" \"local.\" 1234 \"My Fake Info\"\n" );	
+	fprintf( stderr, "  -7 Preset 7 (register fake web server)       DNSServiceTest -rs \"My Fake Web Server\" \"_http._tcp\" \"local.\" 8080 \"index.html\"\n" );
 	fprintf( stderr, "\n" );
 }
 
@@ -734,28 +741,28 @@ static void BrowserCallBack( void *inContext, DNSBrowserRef inRef, DNSStatus inS
 			break;
 			
 		case kDNSBrowserEventTypeAddDomain:			
-			fprintf( stdout, "domain         \"%s\" added on interface 0x%08X (%s)\n", 
+			fprintf( stdout, "domain         \"%s\" added on interface 0x%p (%s)\n", 
 					 inEvent->data.addDomain.domain, 
 					 (int) inEvent->data.addDomain.interfaceID, 
 					 IPv4ToString( inEvent->data.addDomain.interfaceIP.u.ipv4.addr, ifIP ) );
 			break;
 		
 		case kDNSBrowserEventTypeAddDefaultDomain:
-			fprintf( stdout, "default domain \"%s\" added on interface 0x%08X (%s)\n", 
+			fprintf( stdout, "default domain \"%s\" added on interface 0x%p (%s)\n", 
 					 inEvent->data.addDefaultDomain.domain, 
 					 (int) inEvent->data.addDefaultDomain.interfaceID, 
 					 IPv4ToString( inEvent->data.addDefaultDomain.interfaceIP.u.ipv4.addr, ifIP ) );
 			break;
 		
 		case kDNSBrowserEventTypeRemoveDomain:
-			fprintf( stdout, "domain         \"%s\" removed on interface 0x%08X (%s)\n", 
+			fprintf( stdout, "domain         \"%s\" removed on interface 0x%p (%s)\n", 
 					 inEvent->data.removeDomain.domain, 
 					 (int) inEvent->data.removeDomain.interfaceID, 
 					 IPv4ToString( inEvent->data.removeDomain.interfaceIP.u.ipv4.addr, ifIP ) );
 			break;
 		
 		case kDNSBrowserEventTypeAddService:
-			fprintf( stdout, "service        \"%s.%s%s\" added on interface 0x%08X (%s)\n", 
+			fprintf( stdout, "service        \"%s.%s%s\" added on interface 0x%p (%s)\n", 
 					 inEvent->data.addService.name, 
 					 inEvent->data.addService.type, 
 					 inEvent->data.addService.domain, 
@@ -764,7 +771,7 @@ static void BrowserCallBack( void *inContext, DNSBrowserRef inRef, DNSStatus inS
 			break;
 		
 		case kDNSBrowserEventTypeRemoveService:
-			fprintf( stdout, "service        \"%s.%s%s\" removed on interface 0x%08X (%s)\n", 
+			fprintf( stdout, "service        \"%s.%s%s\" removed on interface 0x%p (%s)\n", 
 					 inEvent->data.removeService.name, 
 					 inEvent->data.removeService.type, 
 					 inEvent->data.removeService.domain, 
@@ -778,7 +785,7 @@ static void BrowserCallBack( void *inContext, DNSBrowserRef inRef, DNSStatus inS
 			const uint8_t *		end;
 			int					i;
 			
-			fprintf( stdout, "resolved       \"%s.%s%s\" to \"%s\" (%s:%u) on interface 0x%08X (%s)%s\n", 
+			fprintf( stdout, "resolved       \"%s.%s%s\" to \"%s\" (%s:%u) on interface 0x%p (%s)%s\n", 
 					 inEvent->data.resolved->name, 
 					 inEvent->data.resolved->type, 
 					 inEvent->data.resolved->domain, 
@@ -841,7 +848,7 @@ static void ResolverCallBack( void *inContext, DNSResolverRef inRef, DNSStatus i
 			const uint8_t *		end;
 			int					i;
 			
-			fprintf( stdout, "resolved       \"%s.%s%s\" to \"%s\" (%s:%u) on interface 0x%08X (%s)%s\n", 
+			fprintf( stdout, "resolved       \"%s.%s%s\" to \"%s\" (%s:%u) on interface 0x%p (%s)%s\n", 
 					 inEvent->data.resolved.name, 
 					 inEvent->data.resolved.type, 
 					 inEvent->data.resolved.domain, 
diff --git a/mDNSWindows/Applications/DNSServiceTest/ToolPrefixWindows.h b/mDNSWindows/DNSServiceTest/ToolPrefixWindows.h
similarity index 95%
rename from mDNSWindows/Applications/DNSServiceTest/ToolPrefixWindows.h
rename to mDNSWindows/DNSServiceTest/ToolPrefixWindows.h
index 901df49..6469748 100644
--- a/mDNSWindows/Applications/DNSServiceTest/ToolPrefixWindows.h
+++ b/mDNSWindows/DNSServiceTest/ToolPrefixWindows.h
@@ -3,8 +3,6 @@
  *
  * @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
@@ -25,6 +23,9 @@
     Change History (most recent first):
 
 $Log: ToolPrefixWindows.h,v $
+Revision 1.1  2004/06/18 04:07:54  rpantos
+Move up one level
+
 Revision 1.3  2004/01/30 03:04:32  bradley
 Updated for latest changes to mDNSWindows.
 
diff --git a/mDNSWindows/Applications/DNSServiceTest/ToolPrefixWindowsDebug.h b/mDNSWindows/DNSServiceTest/ToolPrefixWindowsDebug.h
similarity index 95%
rename from mDNSWindows/Applications/DNSServiceTest/ToolPrefixWindowsDebug.h
rename to mDNSWindows/DNSServiceTest/ToolPrefixWindowsDebug.h
index 5858503..7b73d2e 100644
--- a/mDNSWindows/Applications/DNSServiceTest/ToolPrefixWindowsDebug.h
+++ b/mDNSWindows/DNSServiceTest/ToolPrefixWindowsDebug.h
@@ -3,8 +3,6 @@
  *
  * @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
@@ -25,6 +23,9 @@
     Change History (most recent first):
     
 $Log: ToolPrefixWindowsDebug.h,v $
+Revision 1.1  2004/06/18 04:07:54  rpantos
+Move up one level
+
 Revision 1.3  2004/01/30 03:04:32  bradley
 Updated for latest changes to mDNSWindows.
 
diff --git a/mDNSWindows/DNSServiceTest/ToolWin32.mcp b/mDNSWindows/DNSServiceTest/ToolWin32.mcp
new file mode 100644
index 0000000000000000000000000000000000000000..d82908187345ba50f8548396924784023a3dddb9
GIT binary patch
literal 127071
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
X$h<bUAN4c`C+vq^+vetah$Z|#r;YST

literal 0
HcmV?d00001

diff --git a/mDNSWindows/Applications/DNSServiceTest/ToolWin32VS2002.sln b/mDNSWindows/DNSServiceTest/ToolWin32VS2002.sln
similarity index 100%
rename from mDNSWindows/Applications/DNSServiceTest/ToolWin32VS2002.sln
rename to mDNSWindows/DNSServiceTest/ToolWin32VS2002.sln
diff --git a/mDNSWindows/Applications/DNSServiceTest/ToolWin32VS2002.vcproj b/mDNSWindows/DNSServiceTest/ToolWin32VS2002.vcproj
similarity index 99%
rename from mDNSWindows/Applications/DNSServiceTest/ToolWin32VS2002.vcproj
rename to mDNSWindows/DNSServiceTest/ToolWin32VS2002.vcproj
index cddc5a2..c6adefb 100644
--- a/mDNSWindows/Applications/DNSServiceTest/ToolWin32VS2002.vcproj
+++ b/mDNSWindows/DNSServiceTest/ToolWin32VS2002.vcproj
@@ -117,7 +117,7 @@
 	</Configurations>
 	<Files>
 		<Filter
-			Name="Rendezvous"
+			Name="DNSServiceTest"
 			Filter="">
 			<File
 				RelativePath="..\..\..\mDNSCore\DNSCommon.c">
diff --git a/mDNSWindows/Applications/DNSServiceTest/ToolWin32VS2003.sln b/mDNSWindows/DNSServiceTest/ToolWin32VS2003.sln
similarity index 100%
rename from mDNSWindows/Applications/DNSServiceTest/ToolWin32VS2003.sln
rename to mDNSWindows/DNSServiceTest/ToolWin32VS2003.sln
diff --git a/mDNSWindows/Applications/DNSServiceTest/ToolWin32VS2003.vcproj b/mDNSWindows/DNSServiceTest/ToolWin32VS2003.vcproj
similarity index 99%
rename from mDNSWindows/Applications/DNSServiceTest/ToolWin32VS2003.vcproj
rename to mDNSWindows/DNSServiceTest/ToolWin32VS2003.vcproj
index c0ed0ee..7393437 100644
--- a/mDNSWindows/Applications/DNSServiceTest/ToolWin32VS2003.vcproj
+++ b/mDNSWindows/DNSServiceTest/ToolWin32VS2003.vcproj
@@ -131,7 +131,7 @@
 	</References>
 	<Files>
 		<Filter
-			Name="Rendezvous"
+			Name="DNSServiceTest"
 			Filter="">
 			<File
 				RelativePath="..\..\..\mDNSCore\DNSCommon.c">
diff --git a/mDNSWindows/DNSServices/DNSServiceDiscovery.c b/mDNSWindows/DNSServices/DNSServiceDiscovery.c
index e8d5e2e..94e2d02 100644
--- a/mDNSWindows/DNSServices/DNSServiceDiscovery.c
+++ b/mDNSWindows/DNSServices/DNSServiceDiscovery.c
@@ -3,8 +3,6 @@
  *
  * @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
@@ -25,6 +23,12 @@
     Change History (most recent first):
 
 $Log: DNSServiceDiscovery.c,v $
+Revision 1.8  2004/09/17 01:08:58  cheshire
+Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
+  The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
+  declared in that file are ONLY appropriate to single-address-space embedded applications.
+  For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
+
 Revision 1.7  2004/05/08 12:24:48  bradley
 Removed trailing character from zero value to fix compile error.
 
@@ -38,7 +42,7 @@ Updated to support full Unicode display. Added support for all services on www.d
 
 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.
+Best solution is just to combine mDNSEmbeddedAPI.h and mDNSPlatformFunctions.h into a single file.
 
 Revision 1.3  2003/10/04 04:47:08  bradley
 Changed DNSServiceRegistrationCreate to treat the port in network byte order for end-to-end consistency.
@@ -74,7 +78,7 @@ Platform-neutral DNSServices-based emulation layer for the Mac OS X DNSServiceDi
 	
 #endif
 
-#include	"mDNSClientAPI.h"
+#include	"mDNSEmbeddedAPI.h"
 #include	"DNSServices.h"
 
 #include	"DNSServiceDiscovery.h"
diff --git a/mDNSWindows/DNSServices/DNSServiceDiscovery.h b/mDNSWindows/DNSServices/DNSServiceDiscovery.h
index eae6d47..084b0b8 100644
--- a/mDNSWindows/DNSServices/DNSServiceDiscovery.h
+++ b/mDNSWindows/DNSServices/DNSServiceDiscovery.h
@@ -3,8 +3,6 @@
  *
  * @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/DNSServices/DNSServices.c b/mDNSWindows/DNSServices/DNSServices.c
index 79a3258..a8aedb3 100755
--- a/mDNSWindows/DNSServices/DNSServices.c
+++ b/mDNSWindows/DNSServices/DNSServices.c
@@ -3,8 +3,6 @@
  *
  * @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
@@ -25,6 +23,26 @@
     Change History (most recent first):
     
 $Log: DNSServices.c,v $
+Revision 1.31  2004/10/19 21:33:23  cheshire
+<rdar://problem/3844991> Cannot resolve non-local registrations using the mach API
+Added flag 'kDNSServiceFlagsForceMulticast'. Passing through an interface id for a unicast name
+doesn't force multicast unless you set this flag to indicate explicitly that this is what you want
+
+Revision 1.30  2004/09/17 01:08:58  cheshire
+Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
+  The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
+  declared in that file are ONLY appropriate to single-address-space embedded applications.
+  For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
+
+Revision 1.29  2004/09/17 00:31:53  cheshire
+For consistency with ipv6, renamed rdata field 'ip' to 'ipv4'
+
+Revision 1.28  2004/09/16 01:58:25  cheshire
+Fix compiler warnings
+
+Revision 1.27  2004/07/13 21:24:28  rpantos
+Fix for <rdar://problem/3701120>.
+
 Revision 1.26  2004/06/05 00:04:27  cheshire
 <rdar://problem/3668639>: wide-area domains should be returned in reg. domain enumeration
 
@@ -49,10 +67,10 @@ Fix code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1005) instead of 2
 
 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.
+Best solution is just to combine mDNSEmbeddedAPI.h and mDNSPlatformFunctions.h into a single file.
 
 Revision 1.18  2003/11/14 19:18:34  cheshire
-Move AssignDomainName macro to mDNSClientAPI.h to that client layers can use it too
+Move AssignDomainName macro to mDNSEmbeddedAPI.h to that client layers can use it too
 
 Revision 1.17  2003/10/31 12:16:03  bradley
 Added support for providing the resolved host name to the callback.
@@ -61,7 +79,7 @@ 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
+Updated to latest internal version of the mDNSCore code: Added support for interface
 specific registrations; Added support for no-such-service registrations; Added support for host
 name registrations; Added support for host proxy and service proxy registrations; Added support for
 registration record updates (e.g. TXT record updates); Added support for using either a single C
@@ -138,7 +156,7 @@ DNS Services for Windows
 	#include	<CoreServices/CoreServices.h>
 #endif
 
-#include	"mDNSClientAPI.h"
+#include	"mDNSEmbeddedAPI.h"
 
 #include	"DNSServices.h"
 
@@ -871,7 +889,7 @@ DNSStatus
 	MakeDomainNameFromDNSNameString( &type, inType );
 	MakeDomainNameFromDNSNameString( &domain, inDomain );
 	
-	err = mDNS_StartBrowse( gMDNSPtr, &inRef->serviceBrowseQuestion, &type, &domain, mDNSInterface_Any, 
+	err = mDNS_StartBrowse( gMDNSPtr, &inRef->serviceBrowseQuestion, &type, &domain, mDNSInterface_Any, mDNSfalse,
 							DNSBrowserPrivateCallBack, inRef );
 	require_noerr( err, exit );
 	
@@ -1123,11 +1141,11 @@ mDNSlocal void
 			break;
 		
 		case kDNSResolverEventTypeRelease:
-			verbosedebugf( DEBUG_NAME "private resolver callback: release (ref=0x%08X)", inRef );
+			verbosedebugf( DEBUG_NAME "private resolver callback: release (ref=0x%p)", inRef );
 			break;
 		
 		default:
-			verbosedebugf( DEBUG_NAME "private resolver callback: unknown event (ref=0x%08X, event=%ld)", inRef, inEvent->type );
+			verbosedebugf( DEBUG_NAME "private resolver callback: unknown event (ref=0x%p, event=%ld)", inRef, inEvent->type );
 			break;
 	}
 
@@ -2417,7 +2435,7 @@ DNSStatus
 	mDNS_snprintf( buffer, sizeof( buffer ), "%d.%d.%d.%d.in-addr.arpa.", ip.b[ 3 ], ip.b[ 2 ], ip.b[ 1 ], ip.b[ 0 ] );
 	MakeDomainNameFromDNSNameString( &object->RR_PTR.resrec.name, buffer );
 	
-	object->RR_A.resrec.rdata->u.ip = ip;
+	object->RR_A.resrec.rdata->u.ipv4 = ip;
 	AssignDomainName( object->RR_PTR.resrec.rdata->u.name, object->RR_A.resrec.name );
 	
 	// Add the object to the list.
diff --git a/mDNSWindows/DNSServices/DNSServices.h b/mDNSWindows/DNSServices/DNSServices.h
index bbf48b1..8e16a8c 100755
--- a/mDNSWindows/DNSServices/DNSServices.h
+++ b/mDNSWindows/DNSServices/DNSServices.h
@@ -3,8 +3,6 @@
  *
  * @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
@@ -25,6 +23,9 @@
     Change History (most recent first):
     
 $Log: DNSServices.h,v $
+Revision 1.11  2004/07/13 21:24:28  rpantos
+Fix for <rdar://problem/3701120>.
+
 Revision 1.10  2004/01/30 02:56:34  bradley
 Updated to support full Unicode display. Added support for all services on www.dns-sd.org.
 
@@ -32,7 +33,7 @@ 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
+Updated to latest internal version of the mDNSCore code: Added support for interface
 specific registrations; Added support for no-such-service registrations; Added support for host
 name registrations; Added support for host proxy and service proxy registrations; Added support for
 registration record updates (e.g. TXT record updates); Added support for using either a single C
@@ -1322,7 +1323,7 @@ DNSStatus
 //---------------------------------------------------------------------------------------------------------------------------
 /*!	@function	DNSNoSuchServiceRegistrationCreate
 
-	@abstract	Creates a registration object and publish the registration to assert non-existance of a particular service.
+	@abstract	Creates a registration object and publish the registration to assert non-existence of a particular service.
 
 	@param		inFlags
 					Flags to control the registration process.
diff --git a/mDNSWindows/DebugServices.c b/mDNSWindows/DebugServices.c
index 7742b59..7562c2e 100644
--- a/mDNSWindows/DebugServices.c
+++ b/mDNSWindows/DebugServices.c
@@ -3,8 +3,6 @@
  *
  * @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
@@ -25,6 +23,12 @@
     Change History (most recent first):
     
 $Log: DebugServices.c,v $
+Revision 1.5  2004/09/17 01:08:57  cheshire
+Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
+  The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
+  declared in that file are ONLY appropriate to single-address-space embedded applications.
+  For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
+
 Revision 1.4  2004/04/15 08:59:08  bradley
 Removed deprecated debug and log levels and replaced them with modern equivalents.
 
@@ -82,10 +86,10 @@ Debugging support for various platforms.
 	#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 MDNS_DEBUGMSGS is defined (even if defined 0), it is aware of mDNS and it is probably safe to include mDNSEmbeddedAPI.h.
 
 #if( defined( MDNS_DEBUGMSGS ) )
-	#include	"mDNSClientAPI.h"
+	#include	"mDNSEmbeddedAPI.h"
 #endif
 
 #if 0
@@ -1178,8 +1182,8 @@ static pascal void
 //	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.
+//	Changed types to standard C types since mDNSEmbeddedAPI.h may not be available.
+//	Conditionalized mDNS stuff so it can be used with or with mDNSEmbeddedAPI.h.
 //	Added 64-bit support for %d (%lld), %i (%lli), %u (%llu), %o (%llo), %x (%llx), and %b (%llb).
 //	Added %@   - Cocoa/CoreFoundation object. Param is the object. Strings are used directly. Others use CFCopyDescription.
 //	Added %.8a - FIbre Channel address. Arg=ptr to address.
@@ -1391,7 +1395,7 @@ DEBUG_EXPORT size_t DebugSNPrintFVAList(char *sbuffer, size_t buflen, const char
 											default:                F.precision =  0; break;
 											}
 									#else
-										F.precision = 0;	// mDNSClientAPI.h not included so no mDNSAddr support
+										F.precision = 0;	// mDNSEmbeddedAPI.h not included so no mDNSAddr support
 									#endif
 									}
 								else if (F.altForm == 2)
diff --git a/mDNSWindows/DebugServices.h b/mDNSWindows/DebugServices.h
index fd914ee..e687406 100644
--- a/mDNSWindows/DebugServices.h
+++ b/mDNSWindows/DebugServices.h
@@ -3,8 +3,6 @@
  *
  * @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/Installer.vct b/mDNSWindows/Installer.vct
deleted file mode 100644
index c31317d785551748d31e184eb5b2c6e6330568f4..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 40028
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
a8`m#iyUJzHny56S%2bP5qco}b^Zx)F5s_8^

diff --git a/mDNSWindows/Installer/Main.ism b/mDNSWindows/Installer/Main.ism
new file mode 100644
index 0000000000000000000000000000000000000000..c430d40b181fea53399446cfeca72269dcf155d7
GIT binary patch
literal 195584
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
bUl7Ks6Wsc(;r;mgjnMzy%sCT<y!QVA%hRhK

literal 0
HcmV?d00001

diff --git a/mDNSWindows/Installer/SDK.ism b/mDNSWindows/Installer/SDK.ism
new file mode 100644
index 0000000000000000000000000000000000000000..e63bde7651cd92e6b254ab8d2d56b53ed9d46b06
GIT binary patch
literal 189952
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
VT60_CF#bQ+@weTaGriDv{y*Lex~%{J

literal 0
HcmV?d00001

diff --git a/mDNSWindows/Applications/SystemService/Service.rc b/mDNSWindows/Java/jdns_sd.rc
similarity index 51%
rename from mDNSWindows/Applications/SystemService/Service.rc
rename to mDNSWindows/Java/jdns_sd.rc
index 833a410..42511a3 100644
--- a/mDNSWindows/Applications/SystemService/Service.rc
+++ b/mDNSWindows/Java/jdns_sd.rc
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -21,29 +21,26 @@
  * @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.
 
-*/
+$Log: jdns_sd.rc,v $
+Revision 1.3  2004/10/19 03:41:42  shersche
+<rdar://problem/3843396> Include "afxres.h" to resource script so it gets compiled correctly
+Bug #: 3843396
 
-#ifdef RC_INVOKED
-	#ifndef _INC_WINDOWS
-	#define _INC_WINDOWS
-		#include	"winres.h"
-	#endif
-#endif
+Revision 1.2  2004/06/26 21:27:38  rpantos
+Update to use WinVersRes.h
 
-#include	"Resource.h"
+Revision 1.1  2004/06/26 20:06:51  rpantos
+Update to use WinVersRes.h
 
-/////////////////////////////////////////////////////////////////////////////
-//
-// Messages
-//
 
-LANGUAGE 0x9,0x1
-1 11 EventLogMessages.bin
+*/
+
+#ifndef JDNS_SD_RC
+#define JDNS_SD_RC
+
+#include "afxres.h"
+#include "../WinVersRes.h"
 
 /////////////////////////////////////////////////////////////////////////////
 //
@@ -51,16 +48,16 @@ LANGUAGE 0x9,0x1
 //
 
 VS_VERSION_INFO VERSIONINFO
- FILEVERSION 1,0,0,1
- PRODUCTVERSION 1,0,0,1
- FILEFLAGSMASK 0x3fL
+ FILEVERSION MASTER_PROD_VERS
+ PRODUCTVERSION MASTER_PROD_VERS
+ FILEFLAGSMASK 0x17L
 #ifdef _DEBUG
  FILEFLAGS 0x1L
 #else
  FILEFLAGS 0x0L
 #endif
  FILEOS 0x4L
- FILETYPE 0x1L
+ FILETYPE 0x2L
  FILESUBTYPE 0x0L
 BEGIN
     BLOCK "StringFileInfo"
@@ -68,13 +65,13 @@ 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"
+            VALUE "FileDescription", MASTER_PROD_NAME " support for Java"
+            VALUE "FileVersion", MASTER_PROD_VERS_STR
+            VALUE "InternalName", "jdns_sd"
+            VALUE "LegalCopyright", "Copyright (C) 2004"
+            VALUE "OriginalFilename", "jdns_sd.dll"
+            VALUE "ProductName", MASTER_PROD_NAME
+            VALUE "ProductVersion", MASTER_PROD_VERS_STR
         END
     END
     BLOCK "VarFileInfo"
@@ -83,12 +80,4 @@ BEGIN
     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
+#endif // JDNS_SD_RC
diff --git a/mDNSWindows/Applications/Java/makefile b/mDNSWindows/Java/makefile
old mode 100755
new mode 100644
similarity index 87%
rename from mDNSWindows/Applications/Java/makefile
rename to mDNSWindows/Java/makefile
index 3ed3f9f..d787410
--- a/mDNSWindows/Applications/Java/makefile
+++ b/mDNSWindows/Java/makefile
@@ -20,6 +20,15 @@
 # @APPLE_LICENSE_HEADER_END@
 #
 # $Log: makefile,v $
+# Revision 1.3  2004/11/23 08:13:07  shersche
+# Link to the iphlpapi.lib for GetAdaptersInfo
+#
+# Revision 1.2  2004/06/26 20:07:06  rpantos
+# Update to use WinVersRes.h
+#
+# Revision 1.1  2004/06/18 04:12:05  rpantos
+# Move up one level. Integration changes for Scott.
+#
 # Revision 1.2  2004/05/01 00:31:41  rpantos
 # Change line endings for CVS.
 #
@@ -38,17 +47,18 @@
 # 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
+# The default location of the JDK is \javasdk. You can override this on the
 # command line (e.g. 'nmake JDK=\j2dk1.4.2_03').
 
 ############################################################################
 
-COREDIR = ..\..\..\mDNSCore
-SHAREDDIR = ..\..\..\mDNSShared
+COREDIR = ..\..\mDNSCore
+SHAREDDIR = ..\..\mDNSShared
 
-JDK = d:\javasdk
+JDK = \javasdk
 
 CC = cl
+RC = rc
 LD = ld
 CP = copy
 RM = del /Q
@@ -56,7 +66,7 @@ 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..\.. \
+CFLAGS_COMMON = -LD -DAUTO_CALLBACKS=0 -I. -I..\.. \
 	-I$(COREDIR) -I$(SHAREDDIR) -I$(JDK)\include -I$(JDK)\include\win32
 
 # Set up diverging paths for debug vs. prod builds
@@ -116,9 +126,9 @@ JARCONTENTS =	$(OBJDIR)\com\apple\dnssd\DNSSDService.class \
 $(BUILDDIR)\dns_sd.jar: $(JARCONTENTS)
 	$(JAR) -cf $@ -C $(OBJDIR) com
 
-$(BUILDDIR)\jdns_sd.dll: $(JAVASRC)\JNISupport.c $(OBJDIR)\DNSSD.java.h
+$(BUILDDIR)\jdns_sd.dll: $(JAVASRC)\JNISupport.c $(OBJDIR)\DNSSD.java.h $(OBJDIR)\jdns_sd.RES
 	$(CC) -Fe$@ $(JAVASRC)\JNISupport.c $(CFLAGS) -I$(OBJDIR) \
-	$(LIBDIR)\DNSSD.lib $(JDK)\lib\jvm.lib
+	$(LIBDIR)\DNSSD.lib $(JDK)\lib\jvm.lib ws2_32.lib iphlpapi.lib $(OBJDIR)\jdns_sd.RES
 
 .SUFFIXES : .java
 {$(JAVASRC)}.java{$(OBJDIR)\com\apple\dnssd}.class:	
@@ -132,3 +142,6 @@ $(OBJDIR)\DNSSD.java.h: $(OBJDIR)\com\apple\dnssd\DNSSD.class
 		com.apple.dnssd.AppleQuery \
 		com.apple.dnssd.AppleService 
 
+$(OBJDIR)\jdns_sd.RES: jdns_sd.rc
+	$(RC) /fo $@ $?
+
diff --git a/mDNSWindows/NSPTool/NSPTool.aps b/mDNSWindows/NSPTool/NSPTool.aps
new file mode 100644
index 0000000000000000000000000000000000000000..313f3068be307b091c0a6b3a1dd5f2283676d674
GIT binary patch
literal 34296
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
HG*|s!hkI>$

literal 0
HcmV?d00001

diff --git a/mDNSWindows/Applications/NSPTool/Tool.c b/mDNSWindows/NSPTool/NSPTool.c
similarity index 94%
rename from mDNSWindows/Applications/NSPTool/Tool.c
rename to mDNSWindows/NSPTool/NSPTool.c
index bee72f8..3648655 100644
--- a/mDNSWindows/Applications/NSPTool/Tool.c
+++ b/mDNSWindows/NSPTool/NSPTool.c
@@ -3,8 +3,6 @@
  *
  * @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
@@ -24,7 +22,18 @@
 
     Change History (most recent first):
 	
-$Log: Tool.c,v $
+$Log: NSPTool.c,v $
+Revision 1.3  2004/08/26 04:46:49  shersche
+Add -q switch for silent operation
+
+Revision 1.2  2004/06/23 16:39:14  shersche
+Fix extraneous warnings regarding implict casts
+
+Submitted by: Scott Herscher (sherscher@apple.com)
+
+Revision 1.1  2004/06/18 04:14:26  rpantos
+Move up one level.
+
 Revision 1.1  2004/01/30 03:02:58  bradley
 NameSpace Provider Tool for installing, removing, list, etc. NameSpace Providers.
 
@@ -43,7 +52,7 @@ NameSpace Provider Tool for installing, removing, list, etc. NameSpace Providers
 //	Prototypes
 //===========================================================================================================================
 
-int 					main( int argc, char *argv[] );
+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 );
@@ -56,6 +65,8 @@ DEBUG_LOCAL WCHAR *		CharToWCharString( const char *inCharString, WCHAR *outWCha
 DEBUG_LOCAL char *		GUIDtoString( const GUID *inGUID, char *outString );
 DEBUG_LOCAL OSStatus	StringToGUID( const char *inCharString, GUID *outGUID );
 
+DEBUG_LOCAL BOOL gToolQuietMode = FALSE;
+
 //===========================================================================================================================
 //	main
 //===========================================================================================================================
@@ -101,6 +112,7 @@ DEBUG_LOCAL void	Usage( void )
 	
 	fprintf( stderr, "  -list                           - Lists Name Space Providers\n" );	
 	fprintf( stderr, "  -reorder                        - Reorders Name Space Providers\n" );
+	fprintf( stderr, "  -q                              - Enable quiet mode\n" );
 	fprintf( stderr, "  -h[elp]                         - Help\n" );
 	fprintf( stderr, "\n" );
 }
@@ -206,6 +218,10 @@ DEBUG_LOCAL int ProcessArgs( int argc, char* argv[] )
 			err = ReorderNameSpaces();
 			require_noerr( err, exit );
 		}
+		else if( strcmp( argv[ i ], "-q" ) == 0 )
+		{
+			gToolQuietMode = TRUE;
+		}
 		else if( ( strcmp( argv[ i ], "-help" ) == 0 ) || 
 				 ( strcmp( argv[ i ], "-h" ) == 0 ) )
 		{
@@ -270,7 +286,10 @@ OSStatus	InstallNSP( const char *inName, const char *inGUID, const char *inPath
 	WSACleanup();
 	require_noerr( err, exit );
 	
-	fprintf( stderr, "Installed NSP \"%s\" (%s) at %s\n", inName, inGUID, inPath );
+	if (!gToolQuietMode)
+	{
+		fprintf( stderr, "Installed NSP \"%s\" (%s) at %s\n", inName, inGUID, inPath );
+	}
 	
 exit:
 	if( err != kNoErr )
@@ -304,7 +323,10 @@ DEBUG_LOCAL OSStatus	RemoveNSP( const char *inGUID )
 	WSACleanup();
 	require_noerr( err, exit );
 	
-	fprintf( stderr, "Removed NSP %s\n", inGUID );
+	if (!gToolQuietMode)
+	{
+		fprintf( stderr, "Removed NSP %s\n", inGUID );
+	}
 		
 exit:
 	if( err != kNoErr )
@@ -338,7 +360,10 @@ DEBUG_LOCAL OSStatus	EnableNSP( const char *inGUID, BOOL inEnable )
 	WSACleanup();
 	require_noerr( err, exit );
 	
-	fprintf( stderr, "Removed NSP %s\n", inGUID );
+	if (!gToolQuietMode)
+	{
+		fprintf( stderr, "Removed NSP %s\n", inGUID );
+	}
 		
 exit:
 	if( err != kNoErr )
@@ -465,11 +490,11 @@ DEBUG_LOCAL OSStatus	ReorderNameSpaces( void )
 	
 	// Uninstall it then re-install it to move it to the end.
 	
-	size = strlen( array[ i ].lpszIdentifier );
+	size = (DWORD) strlen( array[ i ].lpszIdentifier );
 	require_action( size < sizeof_array( name ), exit, err = kSizeErr );
 	CharToWCharString( array[ i ].lpszIdentifier, name );
 	
-	size = strlen( "%SystemRoot%\\System32\\mswsock.dll" );
+	size = (DWORD) strlen( "%SystemRoot%\\System32\\mswsock.dll" );
 	require_action( size < sizeof_array( path ), exit, err = kSizeErr );
 	CharToWCharString( "%SystemRoot%\\System32\\mswsock.dll", path );
 	
diff --git a/mDNSWindows/NSPTool/NSPTool.rc b/mDNSWindows/NSPTool/NSPTool.rc
new file mode 100644
index 0000000..b75f621
--- /dev/null
+++ b/mDNSWindows/NSPTool/NSPTool.rc
@@ -0,0 +1,102 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE 
+BEGIN
+    "resource.h\0"
+END
+
+2 TEXTINCLUDE 
+BEGIN
+    "#include ""afxres.h""\r\n"
+    "\0"
+END
+
+3 TEXTINCLUDE 
+BEGIN
+    "\r\n"
+    "\0"
+END
+
+#endif    // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 1,0,0,5
+ PRODUCTVERSION 1,0,0,5
+ FILEFLAGSMASK 0x17L
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x1L
+ FILESUBTYPE 0x0L
+BEGIN
+    BLOCK "StringFileInfo"
+    BEGIN
+        BLOCK "040904b0"
+        BEGIN
+            VALUE "CompanyName", "Apple Computer, Inc."
+            VALUE "FileDescription", "NSPTool Application"
+            VALUE "FileVersion", "1, 0, 0, 5"
+            VALUE "InternalName", "NSPTool"
+            VALUE "LegalCopyright", "Copyright (C) 2004"
+            VALUE "OriginalFilename", "NSPTool.exe"
+            VALUE "ProductName", " NSPTool Application"
+            VALUE "ProductVersion", "1, 0, 0, 5"
+        END
+    END
+    BLOCK "VarFileInfo"
+    BEGIN
+        VALUE "Translation", 0x409, 1200
+    END
+END
+
+#endif    // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif    // not APSTUDIO_INVOKED
+
diff --git a/mDNSWindows/Applications/DLL/dnssd.vcproj b/mDNSWindows/NSPTool/NSPTool.vcproj
similarity index 50%
rename from mDNSWindows/Applications/DLL/dnssd.vcproj
rename to mDNSWindows/NSPTool/NSPTool.vcproj
index ad7c1d1..89ca1fb 100644
--- a/mDNSWindows/Applications/DLL/dnssd.vcproj
+++ b/mDNSWindows/NSPTool/NSPTool.vcproj
@@ -1,156 +1,143 @@
-<?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>
+<?xml version="1.0" encoding = "Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="7.00"
+	Name="NSPTool"
+	ProjectGUID="{208B3A9F-1CA0-4D1D-9D6C-C61616F94705}"
+	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=".;.."
+				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;WIN32_LEAN_AND_MEAN"
+				StringPooling="TRUE"
+				MinimalRebuild="TRUE"
+				ExceptionHandling="FALSE"
+				BasicRuntimeChecks="3"
+				SmallerTypeCheck="TRUE"
+				RuntimeLibrary="1"
+				BufferSecurityCheck="TRUE"
+				EnableFunctionLevelLinking="FALSE"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				Detect64BitPortabilityProblems="TRUE"
+				DebugInformationFormat="4"
+				CallingConvention="0"/>
+			<Tool
+				Name="VCCustomBuildTool"/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="ws2_32.lib iphlpapi.lib"
+				OutputFile="$(OutDir)/NSPTool.exe"
+				LinkIncremental="2"
+				GenerateDebugInformation="TRUE"
+				ProgramDatabaseFile="$(OutDir)/NSPTool.pdb"
+				SubSystem="1"
+				TargetMachine="1"/>
+			<Tool
+				Name="VCMIDLTool"/>
+			<Tool
+				Name="VCPostBuildEventTool"/>
+			<Tool
+				Name="VCPreBuildEventTool"/>
+			<Tool
+				Name="VCPreLinkEventTool"/>
+			<Tool
+				Name="VCResourceCompilerTool"/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"/>
+			<Tool
+				Name="VCWebDeploymentTool"/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="Release"
+			IntermediateDirectory="Release"
+			ConfigurationType="1"
+			CharacterSet="2">
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories=".;.."
+				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;WIN32_LEAN_AND_MEAN"
+				RuntimeLibrary="0"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				Detect64BitPortabilityProblems="TRUE"
+				DebugInformationFormat="3"/>
+			<Tool
+				Name="VCCustomBuildTool"/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="ws2_32.lib iphlpapi.lib"
+				OutputFile="$(OutDir)/NSPTool.exe"
+				LinkIncremental="1"
+				GenerateDebugInformation="TRUE"
+				SubSystem="1"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				TargetMachine="1"/>
+			<Tool
+				Name="VCMIDLTool"/>
+			<Tool
+				Name="VCPostBuildEventTool"/>
+			<Tool
+				Name="VCPreBuildEventTool"/>
+			<Tool
+				Name="VCPreLinkEventTool"/>
+			<Tool
+				Name="VCResourceCompilerTool"/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"/>
+			<Tool
+				Name="VCWebDeploymentTool"/>
+		</Configuration>
+	</Configurations>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
+			<File
+				RelativePath="..\DebugServices.c">
+			</File>
+			<File
+				RelativePath=".\NSPTool.c">
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
+			<File
+				RelativePath="..\CommonServices.h">
+			</File>
+			<File
+				RelativePath="..\DebugServices.h">
+			</File>
+			<File
+				RelativePath=".\resource.h">
+			</File>
+		</Filter>
+		<Filter
+			Name="Resource Files"
+			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
+			UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">
+			<File
+				RelativePath=".\NSPTool.rc">
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
diff --git a/mDNSWindows/Applications/NSPTool/Prefix.h b/mDNSWindows/NSPTool/Prefix.h
similarity index 94%
rename from mDNSWindows/Applications/NSPTool/Prefix.h
rename to mDNSWindows/NSPTool/Prefix.h
index c7f01c5..af06d92 100644
--- a/mDNSWindows/Applications/NSPTool/Prefix.h
+++ b/mDNSWindows/NSPTool/Prefix.h
@@ -3,8 +3,6 @@
  *
  * @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
@@ -25,6 +23,9 @@
     Change History (most recent first):
 
 $Log: Prefix.h,v $
+Revision 1.1  2004/06/18 04:14:26  rpantos
+Move up one level.
+
 Revision 1.1  2004/01/30 03:02:58  bradley
 NameSpace Provider Tool for installing, removing, list, etc. NameSpace Providers.
 					
diff --git a/mDNSWindows/NSPTool/resource.h b/mDNSWindows/NSPTool/resource.h
new file mode 100644
index 0000000..78c1d91
--- /dev/null
+++ b/mDNSWindows/NSPTool/resource.h
@@ -0,0 +1,27 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by NSPTool.rc
+//
+#define IDS_PROJNAME                    100
+#define IDR_WMDMLOGGER                  101
+#define IDS_LOG_SEV_INFO                201
+#define IDS_LOG_SEV_WARN                202
+#define IDS_LOG_SEV_ERROR               203
+#define IDS_LOG_DATETIME                204
+#define IDS_LOG_SRCNAME                 205
+#define IDS_DEF_LOGFILE                 301
+#define IDS_DEF_MAXSIZE                 302
+#define IDS_DEF_SHRINKTOSIZE            303
+#define IDS_DEF_LOGENABLED              304
+#define IDS_MUTEX_TIMEOUT               401
+
+// Next default values for new objects
+// 
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE        201
+#define _APS_NEXT_COMMAND_VALUE         32768
+#define _APS_NEXT_CONTROL_VALUE         201
+#define _APS_NEXT_SYMED_VALUE           101
+#endif
+#endif
diff --git a/mDNSWindows/README.txt b/mDNSWindows/README.txt
index 5a7b375..8d8ab4b 100644
--- a/mDNSWindows/README.txt
+++ b/mDNSWindows/README.txt
@@ -54,8 +54,8 @@ Tool.c is an example client that uses the services of mDNS Core.
 
 ToolWin32.mcp is a CodeWarrior project (CodeWarrior for Windows version 8). 
 ToolWin32.vcproj is a Visual Studio .NET 7 project. These projects build 
-Tool.c to make rendezvous.exe, a small Windows command-line tool to do all 
-the standard Rendezvous stuff on Windows. It has the following features:
+Tool.c to make DNSServiceTest.exe, a small Windows command-line tool to do all 
+the standard DNS-SD stuff on Windows. It has the following features:
 
 - Browse for browsing and/or registration domains.
 - Browse for services.
@@ -67,11 +67,11 @@ For example, if you have a Windows machine running a Web server,
 then you can make it advertise that it is offering HTTP on port 80
 with the following command:
 
-rendezvous -rs "Windows Web Server" "_http._tcp." "local." 80 ""
+DNSServiceTest -rs "Windows Web Server" "_http._tcp." "local." 80 ""
 
 To search for AFP servers, use this:
 
-rendezvous -bs "_afpovertcp._tcp." "local."
+DNSServiceTest -bs "_afpovertcp._tcp." "local."
 
 You can also do multiple things at once (e.g. register a service and
 browse for it so one instance of the app can be used for testing).
@@ -79,7 +79,7 @@ Multiple instances can also be run on the same machine to discover each
 other. There is a -help command to show all the commands, their
 parameters, and some examples of using it.
 
-RendezvousBrowser contains the source code for a graphical browser application 
+DNSServiceBrowser contains the source code for a graphical browser application 
 for Windows CE/PocketPC. The Windows CE/PocketPC version requires Microsoft 
 eMbedded C++ 4.0 with SP2 installed and the PocketPC 2003 SDK.
 
diff --git a/mDNSWindows/RMxClient.c b/mDNSWindows/RMxClient.c
deleted file mode 100644
index 540d4ef..0000000
--- a/mDNSWindows/RMxClient.c
+++ /dev/null
@@ -1,1302 +0,0 @@
-/*
- * 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
deleted file mode 100644
index 798f9e9..0000000
--- a/mDNSWindows/RMxClient.h
+++ /dev/null
@@ -1,307 +0,0 @@
-/*
- * 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
deleted file mode 100644
index 686ee93..0000000
--- a/mDNSWindows/RMxCommon.c
+++ /dev/null
@@ -1,1501 +0,0 @@
-/*
- * 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
deleted file mode 100644
index a28da74..0000000
--- a/mDNSWindows/RMxCommon.h
+++ /dev/null
@@ -1,662 +0,0 @@
-/*
- * 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
deleted file mode 100644
index 3c28089..0000000
--- a/mDNSWindows/RMxServer.c
+++ /dev/null
@@ -1,1656 +0,0 @@
-/*
- * 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
deleted file mode 100644
index 4b0fb3a..0000000
--- a/mDNSWindows/RMxServer.h
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * 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__
diff --git a/mDNSWindows/Applications/SystemService/EventLogMessages.bin b/mDNSWindows/SystemService/EventLogMessages.bin
similarity index 100%
rename from mDNSWindows/Applications/SystemService/EventLogMessages.bin
rename to mDNSWindows/SystemService/EventLogMessages.bin
diff --git a/mDNSWindows/SystemService/Firewall.cpp b/mDNSWindows/SystemService/Firewall.cpp
new file mode 100755
index 0000000..15eb7f8
--- /dev/null
+++ b/mDNSWindows/SystemService/Firewall.cpp
@@ -0,0 +1,330 @@
+/*
+ * 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: Firewall.cpp,v $
+Revision 1.2  2004/09/15 09:39:53  shersche
+Retry the method INetFwPolicy::get_CurrentProfile on error
+
+Revision 1.1  2004/09/13 07:32:31  shersche
+Wrapper for Windows Firewall API code
+
+
+*/
+
+#define _WIN32_DCOM 
+
+#include "Firewall.h"
+#include <windows.h>
+#include <crtdbg.h>
+#include <netfw.h>
+#include <objbase.h>
+#include <oleauto.h>
+
+
+static const int kMaxTries			= 30;
+static const int kRetrySleepPeriod	= 1 * 1000; // 1 second
+
+
+static OSStatus
+mDNSFirewallInitialize(OUT INetFwProfile ** fwProfile)
+{
+	INetFwMgr		*	fwMgr		= NULL;
+	INetFwPolicy	*	fwPolicy	= NULL;
+	int					numRetries	= 0;
+	HRESULT				err			= kNoErr;
+    
+	_ASSERT(fwProfile != NULL);
+
+    *fwProfile = NULL;
+
+	// Use COM to get a reference to the firewall settings manager.  This
+	// call will fail on anything other than XP SP2
+
+	err = CoCreateInstance( __uuidof(NetFwMgr), NULL, CLSCTX_INPROC_SERVER, __uuidof(INetFwMgr), (void**)&fwMgr );
+	require(SUCCEEDED(err), exit);
+
+	// Use the reference to get the local firewall policy
+
+	err = fwMgr->get_LocalPolicy(&fwPolicy);
+	require(SUCCEEDED(err), exit);
+
+	// Use the reference to get the extant profile. Empirical evidence
+	// suggests that there is the potential for a race condition when a system
+	// service whose startup type is automatic calls this method.
+	// This is true even when the service declares itself to be dependent
+	// on the firewall service. Re-trying the method will succeed within
+	// a few seconds.
+
+	do
+	{
+    	err = fwPolicy->get_CurrentProfile(fwProfile);
+
+		if (err)
+		{
+			Sleep(kRetrySleepPeriod);
+		}
+	}
+	while (err && (numRetries++ < kMaxTries));
+
+	require(SUCCEEDED(err), exit);
+
+	err = kNoErr;
+
+exit:
+
+	// Release temporary COM objects
+
+    if (fwPolicy != NULL)
+    {
+        fwPolicy->Release();
+    }
+
+    if (fwMgr != NULL)
+    {
+        fwMgr->Release();
+    }
+
+    return err;
+}
+
+
+static void
+mDNSFirewallCleanup
+			(
+			IN INetFwProfile	*	fwProfile
+			)
+{
+	// Call Release on the COM reference.
+
+    if (fwProfile != NULL)
+    {
+        fwProfile->Release();
+    }
+}
+
+
+static OSStatus
+mDNSFirewallAppIsEnabled
+			(
+			IN INetFwProfile	*	fwProfile,
+			IN const wchar_t	*	fwProcessImageFileName,
+			OUT BOOL			*	fwAppEnabled    
+			)
+{
+	BSTR							fwBstrProcessImageFileName = NULL;
+	VARIANT_BOOL					fwEnabled;
+	INetFwAuthorizedApplication	*	fwApp	= NULL;
+	INetFwAuthorizedApplications*	fwApps	= NULL;
+	OSStatus						err		= kNoErr;
+    
+	_ASSERT(fwProfile != NULL);
+	_ASSERT(fwProcessImageFileName != NULL);
+	_ASSERT(fwAppEnabled != NULL);
+
+    *fwAppEnabled = FALSE;
+
+	// Get the list of authorized applications
+
+	err = fwProfile->get_AuthorizedApplications(&fwApps);
+	require(SUCCEEDED(err), exit);
+
+    fwBstrProcessImageFileName = SysAllocString(fwProcessImageFileName);
+	require_action(SysStringLen(fwBstrProcessImageFileName) > 0, exit, err = kNoMemoryErr);
+
+	// Look for us
+
+    err = fwApps->Item(fwBstrProcessImageFileName, &fwApp);
+	
+    if (SUCCEEDED(err))
+    {
+        // It's listed, but is it enabled?
+
+		err = fwApp->get_Enabled(&fwEnabled);
+		require(SUCCEEDED(err), exit);
+
+        if (fwEnabled != VARIANT_FALSE)
+        {
+			// Yes, it's enabled
+
+            *fwAppEnabled = TRUE;
+		}
+	}
+
+	err = kNoErr;
+
+exit:
+
+	// Deallocate the BSTR
+
+    SysFreeString(fwBstrProcessImageFileName);
+
+	// Release the COM objects
+
+    if (fwApp != NULL)
+    {
+        fwApp->Release();
+    }
+
+    if (fwApps != NULL)
+    {
+        fwApps->Release();
+    }
+
+    return err;
+}
+
+
+static OSStatus
+mDNSFirewallAddApp
+			(
+            IN INetFwProfile	*	fwProfile,
+            IN const wchar_t	*	fwProcessImageFileName,
+            IN const wchar_t	*	fwName
+            )
+{
+	BOOL							fwAppEnabled;
+	BSTR							fwBstrName = NULL;
+	BSTR							fwBstrProcessImageFileName = NULL;
+	INetFwAuthorizedApplication	*	fwApp = NULL;
+	INetFwAuthorizedApplications*	fwApps = NULL;
+	OSStatus						err = S_OK;
+    
+	_ASSERT(fwProfile != NULL);
+    _ASSERT(fwProcessImageFileName != NULL);
+    _ASSERT(fwName != NULL);
+
+    // First check to see if the application is already authorized.
+	err = mDNSFirewallAppIsEnabled( fwProfile, fwProcessImageFileName, &fwAppEnabled );
+	require_noerr(err, exit);
+
+	// Only add the application if it isn't enabled
+
+	if (!fwAppEnabled)
+	{
+		// Get the list of authorized applications
+
+        err = fwProfile->get_AuthorizedApplications(&fwApps);
+		require(SUCCEEDED(err), exit);
+
+        // Create an instance of an authorized application.
+
+		err = CoCreateInstance( __uuidof(NetFwAuthorizedApplication), NULL, CLSCTX_INPROC_SERVER, __uuidof(INetFwAuthorizedApplication), (void**)&fwApp );
+		require(SUCCEEDED(err), exit);
+
+        fwBstrProcessImageFileName = SysAllocString(fwProcessImageFileName);
+		require_action(SysStringLen(fwBstrProcessImageFileName) > 0, exit, err = kNoMemoryErr);
+
+		// Set the executable file name
+
+		err = fwApp->put_ProcessImageFileName(fwBstrProcessImageFileName);
+		require(SUCCEEDED(err), exit);
+
+		fwBstrName = SysAllocString(fwName);
+		require_action(SysStringLen(fwBstrName) > 0, exit, err = kNoMemoryErr);
+
+		// Set the friendly name
+
+        err = fwApp->put_Name(fwBstrName);
+		require(SUCCEEDED(err), exit);
+
+		// Now add the application
+
+        err = fwApps->Add(fwApp);
+		require(SUCCEEDED(err), exit);
+	}
+
+	err = kNoErr;
+
+exit:
+
+	// Deallocate the BSTR objects
+
+    SysFreeString(fwBstrName);
+    SysFreeString(fwBstrProcessImageFileName);
+
+    // Release the COM objects
+
+    if (fwApp != NULL)
+    {
+        fwApp->Release();
+    }
+
+    if (fwApps != NULL)
+    {
+        fwApps->Release();
+    }
+
+    return err;
+}
+
+
+OSStatus
+mDNSAddToFirewall
+		(
+		LPWSTR	executable,
+		LPWSTR	name
+		)
+{
+	INetFwProfile	*	fwProfile	= NULL;
+	HRESULT				comInit		= E_FAIL;
+	OSStatus			err			= kNoErr;
+
+	// Initialize COM.
+
+	comInit = CoInitializeEx( 0, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE );
+
+	// Ignore this case. RPC_E_CHANGED_MODE means that COM has already been
+	// initialized with a different mode.
+
+	if (comInit != RPC_E_CHANGED_MODE)
+	{
+		err = comInit;
+		require(SUCCEEDED(err), exit);
+	}
+
+	// Connect to the firewall
+
+	err = mDNSFirewallInitialize(&fwProfile);
+	require_noerr(err, exit);
+
+	// Add us to the list of exempt programs
+
+	err = mDNSFirewallAddApp( fwProfile, executable, name );
+	require_noerr(err, exit);
+
+exit:
+
+	// Disconnect from the firewall
+
+	mDNSFirewallCleanup(fwProfile);
+
+	// De-initialize COM
+
+	if (SUCCEEDED(comInit))
+    {
+        CoUninitialize();
+    }
+
+	return err;
+}
diff --git a/mDNSWindows/SystemService/Firewall.h b/mDNSWindows/SystemService/Firewall.h
new file mode 100755
index 0000000..ac2dfad
--- /dev/null
+++ b/mDNSWindows/SystemService/Firewall.h
@@ -0,0 +1,59 @@
+/*
+ * 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: Firewall.h,v $
+Revision 1.1  2004/09/13 07:32:31  shersche
+Wrapper for Windows Firewall API code
+
+
+*/
+
+#ifndef _Firewall_h
+#define _Firewall_h
+
+
+#include "CommonServices.h"
+#include "DebugServices.h"
+
+
+#if defined(__cplusplus)
+extern "C"
+{
+#endif
+
+
+OSStatus
+mDNSAddToFirewall
+		(
+		LPWSTR	executable,
+		LPWSTR	name
+		);
+
+
+#if defined(__cplusplus)
+}
+#endif
+
+
+#endif
diff --git a/mDNSWindows/Applications/SystemService/Prefix.h b/mDNSWindows/SystemService/Prefix.h
similarity index 95%
rename from mDNSWindows/Applications/SystemService/Prefix.h
rename to mDNSWindows/SystemService/Prefix.h
index 844b96e..59d18e8 100644
--- a/mDNSWindows/Applications/SystemService/Prefix.h
+++ b/mDNSWindows/SystemService/Prefix.h
@@ -3,8 +3,6 @@
  *
  * @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
@@ -25,6 +23,9 @@
     Change History (most recent first):
     
 $Log: Prefix.h,v $
+Revision 1.1  2004/06/18 04:16:41  rpantos
+Move up one level.
+
 Revision 1.2  2004/04/30 02:40:23  bradley
 Define DNS_SD_CLIENT_ENABLED=0 so DNSSD.c can be included without linking the client IPC code.
 
diff --git a/mDNSWindows/SystemService/Service.aps b/mDNSWindows/SystemService/Service.aps
new file mode 100644
index 0000000000000000000000000000000000000000..41f25562d4a630c130f960887f21e59e4da28ead
GIT binary patch
literal 3388
zcmbtW&u`mQ9RHeiV`Yq0li-HrjUHBsW=`8}P>@h+yQ?9!D?80rDN@L6x3!kUk)5pc
z!ih6~0e=Dq4jkc*IPpJlLE?bKffFKpzVF3}9XFi@iR|~@_kDkUzTfZjBO+4qjK}i9
zwD8-(Y8B5OJt3Zt$I4`Xd1*4C;0BSu-3pTPAoicPdWP+}VLFKWL70fulc*oWXKBkj
zPlsX83zHX-AGRiACGlAi)E4dhB-Cp(vvWsK?obk@@hI`b$|*}(hS&B?w`u8S+b})d
zwGJAVV^dYr=o(SGcHp&b^J$~)nx1p$f~#4pADY;&(wq5x-Pzx-*~VmhOVhw`v&djK
zT&F&jhk>{9``*#MnTfOZTSS@5XHg$s3x}1a*KV4w2Ory(z3WhwZj)jedfRK%8kSD?
z)~jo@Mv9Q-_pite|Ng{N#OP;1&tp`52z~Pw{$Fz5h0*c20SGNyuOAwKPMDpiZd^#+
zoKhdsBQejv79}spGhIAq^ZXEf4Td5v_fZ!_+RChU{sRQLGSjzP2T6RAbb9J;)D6?t
ze&i={8XphUW|WRPUDX?of+$uiw%JfOG;Ooh^dGf4!*1``Z$*8-I|{=4(;|Rxk4rwU
zPknxkoyYIOT+ZbozeED^OCT>H{|K6k_*6=^R?tVzXUHse=F0~}1#|^0dd=3&I&CnU
zWz=>Yw?Uh7;hGKih_>XydTcwcNe|@e$n@Zf5V0Lpftcxa$1~{zx!5!72lSzwFK%b-
zD|GepmIiLKmY?s)!lv$&+Ieojd>()y*Qx6QE?T`pq+(}0UcrOl@XPn)>Xj`}n&eR%
zZ<AciEON-k+QNGmbN>Cf^v6HqAVic)f+ELH#GC|8YM&4=e1&3Bpl?VCMbxJgXp5*z
zAvE{tm}2mJE_gKLMgzt?KEs>nQ+gY+I(T|Cpbq%Y;Y|mtP#CCzIuN?lDc1;=LfCpA
z5wiuKDuUO*QK(F98{kQ?$36`p5y3`Z@b$=m4G$PF$3V~np^>ZgMovdlP}7`jRan(>
zZ^o7AV_}=Uk-qg2LpK-6Wj4R0b=a)K)`^f}GzP$dJwKsSXe1GPk*3l;P}hLL29VUy
z0_&667HF@6Tb&Po<X_t346^T84tXWBu{eebeE$MZhQk4L#T3v8_z!a^5Hu~uep_H)
zl%3DOBK!^5R#4d;Sk643RUe-{T+I#aa*d^kuT!Xr<)!bIaD_l!GM7nD@#enJk(WdG
zY=VAKU*!&HdgrC`@>I?D<$IHZS-qQ`%y)0T0X=Bvm-xaQ#U5wDztEg2=;QG<Jg+lL
z;Tt3fc>RuuIJ3`0Z>5kq71#xICdLpH?ui$uK_4S?FmeIL6uCVHdNa-x97%z92p*Q;
zUgh4FX!{tu_@86X2c1s`uJIA1+2Rmhgy3d<UFef`nJ?Q@F%O097&6a=4e3<}zOh7t
z-AHK2WFpX1bQIfQ&3s~nqJudS$;JMu@Iywz(Xy{>HxSy`Td949gXEU-@x)>oi8IJ^
zT(Q7HN^|@pXy;fYx+$zB0vE=rk6lKJvF2z;@Lq)mj)UXuL1$n1#b@rUlI1y=<v2fn
zugrgcvoAbRHrs&!_t9ndY&02tTi_|*k@=4J3;1Sw%6CM*FZ~9?GoJE&iSH-hpv-4H
z<@*WWE3TupXFTP51%DfZtBb#l-1k3Rf3?2nUjO@28HsAX*STZ&mM^nY?rHAlE@T$<
F^S_5#Uikn3

literal 0
HcmV?d00001

diff --git a/mDNSWindows/SystemService/Service.c b/mDNSWindows/SystemService/Service.c
new file mode 100644
index 0000000..ecc5307
--- /dev/null
+++ b/mDNSWindows/SystemService/Service.c
@@ -0,0 +1,1892 @@
+/*
+ * 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.c,v $
+Revision 1.22  2004/12/10 13:18:40  cheshire
+Create no-op function RecordUpdatedNiceLabel(), required by uds_daemon.c
+
+Revision 1.21  2004/11/10 04:03:41  shersche
+Remove SharedAccess dependency.  This causes problems on XP SP1, and isn't necessary for XP SP2 because we already are dependent on WMI, which itself is dependent on SharedAccess.
+
+Revision 1.20  2004/10/14 21:44:05  shersche
+<rdar://problem/3838237> Fix a race condition between the socket thread and the main processing thread that resulted in the socket thread accessing a previously deleted Win32EventSource object.
+Bug #: 3838237
+
+Revision 1.19  2004/10/12 17:59:55  shersche
+<rdar://problem/3718122> Disable routing table modifications when Nortel VPN adapter is active
+Bug #: 3718122
+
+Revision 1.18  2004/10/11 21:57:50  shersche
+<rdar://problem/3832450> The SharedAccess service dependency causes a circular dependency on Windows Server 2003.  Only add the SharedAccess service dependency if running on XP.  All other platforms do not manipulate the firewall and thus are not dependent on it.
+Bug #: 3832450
+
+Revision 1.17  2004/09/17 01:08:58  cheshire
+Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
+  The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
+  declared in that file are ONLY appropriate to single-address-space embedded applications.
+  For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
+
+Revision 1.16  2004/09/16 18:49:34  shersche
+Remove the XP SP2 check before attempting to manage the firewall. There is a race condition in the SP2 updater such that upon first reboot after the upgrade, mDNSResponder might not know that it is running under SP2 yet.  This necessitates a second reboot before the firewall is managed.  Removing the check will cause mDNSResponder to try and manage the firewall everytime it boots up, if and only if it hasn't managed the firewall a previous time.
+
+Revision 1.15  2004/09/15 17:13:33  shersche
+Change Firewall name from "Apple mDNSResponder" to "Rendezvous"
+
+Revision 1.14  2004/09/15 09:37:25  shersche
+Add SharedAccess to dependency list, call CheckFirewall after sending status back to SCM
+
+Revision 1.13  2004/09/13 07:35:10  shersche
+<rdar://problem/3762235> Add mDNSResponder to Windows Firewall application list if SP2 is detected and app hasn't been added before
+Bug #: 3762235
+
+Revision 1.12  2004/09/11 21:18:32  shersche
+<rdar://problem/3779502> Add route to ARP everything when a 169.254.x.x address is selected
+Bug #: 3779502
+
+Revision 1.11  2004/09/11 05:39:19  shersche
+<rdar://problem/3780203> Detect power managment state changes, calling mDNSCoreMachineSleep(m, true) on sleep, and mDNSCoreMachineSleep(m, false) on resume
+Bug #: 3780203
+
+Revision 1.10  2004/08/16 21:45:24  shersche
+Use the full pathname of executable when calling CreateService()
+Submitted by: prepin@zetron.com
+
+Revision 1.9  2004/08/11 01:59:41  cheshire
+Remove "mDNS *globalInstance" parameter from udsserver_init()
+
+Revision 1.8  2004/08/05 05:40:05  shersche
+<rdar://problem/3751566> Only invoke SetConsoleCtrlHandler when running directly from command line.
+<rdar://problem/3751481> Invoke udsserver_handle_configchange() when the computer description changes
+Bug #: 3751481, 3751566
+
+Revision 1.7  2004/07/26 05:35:07  shersche
+ignore non-enet interfaces when setting up link-local routing
+
+Revision 1.6  2004/07/20 06:48:26  shersche
+<rdar://problem/3718122> Allow registry entries to dictate whether to manage link local routing
+Bug #: 3718122
+
+Revision 1.5  2004/07/09 19:08:07  shersche
+<rdar://problem/3713762> ServiceSetupEventLogging() errors are handled gracefully
+Bug #: 3713762
+
+Revision 1.4  2004/06/24 20:58:15  shersche
+Fix compiler error in Release build
+Submitted by: herscher
+
+Revision 1.3  2004/06/24 15:28:53  shersche
+Automatically setup routes to link-local addresses upon interface list change events.
+Submitted by: herscher
+
+Revision 1.2  2004/06/23 16:56:00  shersche
+<rdar://problem/3697326> locked call to udsserver_idle().
+Bug #: 3697326
+Submitted by: herscher
+
+Revision 1.1  2004/06/18 04:16:41  rpantos
+Move up one level.
+
+Revision 1.1  2004/01/30 02:58:39  bradley
+mDNSResponder Windows Service. Provides global Rendezvous support with an IPC interface.
+
+*/
+
+#include	<stdio.h>
+#include	<stdlib.h>
+
+
+#include	"CommonServices.h"
+#include	"DebugServices.h"
+
+#include	"uds_daemon.h"
+#include	"GenLinkedList.h"
+
+#include	"Resource.h"
+
+#include	"mDNSEmbeddedAPI.h"
+#include	"mDNSWin32.h"
+
+#include	"Firewall.h"
+
+#if( !TARGET_OS_WINDOWS_CE )
+	#include	<mswsock.h>
+	#include	<process.h>
+	#include	<ipExport.h>
+	#include	<iphlpapi.h>
+	#include	<iptypes.h>
+#endif
+
+#if 0
+#pragma mark == Constants ==
+#endif
+
+//===========================================================================================================================
+//	Constants
+//===========================================================================================================================
+
+#define	DEBUG_NAME					"[Server] "
+#define	kServiceName				"Apple mDNSResponder"
+#define kServiceFirewallName		L"Rendezvous"
+#define	kServiceDependencies		"Tcpip\0winmgmt\0\0"
+#define kServiceManageLLRouting		"ManageLLRouting"
+#define kServiceCacheEntryCount		"CacheEntryCount"
+#define kServiceManageFirewall		"ManageFirewall"
+#define	kDNSServiceCacheEntryCountDefault	512
+
+#define RR_CACHE_SIZE 500
+static CacheRecord gRRCache[RR_CACHE_SIZE];
+#if 0
+#pragma mark == Structures ==
+#endif
+
+//===========================================================================================================================
+//	Structures
+//===========================================================================================================================
+//---------------------------------------------------------------------------------------------------------------------------
+/*!	@typedef	EventSourceFlags
+
+	@abstract	Session flags.
+	
+	@constant	EventSourceFlagsNone			No flags.
+	@constant	EventSourceFlagsThreadDone		Thread is no longer active.
+	@constant	EventSourceFlagsNoClose			Do not close the session when the thread exits.
+	@constant	EventSourceFinalized			Finalize has been called for this session
+*/
+
+typedef uint32_t		EventSourceFlags;
+
+#define	EventSourceFlagsNone			0
+#define	EventSourceFlagsThreadDone		( 1 << 2 )
+#define	EventSourceFlagsNoClose			( 1 << 3 )
+#define EventSourceFinalized			( 1 << 4 )
+
+
+typedef struct Win32EventSource
+{
+	EventSourceFlags			flags;
+	HANDLE						threadHandle;
+	unsigned					threadID;
+	HANDLE						socketEvent;
+	HANDLE						closeEvent;
+	udsEventCallback			callback;
+	void					*	context;
+	DWORD						waitCount;
+	HANDLE						waitList[2];
+	SOCKET						sock;
+	struct Win32EventSource	*	next;
+} Win32EventSource;
+
+
+#if 0
+#pragma mark == Prototypes ==
+#endif
+
+//===========================================================================================================================
+//	Prototypes
+//===========================================================================================================================
+
+int __cdecl 		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		SetServiceParameters();
+static OSStatus		GetServiceParameters();
+static OSStatus		CheckFirewall();
+static OSStatus		SetServiceInfo( 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 DWORD WINAPI	ServiceControlHandler( DWORD inControl, DWORD inEventType, LPVOID inEventData, LPVOID inContext );
+
+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[] );
+static mStatus		EventSourceFinalize(Win32EventSource * source);
+static void			EventSourceLock();
+static void			EventSourceUnlock();
+static mDNSs32		udsIdle(mDNS * const inMDNS, mDNSs32 interval);
+static void			CoreCallback(mDNS * const inMDNS, mStatus result);
+static void			HostDescriptionChanged(mDNS * const inMDNS);
+static OSStatus		GetRouteDestination(DWORD * ifIndex, DWORD * address);
+static bool			HaveLLRoute(PMIB_IPFORWARDROW rowExtant);
+static OSStatus		SetLLRoute();
+
+#define kLLNetworkAddr      "169.254.0.0"
+#define kLLNetworkAddrMask  "255.255.0.0"
+
+
+#include	"mDNSEmbeddedAPI.h"
+
+#if 0
+#pragma mark == Globals ==
+#endif
+
+//===========================================================================================================================
+//	Globals
+//===========================================================================================================================
+#define gMDNSRecord mDNSStorage
+DEBUG_LOCAL	mDNS_PlatformSupport		gPlatformStorage;
+DEBUG_LOCAL BOOL						gServiceQuietMode		= FALSE;
+DEBUG_LOCAL SERVICE_TABLE_ENTRY			gServiceDispatchTable[] = 
+{
+	{ kServiceName,	ServiceMain }, 
+	{ NULL, 		NULL }
+};
+DEBUG_LOCAL SERVICE_STATUS				gServiceStatus;
+DEBUG_LOCAL SERVICE_STATUS_HANDLE		gServiceStatusHandle 	= NULL;
+DEBUG_LOCAL HANDLE						gServiceEventSource		= NULL;
+DEBUG_LOCAL bool						gServiceAllowRemote		= false;
+DEBUG_LOCAL int							gServiceCacheEntryCount	= 0;	// 0 means to use the DNS-SD default.
+DEBUG_LOCAL bool						gServiceManageLLRouting = true;
+DEBUG_LOCAL int							gWaitCount				= 0;
+DEBUG_LOCAL HANDLE					*	gWaitList				= NULL;
+DEBUG_LOCAL HANDLE						gStopEvent				= NULL;
+DEBUG_LOCAL CRITICAL_SECTION			gEventSourceLock;
+DEBUG_LOCAL GenLinkedList				gEventSources;
+
+
+#if 0
+#pragma mark -
+#endif
+
+//===========================================================================================================================
+//	main
+//===========================================================================================================================
+
+int	__cdecl main( int argc, char *argv[] )
+{
+	OSStatus		err;
+	BOOL			ok;
+	BOOL			start;
+	int				i;
+	
+	debug_initialize( kDebugOutputTypeMetaConsole );
+	debug_set_property( kDebugPropertyTagPrintLevel, kDebugLevelVerbose );
+	
+	// Default to automatically starting the service dispatcher if no extra arguments are specified.
+	
+	start = ( argc <= 1 );
+	
+	// Parse arguments.
+	
+	for( i = 1; i < argc; ++i )
+	{
+		if( strcmp( argv[ i ], "-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, fullPath, NULL, NULL, kServiceDependencies, 
+							 NULL, NULL );
+	err = translate_errno( service, (OSStatus) GetLastError(), kDuplicateErr );
+	require_noerr( err, exit );
+
+	err = SetServiceParameters();
+	check_noerr( err );
+	
+	if( inDescription )
+	{
+		err = SetServiceInfo( scm, inName, inDescription );
+		check_noerr( err );
+	}
+
+	ok = StartService( service, 0, NULL );
+	err = translate_errno( ok, (OSStatus) GetLastError(), kInUseErr );
+	require_noerr( err, exit );
+	
+	ReportStatus( EVENTLOG_SUCCESS, "installed service \"%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 );
+}
+
+
+
+//===========================================================================================================================
+//	SetServiceParameters
+//===========================================================================================================================
+
+static OSStatus SetServiceParameters()
+{
+	DWORD 			value;
+	DWORD			valueLen = sizeof(DWORD);
+	DWORD			type;
+	const char	*	s;
+	OSStatus		err;
+	HKEY			key;
+
+	key = NULL;
+
+	//
+	// Add/Open Parameters section under service entry in registry
+	//
+	s = "SYSTEM\\CurrentControlSet\\Services\\" kServiceName "\\Parameters";
+	err = RegCreateKey( HKEY_LOCAL_MACHINE, s, &key );
+	require_noerr( err, exit );
+	
+	//
+	// If the value isn't already there, then we create it
+	//
+	err = RegQueryValueEx(key, kServiceManageLLRouting, 0, &type, (LPBYTE) &value, &valueLen);
+
+	if (err != ERROR_SUCCESS)
+	{
+		value = 1;
+
+		err = RegSetValueEx( key, kServiceManageLLRouting, 0, REG_DWORD, (const LPBYTE) &value, sizeof(DWORD) );
+		require_noerr( err, exit );
+	}
+
+exit:
+
+	if ( key )
+	{
+		RegCloseKey( key );
+	}
+
+	return( err );
+}
+
+
+
+//===========================================================================================================================
+//	GetServiceParameters
+//===========================================================================================================================
+
+static OSStatus GetServiceParameters()
+{
+	DWORD 			value;
+	DWORD			valueLen;
+	DWORD			type;
+	const char	*	s;
+	OSStatus		err;
+	HKEY			key;
+
+	key = NULL;
+
+	//
+	// Add/Open Parameters section under service entry in registry
+	//
+	s = "SYSTEM\\CurrentControlSet\\Services\\" kServiceName "\\Parameters";
+	err = RegCreateKey( HKEY_LOCAL_MACHINE, s, &key );
+	require_noerr( err, exit );
+	
+	valueLen = sizeof(DWORD);
+	err = RegQueryValueEx(key, kServiceManageLLRouting, 0, &type, (LPBYTE) &value, &valueLen);
+	if (err == ERROR_SUCCESS)
+	{
+		gServiceManageLLRouting = (value) ? true : false;
+	}
+
+	valueLen = sizeof(DWORD);
+	err = RegQueryValueEx(key, kServiceCacheEntryCount, 0, &type, (LPBYTE) &value, &valueLen);
+	if (err == ERROR_SUCCESS)
+	{
+		gServiceCacheEntryCount = value;
+	}
+
+exit:
+
+	if ( key )
+	{
+		RegCloseKey( key );
+	}
+
+	return( err );
+}
+
+
+//===========================================================================================================================
+//	CheckFirewall
+//===========================================================================================================================
+
+static OSStatus CheckFirewall()
+{
+	DWORD 			value;
+	DWORD			valueLen;
+	DWORD			type;
+	const char	*	s;
+	HKEY			key = NULL;
+	OSStatus		err = kUnknownErr;
+	
+	// Check to see if we've managed the firewall.
+	// This package might have been installed, then
+	// the OS was upgraded to SP2 or above.  If that's
+	// the case, then we need to manipulate the firewall
+	// so networking works correctly.
+
+	s = "SYSTEM\\CurrentControlSet\\Services\\" kServiceName "\\Parameters";
+	err = RegCreateKey( HKEY_LOCAL_MACHINE, s, &key );
+	require_noerr( err, exit );
+
+	valueLen = sizeof(DWORD);
+	err = RegQueryValueEx(key, kServiceManageFirewall, 0, &type, (LPBYTE) &value, &valueLen);
+	
+	if ((err != ERROR_SUCCESS) || (value == 0))
+	{
+		wchar_t	fullPath[ MAX_PATH ];
+		DWORD	size;
+
+		// Get a full path to the executable
+
+		size = GetModuleFileNameW( NULL, fullPath, sizeof( fullPath ) );
+		err = translate_errno( size > 0, (OSStatus) GetLastError(), kPathErr );
+		require_noerr( err, exit );
+
+		err = mDNSAddToFirewall(fullPath, kServiceFirewallName);
+		require_noerr( err, exit );
+
+		value = 1;
+		err = RegSetValueEx( key, kServiceManageFirewall, 0, REG_DWORD, (const LPBYTE) &value, sizeof( DWORD ) );
+		require_noerr( err, exit );
+	}
+	
+exit:
+
+	if ( key )
+	{
+		RegCloseKey( key );
+	}
+
+	return( err );
+}
+
+
+
+//===========================================================================================================================
+//	SetServiceInfo
+//===========================================================================================================================
+
+static OSStatus	SetServiceInfo( SC_HANDLE inSCM, const char *inServiceName, const char *inDescription )
+{
+	OSStatus				err;
+	SC_LOCK					lock;
+	SC_HANDLE				service;
+	SERVICE_DESCRIPTION		description;
+	SERVICE_FAILURE_ACTIONS	actions;
+	SC_ACTION				action;
+	BOOL					ok;
+	
+	check( inServiceName );
+	check( inDescription );
+	
+	lock 	= NULL;
+	service	= NULL;
+	
+	// Open the database (if not provided) and lock it to prevent other access while re-configuring.
+	
+	if( !inSCM )
+	{
+		inSCM = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS );
+		err = translate_errno( inSCM, (OSStatus) GetLastError(), kOpenErr );
+		require_noerr( err, exit );
+	}
+	
+	lock = LockServiceDatabase( inSCM );
+	err = translate_errno( lock, (OSStatus) GetLastError(), kInUseErr );
+	require_noerr( err, exit );
+	
+	// Open a handle to the service. 
+
+	service = OpenService( inSCM, inServiceName, SERVICE_CHANGE_CONFIG|SERVICE_START );
+	err = translate_errno( service, (OSStatus) GetLastError(), kNotFoundErr );
+	require_noerr( err, exit );
+	
+	// Change the description.
+	
+	description.lpDescription = (char *) inDescription;
+	ok = ChangeServiceConfig2( service, SERVICE_CONFIG_DESCRIPTION, &description );
+	err = translate_errno( ok, (OSStatus) GetLastError(), kParamErr );
+	require_noerr( err, exit );
+	
+	actions.dwResetPeriod	=	INFINITE;
+	actions.lpRebootMsg		=	NULL;
+	actions.lpCommand		=	NULL;
+	actions.cActions		=	1;
+	actions.lpsaActions		=	&action;
+	action.Delay			=	500;
+	action.Type				=	SC_ACTION_RESTART;
+
+	ok = ChangeServiceConfig2( service, SERVICE_CONFIG_FAILURE_ACTIONS, &actions );
+	err = translate_errno( ok, (OSStatus) GetLastError(), kParamErr );
+	require_noerr( err, exit );
+	
+	err = ERROR_SUCCESS;
+	
+exit:
+	// Close the service and release the lock.
+	
+	if( service )
+	{
+		CloseServiceHandle( service );
+	}
+	if( lock )
+	{
+		UnlockServiceDatabase( lock ); 
+	}
+	return( err );
+}
+
+//===========================================================================================================================
+//	ReportStatus
+//===========================================================================================================================
+
+static void	ReportStatus( int inType, const char *inFormat, ... )
+{
+	if( !gServiceQuietMode )
+	{
+		va_list		args;
+		
+		va_start( args, inFormat );
+		if( gServiceEventSource )
+		{
+			char				s[ 1024 ];
+			BOOL				ok;
+			const char *		array[ 1 ];
+			
+			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;
+   BOOL        ok;
+	
+	initialized = FALSE;
+
+	// Install a Console Control Handler to handle things like control-c signals.
+	
+	ok = SetConsoleCtrlHandler( ConsoleControlHandler, TRUE );
+	err = translate_errno( ok, (OSStatus) GetLastError(), kUnknownErr );
+	require_noerr( err, exit );
+	
+	err = ServiceSpecificInitialize( argc, argv );
+	require_noerr( err, exit );
+	initialized = TRUE;
+	
+	// Run the service. This does not return until the service quits or is stopped.
+	
+	ReportStatus( EVENTLOG_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();
+	check_noerr( err );
+
+	err = GetServiceParameters();
+	check_noerr( err );
+	
+	// Initialize the service status and register the service control handler with the name of the service.
+	
+	gServiceStatus.dwServiceType 				= SERVICE_WIN32_SHARE_PROCESS;
+	gServiceStatus.dwCurrentState 				= 0;
+	gServiceStatus.dwControlsAccepted 			= SERVICE_ACCEPT_STOP|SERVICE_ACCEPT_POWEREVENT;
+	gServiceStatus.dwWin32ExitCode 				= NO_ERROR;
+	gServiceStatus.dwServiceSpecificExitCode 	= NO_ERROR;
+	gServiceStatus.dwCheckPoint 				= 0;
+	gServiceStatus.dwWaitHint 					= 0;
+	
+	gServiceStatusHandle = RegisterServiceCtrlHandlerEx( argv[ 0 ], ServiceControlHandler, NULL );
+	err = translate_errno( gServiceStatusHandle, (OSStatus) GetLastError(), kInUseErr );
+	require_noerr( err, exit );
+	
+	// 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 = SetServiceInfo( 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 DWORD WINAPI	ServiceControlHandler( DWORD inControl, DWORD inEventType, LPVOID inEventData, LPVOID inContext )
+{
+	BOOL		setStatus;
+	BOOL		ok;
+
+	DEBUG_UNUSED( inEventData );
+	DEBUG_UNUSED( inContext );
+	
+	setStatus = TRUE;
+	switch( inControl )
+	{
+		case SERVICE_CONTROL_STOP:
+			dlog( kDebugLevelNotice, DEBUG_NAME "ServiceControlHandler: SERVICE_CONTROL_STOP\n" );
+			
+			ServiceStop();
+			setStatus = FALSE;
+			break;
+		
+		case SERVICE_CONTROL_POWEREVENT:
+
+			if (inEventType == PBT_APMSUSPEND)
+			{
+				mDNSCoreMachineSleep(&gMDNSRecord, TRUE);
+			}
+			else if (inEventType == PBT_APMRESUMESUSPEND)
+			{
+				mDNSCoreMachineSleep(&gMDNSRecord, 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 );
+	}
+
+	return NO_ERROR;
+}
+
+//===========================================================================================================================
+//	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 );
+	
+	err = CheckFirewall();
+	check_noerr( err );
+	
+	// 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;
+	
+	DEBUG_UNUSED( argc );
+	DEBUG_UNUSED( argv );
+	
+	memset( &gMDNSRecord, 0, sizeof gMDNSRecord);
+	memset( &gPlatformStorage, 0, sizeof gPlatformStorage);
+
+	gPlatformStorage.idleThreadCallback = udsIdle;
+	gPlatformStorage.hostDescriptionChangedCallback = HostDescriptionChanged;
+
+	InitializeCriticalSection(&gEventSourceLock);
+	
+	gStopEvent	=	CreateEvent(NULL, FALSE, FALSE, NULL);
+	err = translate_errno( gStopEvent, errno_compat(), kNoResourcesErr );
+	require_noerr( err, exit );
+
+	err = mDNS_Init( &gMDNSRecord, &gPlatformStorage, gRRCache, RR_CACHE_SIZE, mDNS_Init_AdvertiseLocalAddresses, CoreCallback, mDNS_Init_NoInitCallbackContext); 
+	require_noerr( err, exit);
+
+	err = udsserver_init();
+	require_noerr( err, exit);
+
+	//
+	// set a route to link local addresses (169.254.0.0)
+	//
+	if (gServiceManageLLRouting == true)
+	{
+		SetLLRoute();
+	}
+
+exit:
+	if( err != kNoErr )
+	{
+		ServiceSpecificFinalize( argc, argv );
+	}
+	return( err );
+}
+
+//===========================================================================================================================
+//	ServiceSpecificRun
+//===========================================================================================================================
+
+static OSStatus	ServiceSpecificRun( int argc, char *argv[] )
+{
+	DWORD result;
+	
+	DEBUG_UNUSED( argc );
+	DEBUG_UNUSED( argv );
+
+	// Main event loop. Process connection requests and state changes (i.e. quit).
+	while( (result = WaitForSingleObject(gStopEvent, INFINITE)) != WAIT_OBJECT_0 )
+	{
+		// Unexpected wait result.
+		dlog( kDebugLevelWarning, DEBUG_NAME "%s: unexpected wait result (result=0x%08X)\n", __ROUTINE__, result );
+	}
+
+	return kNoErr;
+}
+
+//===========================================================================================================================
+//	ServiceSpecificStop
+//===========================================================================================================================
+
+static OSStatus	ServiceSpecificStop( void )
+{
+	OSStatus	err;
+	BOOL	 	ok;
+
+	ok = SetEvent(gStopEvent);
+	err = translate_errno( ok, (OSStatus) GetLastError(), kUnknownErr );
+	require_noerr( err, exit );
+exit:
+	return( err );
+}
+
+//===========================================================================================================================
+//	ServiceSpecificFinalize
+//===========================================================================================================================
+
+static void	ServiceSpecificFinalize( int argc, char *argv[] )
+{
+	DEBUG_UNUSED( argc );
+	DEBUG_UNUSED( argv );
+	
+	//
+	// clean up any open sessions
+	//
+	while (gEventSources.Head)
+	{
+		EventSourceFinalize((Win32EventSource*) gEventSources.Head);
+	}
+	//
+	// give a chance for the udsserver code to clean up
+	//
+	udsserver_exit();
+
+	//
+	// and finally close down the mDNSCore
+	//
+	mDNS_Close(&gMDNSRecord);
+
+	//
+	// clean up the event sources mutex...no one should be using it now
+	//
+	DeleteCriticalSection(&gEventSourceLock);
+}
+
+
+static void
+CoreCallback(mDNS * const inMDNS, mStatus status)
+{
+	DEBUG_UNUSED( inMDNS );
+
+	if (status == mStatus_ConfigChanged)
+	{
+		if (gServiceManageLLRouting == true)
+		{
+			SetLLRoute();
+		}
+	}
+}
+
+
+static mDNSs32
+udsIdle(mDNS * const inMDNS, mDNSs32 interval)
+{
+	DEBUG_UNUSED( inMDNS );
+
+	//
+	// rdar://problem/3697326
+	//
+	// udsserver_idle wasn't being locked.  This resulted
+	// in multiple threads contesting for the all_requests
+	// data structure in uds_daemon.c
+	//
+	mDNSPlatformLock(&gMDNSRecord);
+
+	interval = udsserver_idle(interval);
+
+	mDNSPlatformUnlock(&gMDNSRecord);
+
+	return interval;
+}
+
+
+static void
+HostDescriptionChanged(mDNS * const inMDNS)
+{
+	DEBUG_UNUSED( inMDNS );
+
+	udsserver_handle_configchange();
+}
+
+
+mDNSlocal unsigned WINAPI
+udsSocketThread(LPVOID inParam)
+{
+	Win32EventSource	*	source		=	(Win32EventSource*) inParam;
+	DWORD					threadID	=	GetCurrentThreadId();
+	DWORD					waitCount;
+	HANDLE					waitList[2];
+	bool					safeToClose;
+	bool					done;
+	bool					locked		= false;
+	mStatus					err			= 0;
+
+	waitCount	= source->waitCount;
+	waitList[0] = source->waitList[0];
+	waitList[1] = source->waitList[1];
+	done		= (bool) (source->flags & EventSourceFinalized);
+
+	while (!done)
+	{
+		DWORD result;
+
+		result = WaitForMultipleObjects(waitCount, waitList, FALSE, INFINITE);
+		
+		mDNSPlatformLock(&gMDNSRecord);
+		locked = true;
+
+		// <rdar://problem/3838237>
+		//
+		// Look up the source by the thread id.  This will ensure that the 
+		// source is still extant.  It could already have been deleted
+		// by the processing thread.
+		//
+
+		EventSourceLock();
+
+		for (source = gEventSources.Head; source; source = source->next)
+		{
+			if (source->threadID == threadID)
+			{
+				break;
+			}
+		}
+
+		EventSourceUnlock();
+		
+		if (source == NULL)
+		{
+			goto exit;
+		}
+
+		//
+		// socket event
+		//
+		if (result == WAIT_OBJECT_0)
+		{
+			source->callback(source->context);
+		}
+		//
+		// close event
+		//
+		else if (result == WAIT_OBJECT_0 + 1)
+		{
+			//
+			// this is a bit of a hack.  we want to clean up the internal data structures
+			// so we'll go in here and it will clean up for us
+			//
+			shutdown(source->sock, 2);
+			source->callback(source->context);
+
+			break;
+		}
+		else
+		{
+			// Unexpected wait result.
+			dlog( kDebugLevelWarning, DEBUG_NAME "%s: unexpected wait result (result=0x%08X)\n", __ROUTINE__, result );
+			goto exit;
+		}
+
+		done   = (bool) (source->flags & EventSourceFinalized);
+		
+		mDNSPlatformUnlock(&gMDNSRecord);
+		locked = false;
+	}
+
+	EventSourceLock();
+	source->flags |= EventSourceFlagsThreadDone;
+	safeToClose = !( source->flags & EventSourceFlagsNoClose );
+	EventSourceUnlock();
+
+	if( safeToClose )
+	{
+		EventSourceFinalize( source );
+	}
+
+exit:
+
+	if ( locked )
+	{
+		mDNSPlatformUnlock(&gMDNSRecord);
+	}
+
+	_endthreadex_compat( (unsigned) err );
+	return( (unsigned) err );	
+}
+
+
+mStatus
+udsSupportAddFDToEventLoop( SocketRef fd, udsEventCallback callback, void *context)
+{
+	Win32EventSource *  newSource;
+	DWORD				result;
+	mStatus				err;
+
+	newSource = malloc(sizeof(Win32EventSource));
+	require_action( newSource, exit, err = mStatus_NoMemoryErr );
+	memset(newSource, 0, sizeof(Win32EventSource));
+
+	newSource->flags	= 0;
+	newSource->sock		= (SOCKET) fd;
+	newSource->callback	= callback;
+	newSource->context	= context;
+
+	newSource->socketEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+	err = translate_errno( newSource->socketEvent, (mStatus) GetLastError(), kUnknownErr );
+	require_noerr( err, exit );
+
+	newSource->closeEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+	err = translate_errno( newSource->closeEvent, (mStatus) GetLastError(), kUnknownErr );
+	require_noerr( err, exit );
+
+	err = WSAEventSelect(newSource->sock, newSource->socketEvent, FD_ACCEPT|FD_READ|FD_CLOSE);
+	err = translate_errno( err == 0, errno_compat(), kNoResourcesErr );
+	require_noerr( err, exit );
+
+	newSource->waitCount = 0;
+	newSource->waitList[ newSource->waitCount++ ] = newSource->socketEvent;
+	newSource->waitList[ newSource->waitCount++ ] = newSource->closeEvent;
+
+	//
+	// lock the list
+	//
+	EventSourceLock();
+	
+	// add the event source to the end of the list, while checking
+	// to see if the list needs to be initialized
+	//
+	if ( gEventSources.LinkOffset == 0)
+	{
+		InitLinkedList( &gEventSources, offsetof( Win32EventSource, next));
+	}
+
+	AddToTail( &gEventSources, newSource);
+
+	//
+	// no longer using the list
+	//
+	EventSourceUnlock();
+
+	// Create thread with _beginthreadex() instead of CreateThread() to avoid memory leaks when using static run-time 
+	// libraries. See <http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/createthread.asp>.
+	// Create the thread suspended then resume it so the thread handle and ID are valid before the thread starts running.
+	newSource->threadHandle = (HANDLE) _beginthreadex_compat( NULL, 0, udsSocketThread, newSource, CREATE_SUSPENDED, &newSource->threadID );
+	err = translate_errno( newSource->threadHandle, (mStatus) GetLastError(), kUnknownErr );
+	require_noerr( err, exit );
+
+	result = ResumeThread( newSource->threadHandle );
+	err = translate_errno( result != (DWORD) -1, errno_compat(), kNoResourcesErr );
+	require_noerr( err, exit );
+
+exit:
+
+	if (err && newSource)
+	{
+		EventSourceFinalize(newSource);
+	}
+
+	return err;
+}
+
+
+mStatus
+udsSupportRemoveFDFromEventLoop( SocketRef fd)
+{
+	Win32EventSource	*	source;
+	mStatus					err = mStatus_NoError;
+	
+	//
+	// find the event source
+	//
+	EventSourceLock();
+
+	for (source = gEventSources.Head; source; source = source->next)
+	{
+		if (source->sock == (SOCKET) fd)
+		{
+			break;
+		}
+	}
+
+	//
+	// if we found him, finalize him
+	//
+	if (source != NULL)
+	{
+		EventSourceFinalize(source);
+	}
+
+	//
+	// done with the list
+	//
+	EventSourceUnlock();
+
+	return err;
+}
+
+
+mDNSexport void RecordUpdatedNiceLabel(mDNS *const m, mDNSs32 delay)
+	{
+	(void)m;
+	(void)delay;
+	// No-op, for now
+	}
+
+
+static mStatus
+EventSourceFinalize(Win32EventSource * source)
+{
+	OSStatus				err;
+	bool					locked;
+	Win32EventSource	*	inserted;
+	bool				sameThread;
+	bool				deferClose;
+	BOOL				ok;
+	DWORD 				threadID;
+	DWORD				result;
+	
+	check( source );
+	
+	// Find the session in the list.
+	
+	EventSourceLock();
+	locked = true;
+	
+	for( inserted = (Win32EventSource*) gEventSources.Head; inserted; inserted = inserted->next )
+	{
+		if( inserted == source )
+		{
+			break;
+		}
+	}
+	require_action( inserted, exit, err = kNotFoundErr );
+
+	//
+	// note that we've had finalize called
+	//
+	source->flags |= EventSourceFinalized;
+	
+	// If we're being called from the same thread as the session (e.g. message callback is closing the session) then 
+	// we must defer the close until the thread is done because the thread is still using the session object.
+	
+	deferClose	= false;
+	threadID	= GetCurrentThreadId();
+	sameThread	= source->threadHandle && ( threadID == source->threadID );
+	if( sameThread && !( source->flags & EventSourceFlagsThreadDone ) )
+	{
+		source->flags &= ~EventSourceFlagsNoClose;
+		deferClose = true;
+	}
+	
+	// If the thread we're not being called from the session thread, but the thread has already marked itself as
+	// as done (e.g. session closed from something like a peer disconnect and at the same time the client also 
+	// tried to close) then we only want to continue with the close if the thread is not going to close itself.
+	
+	if( !sameThread && ( source->flags & EventSourceFlagsThreadDone ) && !( source->flags & EventSourceFlagsNoClose ) )
+	{
+		deferClose = true;
+	}
+	
+	// Signal a close so the thread exits.
+	
+	if( source->closeEvent )
+	{
+		ok = SetEvent( source->closeEvent );
+		check_translated_errno( ok, errno_compat(), kUnknownErr );
+	}	
+	if( deferClose )
+	{
+		err = kNoErr;
+		goto exit;
+	}
+	
+	source->flags |= EventSourceFlagsNoClose;
+	
+	// Remove the session from the list.
+	RemoveFromList(&gEventSources, source);
+	
+	EventSourceUnlock();
+	locked = false;
+	
+	// Wait for the thread to exit. Give up after 3 seconds to handle a hung thread.
+	
+	if( source->threadHandle && ( threadID != source->threadID ) )
+	{
+		result = WaitForSingleObject( source->threadHandle, 3 * 1000 );
+		check_translated_errno( result == WAIT_OBJECT_0, (OSStatus) GetLastError(), result );
+	}
+	
+	// Release the thread.
+	
+	if( source->threadHandle )
+	{
+		ok = CloseHandle( source->threadHandle );
+		check_translated_errno( ok, errno_compat(), kUnknownErr );
+		source->threadHandle = NULL;
+	}
+	
+	// Release the socket event.
+	
+	if( source->socketEvent )
+	{
+		ok = CloseHandle( source->socketEvent );
+		check_translated_errno( ok, errno_compat(), kUnknownErr );
+		source->socketEvent = NULL;
+	}
+	
+	// Release the close event.
+	
+	if( source->closeEvent )
+	{
+		ok = CloseHandle( source->closeEvent );
+		check_translated_errno( ok, errno_compat(), kUnknownErr );
+		source->closeEvent = NULL;
+	}
+	
+	// Release the memory used by the object.
+	free ( source );
+
+	err = kNoErr;
+	
+	dlog( kDebugLevelNotice, DEBUG_NAME "session closed\n" );
+	
+exit:
+
+	if( locked )
+	{
+		EventSourceUnlock();
+	}
+
+	return( err );
+}
+
+
+static void
+EventSourceLock()
+{
+	EnterCriticalSection(&gEventSourceLock);
+}
+
+
+static void
+EventSourceUnlock()
+{
+	LeaveCriticalSection(&gEventSourceLock);
+}
+
+
+//===========================================================================================================================
+//	HaveLLRoute
+//===========================================================================================================================
+
+static bool
+HaveLLRoute(PMIB_IPFORWARDROW rowExtant)
+{
+	PMIB_IPFORWARDTABLE	pIpForwardTable	= NULL;
+	DWORD				dwSize			= 0;
+	BOOL				bOrder			= FALSE;
+	OSStatus			err;
+	bool				found			= false;
+	unsigned long int	i;
+
+	//
+	// Find out how big our buffer needs to be.
+	//
+	err = GetIpForwardTable(NULL, &dwSize, bOrder);
+	require_action( err == ERROR_INSUFFICIENT_BUFFER, exit, err = kUnknownErr );
+
+	//
+	// Allocate the memory for the table
+	//
+	pIpForwardTable = (PMIB_IPFORWARDTABLE) malloc( dwSize );
+	require_action( pIpForwardTable, exit, err = kNoMemoryErr );
+  
+	//
+	// Now get the table.
+	//
+	err = GetIpForwardTable(pIpForwardTable, &dwSize, bOrder);
+	require_noerr( err, exit );
+
+	//
+	// Search for the row in the table we want.
+	//
+	for ( i = 0; i < pIpForwardTable->dwNumEntries; i++)
+	{
+		if (pIpForwardTable->table[i].dwForwardDest == inet_addr(kLLNetworkAddr))
+		{
+			memcpy( rowExtant, &(pIpForwardTable->table[i]), sizeof(*rowExtant) );
+			found = true;
+			break;
+		}
+	}
+
+exit:
+
+	if ( pIpForwardTable != NULL ) 
+	{
+		free(pIpForwardTable);
+	}
+    
+	return found;
+}
+
+
+//===========================================================================================================================
+//	SetLLRoute
+//===========================================================================================================================
+
+static OSStatus
+SetLLRoute()
+{
+	DWORD				ifIndex;
+	MIB_IPFORWARDROW	rowExtant;
+	bool				addRoute;
+	MIB_IPFORWARDROW	row;
+	OSStatus			err;
+
+	ZeroMemory(&row, sizeof(row));
+
+	err = GetRouteDestination(&ifIndex, &row.dwForwardNextHop);
+	require_noerr( err, exit );
+	row.dwForwardDest		= inet_addr(kLLNetworkAddr);
+	row.dwForwardIfIndex	= ifIndex;
+	row.dwForwardMask		= inet_addr(kLLNetworkAddrMask);
+	row.dwForwardType		= 3;
+	row.dwForwardProto		= MIB_IPPROTO_NETMGMT;
+	row.dwForwardAge		= 0;
+	row.dwForwardPolicy		= 0;
+	row.dwForwardMetric1	= 30;
+	row.dwForwardMetric2	= (DWORD) - 1;
+	row.dwForwardMetric3	= (DWORD) - 1;
+	row.dwForwardMetric4	= (DWORD) - 1;
+	row.dwForwardMetric5	= (DWORD) - 1;
+
+	addRoute = true;
+
+	//
+	// check to make sure we don't already have a route
+	//
+	if (HaveLLRoute(&rowExtant))
+	{
+		//
+		// set the age to 0 so that we can do a memcmp.
+		//
+		rowExtant.dwForwardAge = 0;
+
+		//
+		// check to see if this route is the same as our route
+		//
+		if (memcmp(&row, &rowExtant, sizeof(row)) != 0)
+		{
+			//
+			// if it isn't then delete this entry
+			//
+			DeleteIpForwardEntry(&rowExtant);
+		}
+		else
+		{
+			//
+			// else it is, so we don't want to create another route
+			//
+			addRoute = false;
+		}
+	}
+
+	if (addRoute && row.dwForwardNextHop)
+	{
+		err = CreateIpForwardEntry(&row);
+
+		require_noerr( err, exit );
+	}
+
+	//
+	// see if this address is a link local address
+	//
+	if ((row.dwForwardNextHop & 0xFFFF) == row.dwForwardDest)
+	{
+		//
+		// if so, set up a route to ARP everything
+		//
+		row.dwForwardDest		= 0;
+		row.dwForwardIfIndex	= ifIndex;
+		row.dwForwardMask		= 0;
+		row.dwForwardType		= 3;
+		row.dwForwardProto		= MIB_IPPROTO_NETMGMT;
+		row.dwForwardAge		= 0;
+		row.dwForwardPolicy		= 0;
+		row.dwForwardMetric1	= 1;
+		row.dwForwardMetric2	= (DWORD) - 1;
+		row.dwForwardMetric3	= (DWORD) - 1;
+		row.dwForwardMetric4	= (DWORD) - 1;
+		row.dwForwardMetric5	= (DWORD) - 1;
+
+		err = CreateIpForwardEntry(&row);
+
+		require_noerr( err, exit );
+	}
+exit:
+
+	return ( err );
+}
+
+
+//===========================================================================================================================
+//	GetRouteDestination
+//===========================================================================================================================
+
+static OSStatus
+GetRouteDestination(DWORD * ifIndex, DWORD * address)
+{
+	struct in_addr		ia;
+	IP_ADAPTER_INFO	*	pAdapterInfo	=	NULL;
+	IP_ADAPTER_INFO	*	pAdapter		=	NULL;
+	ULONG				bufLen;
+	OSStatus			err;
+
+	//
+	// GetBestInterface will fail if there is no default gateway
+	// configured.  If that happens, we will just take the first
+	// interface in the list. MSDN support says there is no surefire
+	// way to manually determine what the best interface might
+	// be for a particular network address.
+	//
+	ia.s_addr	=	inet_addr(kLLNetworkAddr);
+	err			=	GetBestInterface(*(IPAddr*) &ia, ifIndex);
+
+	if (err)
+	{
+		*ifIndex = 0;
+	}
+
+	//
+	// Make an initial call to GetAdaptersInfo to get
+	// the necessary size into the bufLen variable
+	//
+	err = GetAdaptersInfo( NULL, &bufLen);
+	require_action( err == ERROR_BUFFER_OVERFLOW, exit, err = kUnknownErr );
+
+	pAdapterInfo = (IP_ADAPTER_INFO*) malloc( bufLen );
+	require_action( pAdapterInfo, exit, err = kNoMemoryErr );
+	
+	err = GetAdaptersInfo( pAdapterInfo, &bufLen);
+	require_noerr( err, exit );
+	
+	pAdapter	=	pAdapterInfo;
+	err			=	kUnknownErr;
+			
+	// <rdar://problem/3718122>
+	//
+	// Look for the Nortel VPN virtual interface.  This interface
+	// is identified by it's unique MAC address: 44-45-53-54-42-00
+	//
+	// If the interface is active (i.e., has a non-zero IP Address),
+	// then we want to disable routing table modifications.
+
+	while (pAdapter)
+	{
+		if ((pAdapter->Type == MIB_IF_TYPE_ETHERNET) &&
+		    (pAdapter->AddressLength == 6) &&
+		    (pAdapter->Address[0] == 0x44) &&
+		    (pAdapter->Address[1] == 0x45) &&
+		    (pAdapter->Address[2] == 0x53) &&
+		    (pAdapter->Address[3] == 0x54) &&
+		    (pAdapter->Address[4] == 0x42) &&
+		    (pAdapter->Address[5] == 0x00) &&
+			(inet_addr( pAdapter->IpAddressList.IpAddress.String ) != 0))
+		{
+			goto exit;
+		}
+
+		pAdapter = pAdapter->Next;
+	}
+
+	pAdapter	=	pAdapterInfo;
+	err			=	kUnknownErr;
+
+	while (pAdapter)
+	{
+		//
+		// if we don't have an interface selected, choose the first one
+		//
+		if ((pAdapter->Type == MIB_IF_TYPE_ETHERNET) && (!(*ifIndex) || (pAdapter->Index == (*ifIndex))))
+		{
+			*address =	inet_addr( pAdapter->IpAddressList.IpAddress.String );
+			*ifIndex =  pAdapter->Index;
+			err		 =	kNoErr;
+			break;
+		}
+	
+		pAdapter = pAdapter->Next;
+	}
+
+exit:
+
+	if ( pAdapterInfo != NULL )
+	{
+		free( pAdapterInfo );
+	}
+
+	return( err );
+}
+
diff --git a/mDNSWindows/SystemService/Service.mcp b/mDNSWindows/SystemService/Service.mcp
new file mode 100644
index 0000000000000000000000000000000000000000..ca1556669f00fe404e3383dc0a7055f8f6d7a876
GIT binary patch
literal 126095
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
a0zdC(b-27@{`d16K;G5i;@71S?*9kJhkvaA

literal 0
HcmV?d00001

diff --git a/mDNSWindows/SystemService/Service.rc b/mDNSWindows/SystemService/Service.rc
new file mode 100644
index 0000000..e13561e
--- /dev/null
+++ b/mDNSWindows/SystemService/Service.rc
@@ -0,0 +1,113 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "winres.h"
+#include "WinVersRes.h"
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION MASTER_PROD_VERS
+ PRODUCTVERSION MASTER_PROD_VERS
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x1L
+ FILESUBTYPE 0x0L
+BEGIN
+    BLOCK "StringFileInfo"
+    BEGIN
+        BLOCK "040904b0"
+        BEGIN
+            VALUE "CompanyName", "Apple Computer, Inc."
+            VALUE "FileDescription", "mDNSResponder"
+            VALUE "FileVersion", MASTER_PROD_VERS_STR
+            VALUE "InternalName", "mDNSResponder"
+            VALUE "LegalCopyright", "Copyright (C) 2003-2004 Apple Computer, Inc."
+            VALUE "OriginalFilename", "mDNSResponder.exe"
+            VALUE "ProductName", MASTER_PROD_NAME
+            VALUE "ProductVersion", MASTER_PROD_VERS_STR
+        END
+    END
+    BLOCK "VarFileInfo"
+    BEGIN
+        VALUE "Translation", 0x409, 1200
+    END
+END
+
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE 
+BEGIN
+    "resource.h\0"
+END
+
+2 TEXTINCLUDE 
+BEGIN
+    "#include ""winres.h""\r\n"
+    "#include ""WinVersRes.h""\0"
+END
+
+3 TEXTINCLUDE 
+BEGIN
+    "\r\n"
+    "\0"
+END
+
+#endif    // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// String Table
+//
+
+STRINGTABLE 
+BEGIN
+    IDS_SERVICE_DESCRIPTION "Enables hardware devices and software services to automatically configure themselves on the network and advertise their presence, so that users can discover and use those services without any unnecessary manual setup or administration."
+END
+
+#endif    // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif    // not APSTUDIO_INVOKED
+
diff --git a/mDNSWindows/SystemService/Service.vcproj b/mDNSWindows/SystemService/Service.vcproj
new file mode 100644
index 0000000..f147c74
--- /dev/null
+++ b/mDNSWindows/SystemService/Service.vcproj
@@ -0,0 +1,199 @@
+<?xml version="1.0" encoding = "Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="7.00"
+	Name="mDNSResponder"
+	ProjectGUID="{C1D98254-BA27-4427-A3BE-A68CA2CC5F69}"
+	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;../../mDNSShared;&quot;C:\Program Files\Microsoft Platform SDK for Windows XP SP2\Include&quot;"
+				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;DEBUG=1;MDNS_DEBUGMSGS=0;UNICAST_DISABLED;TARGET_OS_WIN32;WIN32_LEAN_AND_MEAN;USE_TCP_LOOPBACK;PLATFORM_NO_STRSEP;PLATFORM_NO_EPIPE;PLATFORM_NO_RLIMIT;PID_FILE=&quot;&quot;&quot;&quot;"
+				StringPooling="TRUE"
+				MinimalRebuild="TRUE"
+				ExceptionHandling="FALSE"
+				BasicRuntimeChecks="3"
+				SmallerTypeCheck="TRUE"
+				RuntimeLibrary="1"
+				BufferSecurityCheck="TRUE"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				Detect64BitPortabilityProblems="TRUE"
+				DebugInformationFormat="4"
+				CallingConvention="2"/>
+			<Tool
+				Name="VCCustomBuildTool"/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="ws2_32.lib iphlpapi.lib"
+				OutputFile="$(OutDir)/mDNSResponder.exe"
+				LinkIncremental="2"
+				IgnoreAllDefaultLibraries="FALSE"
+				GenerateDebugInformation="TRUE"
+				ProgramDatabaseFile="$(OutDir)/mDNSResponder.pdb"
+				SubSystem="1"
+				TargetMachine="1"/>
+			<Tool
+				Name="VCMIDLTool"/>
+			<Tool
+				Name="VCPostBuildEventTool"/>
+			<Tool
+				Name="VCPreBuildEventTool"/>
+			<Tool
+				Name="VCPreLinkEventTool"/>
+			<Tool
+				Name="VCResourceCompilerTool"
+				AdditionalIncludeDirectories="../"/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"/>
+			<Tool
+				Name="VCWebDeploymentTool"/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="Release"
+			IntermediateDirectory="Release"
+			ConfigurationType="1"
+			CharacterSet="2">
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories=".;../;../../mDNSCore;../../mDNSShared;&quot;C:\Program Files\Microsoft Platform SDK for Windows XP SP2\Include&quot;"
+				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;UNICAST_DISABLED;TARGET_OS_WIN32;WIN32_LEAN_AND_MEAN;USE_TCP_LOOPBACK;PLATFORM_NO_STRSEP;PLATFORM_NO_EPIPE;PLATFORM_NO_RLIMIT;PID_FILE=&quot;&quot;&quot;&quot;"
+				RuntimeLibrary="0"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				Detect64BitPortabilityProblems="TRUE"
+				DebugInformationFormat="3"/>
+			<Tool
+				Name="VCCustomBuildTool"/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="ws2_32.lib iphlpapi.lib"
+				OutputFile="$(OutDir)/mDNSResponder.exe"
+				LinkIncremental="1"
+				GenerateDebugInformation="TRUE"
+				SubSystem="1"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				TargetMachine="1"/>
+			<Tool
+				Name="VCMIDLTool"/>
+			<Tool
+				Name="VCPostBuildEventTool"/>
+			<Tool
+				Name="VCPreBuildEventTool"/>
+			<Tool
+				Name="VCPreLinkEventTool"/>
+			<Tool
+				Name="VCResourceCompilerTool"
+				AdditionalIncludeDirectories="../"/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"/>
+			<Tool
+				Name="VCWebDeploymentTool"/>
+		</Configuration>
+	</Configurations>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
+			<File
+				RelativePath="..\..\mDNSCore\DNSCommon.c">
+			</File>
+			<File
+				RelativePath="..\..\mDNSCore\DNSDigest.c">
+			</File>
+			<File
+				RelativePath="..\DebugServices.c">
+			</File>
+			<File
+				RelativePath="Firewall.cpp">
+			</File>
+			<File
+				RelativePath="..\..\mDNSShared\GenLinkedList.c">
+			</File>
+			<File
+				RelativePath=".\Service.c">
+			</File>
+			<File
+				RelativePath="..\..\mDNSShared\dnssd_ipc.c">
+			</File>
+			<File
+				RelativePath="..\..\mDNSCore\mDNS.c">
+			</File>
+			<File
+				RelativePath="..\..\mDNSShared\mDNSDebug.c">
+			</File>
+			<File
+				RelativePath="..\mDNSWin32.c">
+			</File>
+			<File
+				RelativePath="..\..\mDNSCore\uDNS.c">
+			</File>
+			<File
+				RelativePath="..\..\mDNSShared\uds_daemon.c">
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
+			<File
+				RelativePath="..\CommonServices.h">
+			</File>
+			<File
+				RelativePath="..\..\mDNSCore\DNSCommon.h">
+			</File>
+			<File
+				RelativePath="..\DebugServices.h">
+			</File>
+			<File
+				RelativePath="..\..\mDNSShared\GenLinkedList.h">
+			</File>
+			<File
+				RelativePath=".\Resource.h">
+			</File>
+			<File
+				RelativePath="..\..\mDNSShared\dnssd_ipc.h">
+			</File>
+			<File
+				RelativePath="..\..\mDNSCore\mDNSClientAPI.h">
+			</File>
+			<File
+				RelativePath="..\..\mDNSCore\mDNSDebug.h">
+			</File>
+			<File
+				RelativePath="..\mDNSWin32.h">
+			</File>
+			<File
+				RelativePath="..\..\mDNSCore\uDNS.h">
+			</File>
+			<File
+				RelativePath="..\..\mDNSShared\uds_daemon.h">
+			</File>
+		</Filter>
+		<Filter
+			Name="Resource Files"
+			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
+			UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">
+			<File
+				RelativePath=".\Service.rc">
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
diff --git a/mDNSWindows/SystemService/resource.h b/mDNSWindows/SystemService/resource.h
new file mode 100644
index 0000000..d968af9
--- /dev/null
+++ b/mDNSWindows/SystemService/resource.h
@@ -0,0 +1,17 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by Service.rc
+//
+
+#define IDS_SERVICE_DESCRIPTION        100
+
+// Next default values for new objects
+// 
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE        101
+#define _APS_NEXT_COMMAND_VALUE         40001
+#define _APS_NEXT_CONTROL_VALUE         1000
+#define _APS_NEXT_SYMED_VALUE           101
+#endif
+#endif
diff --git a/mDNSWindows/SystemService/resrc1.h b/mDNSWindows/SystemService/resrc1.h
new file mode 100644
index 0000000..54a6524
--- /dev/null
+++ b/mDNSWindows/SystemService/resrc1.h
@@ -0,0 +1,15 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by Service.rc
+//
+
+// Next default values for new objects
+// 
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE        101
+#define _APS_NEXT_COMMAND_VALUE         40001
+#define _APS_NEXT_CONTROL_VALUE         1000
+#define _APS_NEXT_SYMED_VALUE           101
+#endif
+#endif
diff --git a/mDNSWindows/Applications/SystemServiceTest/Prefix.h b/mDNSWindows/SystemServiceTest/Prefix.h
similarity index 94%
rename from mDNSWindows/Applications/SystemServiceTest/Prefix.h
rename to mDNSWindows/SystemServiceTest/Prefix.h
index 68e705b..53fb893 100644
--- a/mDNSWindows/Applications/SystemServiceTest/Prefix.h
+++ b/mDNSWindows/SystemServiceTest/Prefix.h
@@ -3,8 +3,6 @@
  *
  * @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
@@ -25,6 +23,9 @@
     Change History (most recent first):
 
 $Log: Prefix.h,v $
+Revision 1.1  2004/06/18 04:17:43  rpantos
+Move up one level.
+
 Revision 1.1  2004/01/30 02:58:57  bradley
 Test tool for the mDNSResponder Windows service.
 					
diff --git a/mDNSWindows/Applications/SystemServiceTest/Tool.c b/mDNSWindows/SystemServiceTest/Tool.c
similarity index 99%
rename from mDNSWindows/Applications/SystemServiceTest/Tool.c
rename to mDNSWindows/SystemServiceTest/Tool.c
index 5ab16d9..f4d675a 100644
--- a/mDNSWindows/Applications/SystemServiceTest/Tool.c
+++ b/mDNSWindows/SystemServiceTest/Tool.c
@@ -3,8 +3,6 @@
  *
  * @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
@@ -25,6 +23,12 @@
     Change History (most recent first):
 	
 $Log: Tool.c,v $
+Revision 1.2  2004/07/13 21:24:28  rpantos
+Fix for <rdar://problem/3701120>.
+
+Revision 1.1  2004/06/18 04:17:43  rpantos
+Move up one level.
+
 Revision 1.3  2004/04/09 21:03:15  bradley
 Changed port numbers to use network byte order for consistency with other platforms.
 
@@ -176,7 +180,7 @@ int main( int argc, char *argv[] )
 static void	Usage( void )
 {
 	fprintf( stderr, "\n" );
-	fprintf( stderr, "Rendezvous Service Test 1.0d1\n" );
+	fprintf( stderr, "DNSServiceTest 1.0d1\n" );
 	fprintf( stderr, "\n" );
 	fprintf( stderr, "  -server <IP>                                      Set Remote Server\n" );
 	fprintf( stderr, "  -cv                                               Check Version\n" );
diff --git a/mDNSWindows/Applications/mdnsNSP/mdnsNSP.mcp b/mDNSWindows/SystemServiceTest/Tool.mcp
similarity index 50%
rename from mDNSWindows/Applications/mdnsNSP/mdnsNSP.mcp
rename to mDNSWindows/SystemServiceTest/Tool.mcp
index 96007ece3f0de0b3628107a5859a41336156938b..2f38283556de75bcc00a25ccd1fbb8f14bd0392a 100644
GIT binary patch
literal 210145
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
X#hu<D+G!8&#fV+m=@r)rt%Uy%q;Mb;

literal 198118
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
X@;`ru--xjOvXe{x=M<!~KkNS=mky!7

diff --git a/mDNSWindows/Applications/SystemServiceTest/Tool2002.vcproj b/mDNSWindows/SystemServiceTest/Tool2002.vcproj
similarity index 100%
rename from mDNSWindows/Applications/SystemServiceTest/Tool2002.vcproj
rename to mDNSWindows/SystemServiceTest/Tool2002.vcproj
diff --git a/mDNSWindows/WinServices.cpp b/mDNSWindows/WinServices.cpp
new file mode 100644
index 0000000..ca20ae0
--- /dev/null
+++ b/mDNSWindows/WinServices.cpp
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+    
+$Log: WinServices.cpp,v $
+Revision 1.1  2004/06/18 05:23:33  rpantos
+First checked in
+
+
+*/
+
+#include "WinServices.h"
+
+
+//===========================================================================================================================
+//	UTF8StringToStringObject
+//===========================================================================================================================
+
+OSStatus	UTF8StringToStringObject( const char *inUTF8, CString &inObject )
+{
+	OSStatus		err;
+	int				n;
+	BSTR			unicode;
+	
+	unicode = NULL;
+	
+	n = MultiByteToWideChar( CP_UTF8, 0, inUTF8, -1, NULL, 0 );
+	if( n > 0 )
+	{
+		unicode = (BSTR) malloc( (size_t)( n * sizeof( wchar_t ) ) );
+		if( !unicode )
+		{
+			err = ERROR_INSUFFICIENT_BUFFER;
+			goto exit;
+		}
+
+		n = MultiByteToWideChar( CP_UTF8, 0, inUTF8, -1, unicode, n );
+		try
+		{
+			inObject = unicode;
+		}
+		catch( ... )
+		{
+			err = ERROR_NO_UNICODE_TRANSLATION;
+			goto exit;
+		}
+	}
+	else
+	{
+		inObject = "";
+	}
+	err = ERROR_SUCCESS;
+	
+exit:
+	if( unicode )
+	{
+		free( unicode );
+	}
+	return( err );
+}
diff --git a/mDNSWindows/WinServices.h b/mDNSWindows/WinServices.h
new file mode 100644
index 0000000..9700cd4
--- /dev/null
+++ b/mDNSWindows/WinServices.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+    
+$Log: WinServices.h,v $
+Revision 1.1  2004/06/18 05:23:33  rpantos
+First checked in
+
+
+*/
+
+
+#pragma once
+
+#include <afxwin.h>         // MFC core and standard components
+#include <afxext.h>         // MFC extensions
+#include <afxdtctl.h>		// MFC support for Internet Explorer 4 Common Controls
+#ifndef _AFX_NO_AFXCMN_SUPPORT
+#	include <afxcmn.h>		// MFC support for Windows Common Controls
+#endif
+
+#include <winsock2.h>
+#include <afxsock.h>		// MFC socket extensions
+#include "CommonServices.h"
+
+
+OSStatus	UTF8StringToStringObject( const char *inUTF8, CString &inObject );
diff --git a/mDNSWindows/WinVersRes.h b/mDNSWindows/WinVersRes.h
new file mode 100644
index 0000000..b6edb1e
--- /dev/null
+++ b/mDNSWindows/WinVersRes.h
@@ -0,0 +1,90 @@
+/*
+ * 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@
+
+    Change History (most recent first):
+
+$Log: WinVersRes.h,v $
+Revision 1.17  2004/10/20 15:37:46  shersche
+Bump to Windows-trial-21
+
+Revision 1.16  2004/10/12 23:51:36  cheshire
+Bump version to 1.0.0.20
+
+Revision 1.15  2004/09/21 01:15:56  shersche
+bump version to 1.0.19
+
+Revision 1.14  2004/09/16 21:27:46  shersche
+Bump to version 18
+
+Revision 1.13  2004/09/13 21:28:41  shersche
+Bump version to 17
+
+Revision 1.12  2004/08/28 00:18:01  rpantos
+no message
+
+Revision 1.11  2004/08/26 17:37:15  shersche
+bump version to 1.0.0.14
+
+Revision 1.10  2004/08/05 18:00:04  rpantos
+bump to 1.0.0.13
+
+Revision 1.9  2004/07/27 07:31:46  shersche
+bump to 1.0.0.12
+
+Revision 1.8  2004/07/22 23:28:54  shersche
+bump to Version 1.0.0.11
+
+Revision 1.7  2004/07/20 23:36:24  shersche
+bump to version 1.0.0.10
+
+Revision 1.6  2004/07/14 19:53:26  shersche
+bump version to 1.0.0.9
+
+Revision 1.5  2004/07/13 22:20:02  rpantos
+Fix for <rdar://problem/3701120>.
+
+Revision 1.4  2004/07/09 18:04:17  shersche
+bump version to 1.0.0.8
+
+Revision 1.3  2004/06/27 17:00:15  rpantos
+Cleanup.
+
+Revision 1.2  2004/06/26 22:24:08  rpantos
+Cleanup.
+
+Revision 1.1  2004/06/26 19:17:41  rpantos
+First checked in.
+
+ */
+
+#ifndef WINRESVERS_H
+#define WINRESVERS_H
+
+#define MASTER_PROD_NAME	"Rendezvous"
+
+// Define the product version for mDNSResponder on Windows
+#define MASTER_PROD_VERS		1,0,0,21
+#define MASTER_PROD_VERS_STR	"1,0,0,21"
+#define MASTER_PROD_VERS_STR2	"1.0.0.21"
+#define MASTER_PROD_VERS_STR3 "Explorer Plugin 1.0.0.21"
+
+#endif // WINRESVERS_H
diff --git a/mDNSWindows/mDNSWin32.c b/mDNSWindows/mDNSWin32.c
index b24527f..1f48cf7 100755
--- a/mDNSWindows/mDNSWin32.c
+++ b/mDNSWindows/mDNSWin32.c
@@ -3,8 +3,6 @@
  *
  * @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
@@ -25,6 +23,91 @@
     Change History (most recent first):
     
 $Log: mDNSWin32.c,v $
+Revision 1.63  2004/11/23 03:39:47  cheshire
+Let interface name/index mapping capability live directly in JNISupport.c,
+instead of having to call through to the daemon via IPC to get this information.
+
+Revision 1.62  2004/11/12 03:16:41  rpantos
+rdar://problem/3809541 Add mDNSPlatformGetInterfaceByName, mDNSPlatformGetInterfaceName
+
+Revision 1.61  2004/11/05 22:54:38  shersche
+Change registry key flags from KEY_ALL_ACCESS to KEY_READ to support mDNSResponder running with limited access rights
+Submitted by: Pavel Repin <prepin@gmail.com>
+
+Revision 1.60  2004/11/05 22:41:56  shersche
+Determine subnet mask when populating network interface data structures
+Submitted by: Pavel Repin <prepin@gmail.com>
+Reviewed by:
+
+Revision 1.59  2004/10/28 03:24:42  cheshire
+Rename m->CanReceiveUnicastOn as m->CanReceiveUnicastOn5353
+
+Revision 1.58  2004/10/16 00:17:01  cheshire
+<rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check
+
+Revision 1.57  2004/10/11 21:53:15  shersche
+<rdar://problem/3832450> Change GetWindowsVersionString link scoping from static to non-static so that it can be accessed from other compilation units. The information returned in this function will be used to determine what service dependencies to use when calling CreateService().
+Bug #: 3832450
+
+Revision 1.56  2004/09/26 23:20:36  ksekar
+<rdar://problem/3813108> Allow default registrations in multiple wide-area domains
+
+Revision 1.55  2004/09/21 21:02:57  cheshire
+Set up ifname before calling mDNS_RegisterInterface()
+
+Revision 1.54  2004/09/17 01:08:57  cheshire
+Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
+  The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
+  declared in that file are ONLY appropriate to single-address-space embedded applications.
+  For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
+
+Revision 1.53  2004/09/17 00:19:11  cheshire
+For consistency with AllDNSLinkGroupv6, rename AllDNSLinkGroup to AllDNSLinkGroupv4
+
+Revision 1.52  2004/09/16 00:24:50  cheshire
+<rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
+
+Revision 1.51  2004/09/14 23:42:37  cheshire
+<rdar://problem/3801296> Need to seed random number generator from platform-layer data
+
+Revision 1.50  2004/08/25 23:36:56  shersche
+<rdar://problem/3658379> Remove code that retrieves TTL from received packets
+Bug #: 3658379
+
+Revision 1.49  2004/08/25 16:43:29  ksekar
+Fix Windows build - change mDNS_SetFQDNs to mDNS_SetFQDN, remove unicast
+hostname parameter.
+
+Revision 1.48  2004/08/14 03:22:43  cheshire
+<rdar://problem/3762579> Dynamic DNS UI <-> mDNSResponder glue
+Add GetUserSpecifiedDDNSName() routine
+Convert ServiceRegDomain to domainname instead of C string
+Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs
+
+Revision 1.47  2004/08/06 17:33:02  shersche
+<rdar://problem/3753797> Put correct length of string in first byte of nicelabel
+Bug #: 3753797
+
+Revision 1.46  2004/08/05 05:43:01  shersche
+<rdar://problem/3751566> Add HostDescriptionChangedCallback so callers can choose to handle it when mDNSWin32 core detects that the computer description string has changed
+Bug #: 3751566
+
+Revision 1.45  2004/07/26 22:49:31  ksekar
+<rdar://problem/3651409>: Feature #9516: Need support for NATPMP in client
+
+Revision 1.44  2004/07/26 05:42:50  shersche
+use "Computer Description" for nicename if available, track dynamic changes to "Computer Description"
+
+Revision 1.43  2004/07/13 21:24:25  rpantos
+Fix for <rdar://problem/3701120>.
+
+Revision 1.42  2004/06/24 15:23:24  shersche
+Add InterfaceListChanged callback.  This callback is used in Service.c to add link local routes to the routing table
+Submitted by: herscher
+
+Revision 1.41  2004/06/18 05:22:16  rpantos
+Integrate Scott's changes
+
 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
@@ -42,7 +125,7 @@ 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"
+from mDNSMacOSX.h to mDNSEmbeddedAPI.h), impelemted to return "local"
 only on non-OSX platforms.  Changed call to return a copy of the list
 to avoid shared memory issues.  Added a routine to free the list.
 
@@ -87,7 +170,7 @@ 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.
+Best solution is just to combine mDNSEmbeddedAPI.h and mDNSPlatformFunctions.h into a single file.
 
 Revision 1.24  2003/10/24 23:23:02  bradley
 Removed legacy port 53 support as it is no longer needed.
@@ -96,7 +179,7 @@ Revision 1.23  2003/10/14 03:26:12  bradley
 Clear interface list buffer to workaround Windows CE bug where interfaces are not reported correctly.
 
 Revision 1.22  2003/08/20 06:21:25  bradley
-Updated to latest internal version of the Rendezvous for Windows platform plugin: Added support
+Updated to latest internal version of the mDNSWindows platform layer: Added support
 for Windows CE/PocketPC 2003; re-did interface-related code to emulate getifaddrs/freeifaddrs for
 restricting usage to only active, multicast-capable, and non-point-to-point interfaces and to ease
 the addition of IPv6 support in the future; Changed init code to serialize thread initialization to
@@ -107,7 +190,7 @@ platforms (re-mapped to CreateThread on Window CE) to avoid a leak in the Micros
 Added IPv4/IPv6 string<->address conversion routines; Cleaned up some code and added HeaderDoc.
 
 Revision 1.21  2003/08/18 23:09:57  cheshire
-<rdar://problem/3382647> mDNSResponder divide by zero in mDNSPlatformTimeNow()
+<rdar://problem/3382647> mDNSResponder divide by zero in mDNSPlatformRawTime()
 
 Revision 1.20  2003/08/12 19:56:27  cheshire
 Update to APSL 2.0
@@ -195,7 +278,7 @@ Multicast DNS platform plugin for Win32
 	#include	<process.h>
 #endif
 
-#include	"mDNSClientAPI.h"
+#include	"mDNSEmbeddedAPI.h"
 
 #include	"mDNSWin32.h"
 
@@ -223,7 +306,8 @@ Multicast DNS platform plugin for Win32
 #define	kWaitListCancelEvent						( WAIT_OBJECT_0 + 0 )
 #define	kWaitListInterfaceListChangedEvent			( WAIT_OBJECT_0 + 1 )
 #define	kWaitListWakeupEvent						( WAIT_OBJECT_0 + 2 )
-#define	kWaitListFixedItemCount						3
+#define kWaitListRegEvent							( WAIT_OBJECT_0 + 3 )
+#define	kWaitListFixedItemCount						4
 
 #if( !TARGET_OS_WINDOWS_CE )
 	static GUID										kWSARecvMsgGUID = WSAID_WSARECVMSG;
@@ -239,6 +323,8 @@ Multicast DNS platform plugin for Win32
 
 mDNSlocal mStatus			SetupSynchronizationObjects( mDNS * const inMDNS );
 mDNSlocal mStatus			TearDownSynchronizationObjects( mDNS * const inMDNS );
+mDNSlocal mStatus			SetupNiceName( mDNS * const inMDNS );
+mDNSlocal mStatus			SetupHostName( mDNS * const inMDNS );
 mDNSlocal mStatus			SetupName( mDNS * const inMDNS );
 mDNSlocal mStatus			SetupInterfaceList( mDNS * const inMDNS );
 mDNSlocal mStatus			TearDownInterfaceList( mDNS * const inMDNS );
@@ -256,6 +342,7 @@ mDNSlocal mStatus 			ProcessingThreadInitialize( mDNS * const inMDNS );
 mDNSlocal mStatus			ProcessingThreadSetupWaitList( mDNS * const inMDNS, HANDLE **outWaitList, int *outWaitListCount );
 mDNSlocal void				ProcessingThreadProcessPacket( mDNS *inMDNS, mDNSInterfaceData *inIFD, SocketRef inSock );
 mDNSlocal void				ProcessingThreadInterfaceListChanged( mDNS *inMDNS );
+mDNSlocal void				ProcessingThreadRegistryChanged( mDNS * inMDNS );
 
 // Platform Accessors
 
@@ -277,6 +364,7 @@ mDNSexport mStatus	mDNSPlatformInterfaceIDToInfo( mDNS * const inMDNS, mDNSInter
 
 #if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
 	mDNSlocal int	getifaddrs_ipv6( struct ifaddrs **outAddrs );
+	mDNSlocal int	getifnetmask_ipv6( struct ifaddrs * ifa );
 #endif
 
 #if( !TARGET_OS_WINDOWS_CE )
@@ -288,7 +376,6 @@ mDNSexport mStatus	mDNSPlatformInterfaceIDToInfo( mDNS * const inMDNS, mDNSInter
 #endif
 
 mDNSlocal mDNSBool	CanReceiveUnicast( void );
-mDNSlocal OSStatus	GetWindowsVersionString(  char *inBuffer, size_t inBufferSize );
 
 #ifdef	__cplusplus
 	}
@@ -353,7 +440,7 @@ mStatus	mDNSPlatformInit( mDNS * const inMDNS )
 	supported = ( ( LOBYTE( wsaData.wVersion ) == kWinSockMajorMin ) && ( HIBYTE( wsaData.wVersion ) == kWinSockMinorMin ) );
 	require_action( supported, exit, err = mStatus_UnsupportedErr );
 	
-	inMDNS->CanReceiveUnicast = CanReceiveUnicast();
+	inMDNS->CanReceiveUnicastOn5353 = CanReceiveUnicast();
 	
 	// Setup the HINFO HW/SW strings.
 	
@@ -406,6 +493,7 @@ void	mDNSPlatformClose( mDNS * const inMDNS )
 	
 	err = TearDownInterfaceList( inMDNS );
 	check_noerr( err );
+	check( !inMDNS->p->inactiveInterfaceList );
 		
 	err = TearDownSynchronizationObjects( inMDNS );
 	check_noerr( err );
@@ -434,7 +522,7 @@ void	mDNSPlatformClose( mDNS * const inMDNS )
 mStatus
 	mDNSPlatformSendUDP( 
 		const mDNS * const			inMDNS, 
-		const DNSMessage * const	inMsg, 
+		const void * const	        inMsg, 
 		const mDNSu8 * const		inMsgEnd, 
 		mDNSInterfaceID 			inInterfaceID, 
 		const mDNSAddr *			inDstIP, 
@@ -617,25 +705,30 @@ mDNSexport void	mDNSPlatformMemFree( void *inMem )
 	free( inMem );
 }
 
+//===========================================================================================================================
+//	mDNSPlatformRandomSeed
+//===========================================================================================================================
+
+mDNSexport mDNSu32 mDNSPlatformRandomSeed(void)
+{
+	return( GetTickCount() );
+}
+
 //===========================================================================================================================
 //	mDNSPlatformTimeInit
 //===========================================================================================================================
 
-mDNSexport mStatus	mDNSPlatformTimeInit( mDNSs32 *outTimeNow )
+mDNSexport mStatus	mDNSPlatformTimeInit( void )
 {
-	check( outTimeNow );
-	
 	// No special setup is required on Windows -- we just use GetTickCount().
-	
-	*outTimeNow = mDNSPlatformTimeNow();
 	return( mStatus_NoError );
 }
 
 //===========================================================================================================================
-//	mDNSPlatformTimeNow
+//	mDNSPlatformRawTime
 //===========================================================================================================================
 
-mDNSs32	mDNSPlatformTimeNow( void )
+mDNSs32	mDNSPlatformRawTime( void )
 {
 	return( (mDNSs32) GetTickCount() );
 }
@@ -766,6 +859,7 @@ mDNSu32	mDNSPlatformInterfaceIndexfromInterfaceID( const mDNS * const inMDNS, mD
 	{
 		mDNSInterfaceData *		ifd;
 		
+		// Search active interfaces.
 		for( ifd = inMDNS->p->interfaceList; ifd; ifd = ifd->next )
 		{
 			if( (mDNSInterfaceID) ifd == inID )
@@ -774,6 +868,20 @@ mDNSu32	mDNSPlatformInterfaceIndexfromInterfaceID( const mDNS * const inMDNS, mD
 				break;
 			}
 		}
+		
+		// Search inactive interfaces too so remove events for inactive interfaces report the old interface index.
+		
+		if( !ifd )
+		{
+			for( ifd = inMDNS->p->inactiveInterfaceList; ifd; ifd = ifd->next )
+			{
+				if( (mDNSInterfaceID) ifd == inID )
+				{
+					index = ifd->scopeID;
+					break;
+				}
+			}
+		}
 		check( ifd );
 	}
 	return( index );
@@ -857,6 +965,14 @@ mDNSexport DNameListElem *mDNSPlatformGetSearchDomainList(void)
 	return mDNS_CopyDNameList(&tmp);
 	}
 
+//===========================================================================================================================
+//	mDNSPlatformGetRegDomainList
+//===========================================================================================================================
+
+mDNSexport DNameListElem *mDNSPlatformGetRegDomainList(void)
+	{
+	return NULL;
+	}
 
 
 #if 0
@@ -905,6 +1021,7 @@ void	verbosedebugf_( const char *inFormat, ... )
 //	LogMsg
 //===========================================================================================================================
 
+/*
 void	LogMsg( const char *inFormat, ... )
 {
 	char		buffer[ 512 ];
@@ -917,6 +1034,7 @@ void	LogMsg( const char *inFormat, ... )
 	
 	dlog( kDebugLevelWarning, "%s\n", buffer );
 }
+*/
 
 #if 0
 #pragma mark -
@@ -992,52 +1110,141 @@ mDNSlocal mStatus	TearDownSynchronizationObjects( mDNS * const inMDNS )
 	return( mStatus_NoError );
 }
 
+
 //===========================================================================================================================
-//	SetupName
+//	SetupNiceName
 //===========================================================================================================================
 
-mDNSlocal mStatus	SetupName( mDNS * const inMDNS )
+mDNSlocal mStatus	SetupNiceName( mDNS * const inMDNS )
 {
-	mStatus		err;
+	mStatus		err = 0;
 	char		tempString[ 256 ];
 	
 	check( inMDNS );
 	
 	// Set up the nice name.
+	tempString[ 0 ] = '\0';
+
+	// First try and open the registry key that contains the computer description value
+	if (inMDNS->p->regKey == NULL)
+	{
+		const char * s = "SYSTEM\\CurrentControlSet\\Services\\lanmanserver\\parameters";
+		err = RegOpenKeyEx( HKEY_LOCAL_MACHINE, s, 0, KEY_READ, &inMDNS->p->regKey);
+		check_translated_errno( err == 0, errno_compat(), kNameErr );
+
+		if (err)
+		{
+			inMDNS->p->regKey = NULL;
+		}
+	}
+
+	// if we opened it...
+	if (inMDNS->p->regKey != NULL)
+	{
+		DWORD type;
+		DWORD valueLen = sizeof(tempString);
+
+		// look for the computer description
+		err = RegQueryValueEx(inMDNS->p->regKey, "srvcomment", 0, &type, (LPBYTE) &tempString, &valueLen);
+		check_translated_errno( err == 0, errno_compat(), kNameErr );
+	}
+
+	// if we can't find it in the registry, then use the hostname of the machine
+	if (err || ( tempString[ 0] == '\0' ) )
+	{
+		err = gethostname( tempString, sizeof( tempString ) - 1 );
+		check_translated_errno( err == 0, errno_compat(), kNameErr );
+	}
+
+	// if we can't get the hostname
+	if( err || ( tempString[ 0 ] == '\0' ) )
+	{
+		// Invalidate name so fall back to a default name.
+		
+		strcpy( tempString, kMDNSDefaultName );
+	}
+
+	tempString[ sizeof( tempString ) - 1 ] = '\0';
 	
+	inMDNS->nicelabel.c[ 0 ] = (mDNSu8) (strlen( tempString ) < MAX_DOMAIN_LABEL ? strlen( tempString ) : MAX_DOMAIN_LABEL);
+	memcpy( &inMDNS->nicelabel.c[ 1 ], tempString, inMDNS->nicelabel.c[ 0 ] );
+	
+	dlog( kDebugLevelInfo, DEBUG_NAME "nice name \"%.*s\"\n", inMDNS->nicelabel.c[ 0 ], &inMDNS->nicelabel.c[ 1 ] );
+	
+	return( err );
+}
+
+
+//===========================================================================================================================
+//	SetupHostName
+//===========================================================================================================================
+
+mDNSlocal mStatus	SetupHostName( mDNS * const inMDNS )
+{
+	mStatus		err = 0;
+	char		tempString[ 256 ];
+	domainlabel tempLabel;
+	
+	check( inMDNS );
+
+	// Set up the nice name.
 	tempString[ 0 ] = '\0';
+
+	// use the hostname of the machine
 	err = gethostname( tempString, sizeof( tempString ) - 1 );
 	check_translated_errno( err == 0, errno_compat(), kNameErr );
+
+	// if we can't get the hostname
 	if( err || ( tempString[ 0 ] == '\0' ) )
 	{
 		// Invalidate name so fall back to a default name.
 		
 		strcpy( tempString, kMDNSDefaultName );
 	}
+
 	tempString[ sizeof( tempString ) - 1 ] = '\0';
-	
-	inMDNS->nicelabel.c[ 0 ] = (mDNSu8) strlen( tempString );
-	memcpy( &inMDNS->nicelabel.c[ 1 ], tempString, inMDNS->nicelabel.c[ 0 ] );
+	tempLabel.c[ 0 ] = (mDNSu8) (strlen( tempString ) < MAX_DOMAIN_LABEL ? strlen( tempString ) : MAX_DOMAIN_LABEL );
+	memcpy( &tempLabel.c[ 1 ], tempString, tempLabel.c[ 0 ] );
 	
 	// Set up the host name.
 	
-	ConvertUTF8PstringToRFC1034HostLabel( inMDNS->nicelabel.c, &inMDNS->hostlabel );
+	ConvertUTF8PstringToRFC1034HostLabel( tempLabel.c, &inMDNS->hostlabel );
 	if( inMDNS->hostlabel.c[ 0 ] == 0 )
 	{
 		// Nice name has no characters that are representable as an RFC1034 name (e.g. Japanese) so use the default.
 		
 		MakeDomainLabelFromLiteralString( &inMDNS->hostlabel, kMDNSDefaultName );
 	}
-	check( inMDNS->nicelabel.c[ 0 ] != 0 );
+
 	check( inMDNS->hostlabel.c[ 0 ] != 0 );
 	
-	mDNS_GenerateFQDN( inMDNS );
+	mDNS_SetFQDN( inMDNS );
 	
-	dlog( kDebugLevelInfo, DEBUG_NAME "nice name \"%.*s\"\n", inMDNS->nicelabel.c[ 0 ], &inMDNS->nicelabel.c[ 1 ] );
 	dlog( kDebugLevelInfo, DEBUG_NAME "host name \"%.*s\"\n", inMDNS->hostlabel.c[ 0 ], &inMDNS->hostlabel.c[ 1 ] );
+	
 	return( err );
 }
 
+//===========================================================================================================================
+//	SetupName
+//===========================================================================================================================
+
+mDNSlocal mStatus	SetupName( mDNS * const inMDNS )
+{
+	mStatus		err = 0;
+	
+	check( inMDNS );
+	
+	err = SetupNiceName( inMDNS );
+	check_noerr( err );
+
+	err = SetupHostName( inMDNS );
+	check_noerr( err );
+
+	return err;
+}
+
+
 //===========================================================================================================================
 //	SetupInterfaceList
 //===========================================================================================================================
@@ -1062,7 +1269,7 @@ mDNSlocal mStatus	SetupInterfaceList( mDNS * const inMDNS )
 	// Tear down any existing interfaces that may be set up.
 	
 	TearDownInterfaceList( inMDNS );
-	
+
 	// Set up the name of this machine.
 	
 	err = SetupName( inMDNS );
@@ -1197,12 +1404,32 @@ exit:
 mDNSlocal mStatus	TearDownInterfaceList( mDNS * const inMDNS )
 {
 	mStatus					err;
+	mDNSInterfaceData **		p;
 	mDNSInterfaceData *		ifd;
 	
 	dlog( kDebugLevelTrace, DEBUG_NAME "tearing down interface list\n" );
 	check( inMDNS );
 	check( inMDNS->p );
 	
+	// Free any interfaces that were previously marked inactive and are no longer referenced by the mDNS cache.
+	// Interfaces are marked inactive, but not deleted immediately if they were still referenced by the mDNS cache
+	// so that remove events that occur after an interface goes away can still report the correct interface.
+
+	p = &inMDNS->p->inactiveInterfaceList;
+	while( *p )
+	{
+		ifd = *p;
+		if( NumCacheRecordsForInterfaceID( inMDNS, (mDNSInterfaceID) ifd ) > 0 )
+		{
+			p = &ifd->next;
+			continue;
+		}
+		
+		dlog( kDebugLevelInfo, DEBUG_NAME "freeing unreferenced, inactive interface %#p %#a\n", ifd, &ifd->interfaceInfo.ip );
+		*p = ifd->next;
+		free( ifd );
+	}
+	
 	// Tear down interface list change notifications.
 	
 	err = TearDownNotifications( inMDNS );
@@ -1252,7 +1479,10 @@ mDNSlocal mStatus	SetupInterface( mDNS * const inMDNS, const struct ifaddrs *inI
 	check( strlen( inIFA->ifa_name ) < sizeof( ifd->name ) );
 	strncpy( ifd->name, inIFA->ifa_name, sizeof( ifd->name ) - 1 );
 	ifd->name[ sizeof( ifd->name ) - 1 ] = '\0';
-
+	
+	strncpy(ifd->interfaceInfo.ifname, inIFA->ifa_name, sizeof(ifd->interfaceInfo.ifname));
+	ifd->interfaceInfo.ifname[sizeof(ifd->interfaceInfo.ifname)-1] = 0;
+	
 	// We always send and receive using IPv4, but to reduce traffic, we send and receive using IPv6 only on interfaces 
 	// that have no routable IPv4 address. Having a routable IPv4 address assigned is a reasonable indicator of being 
 	// on a large configured network, which means there's a good chance that most or all the other devices on that 
@@ -1351,6 +1581,9 @@ mDNSlocal mStatus	SetupInterface( mDNS * const inMDNS, const struct ifaddrs *inI
 	err = SockAddrToMDNSAddr( inIFA->ifa_addr, &ifd->interfaceInfo.ip, NULL );
 	require_noerr( err, exit );
 	
+	err = SockAddrToMDNSAddr( inIFA->ifa_netmask, &ifd->interfaceInfo.mask, NULL );
+	require_noerr( err, exit );
+	
 	ifd->interfaceInfo.Advertise = inMDNS->AdvertiseLocalAddresses;
 	
 	err = mDNS_RegisterInterface( inMDNS, &ifd->interfaceInfo );
@@ -1408,10 +1641,21 @@ mDNSlocal mStatus	TearDownInterface( mDNS * const inMDNS, mDNSInterfaceData *inI
 	{
 		close_compat( sock );
 	}
-		
-	// Free the memory used by the interface info.
 	
-	free( inIFD );	
+	// If the interface is still referenced by items in the mDNS cache then put it on the inactive list. This keeps 
+	// the InterfaceID valid so remove events report the correct interface. If it is no longer referenced, free it.
+
+	if( NumCacheRecordsForInterfaceID( inMDNS, (mDNSInterfaceID) inIFD ) > 0 )
+	{
+		inIFD->next = inMDNS->p->inactiveInterfaceList;
+		inMDNS->p->inactiveInterfaceList = inIFD;
+		dlog( kDebugLevelInfo, DEBUG_NAME "deferring free of interface %#p %#a\n", inIFD, &inIFD->interfaceInfo.ip );
+	}
+	else
+	{
+		dlog( kDebugLevelInfo, DEBUG_NAME "freeing interface %#p %#a immediately\n", inIFD, &inIFD->interfaceInfo.ip );
+		free( inIFD );
+	}
 	return( mStatus_NoError );
 }
 
@@ -1468,7 +1712,7 @@ mDNSlocal mStatus	SetupSocket( mDNS * const inMDNS, const struct sockaddr *inAdd
 		
 		// Join the all-DNS multicast group so we receive Multicast DNS packets.
 		
-		mreqv4.imr_multiaddr.s_addr = AllDNSLinkGroup.NotAnInteger;
+		mreqv4.imr_multiaddr.s_addr = AllDNSLinkGroupv4.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 );
@@ -1523,12 +1767,6 @@ mDNSlocal mStatus	SetupSocket( mDNS * const inMDNS, const struct sockaddr *inAdd
 		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).
@@ -1680,6 +1918,16 @@ mDNSlocal mStatus	SetupNotifications( mDNS * const inMDNS )
 	err = translate_errno( err == 0, errno_compat(), kUnknownErr );
 	require_noerr( err, exit );
 
+	inMDNS->p->regEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+	err = translate_errno( inMDNS->p->regEvent, (mStatus) GetLastError(), kUnknownErr );
+	require_noerr( err, exit );
+
+	if (inMDNS->p->regKey != NULL)
+	{
+		err = RegNotifyChangeKeyValue(inMDNS->p->regKey, TRUE, REG_NOTIFY_CHANGE_LAST_SET, inMDNS->p->regEvent, TRUE);
+		require_noerr( err, exit );
+	}
+
 exit:
 	if( err )
 	{
@@ -1699,6 +1947,19 @@ mDNSlocal mStatus	TearDownNotifications( mDNS * const inMDNS )
 		close_compat( inMDNS->p->interfaceListChangedSocket );
 		inMDNS->p->interfaceListChangedSocket = kInvalidSocketRef;
 	}
+
+	if ( inMDNS->p->regEvent != NULL )
+	{
+		CloseHandle( inMDNS->p->regEvent );
+		inMDNS->p->regEvent = NULL;
+	}
+
+	if ( inMDNS->p->regKey != NULL )
+	{
+		RegCloseKey( inMDNS->p->regKey );
+		inMDNS->p->regKey = NULL;
+	}
+
 	return( mStatus_NoError );
 }
 
@@ -1813,7 +2074,11 @@ mDNSlocal unsigned WINAPI	ProcessingThread( LPVOID inParam )
 		{
 			// Give the mDNS core a chance to do its work and determine next event time.
 			
-			mDNSs32 interval = mDNS_Execute(m) - mDNSPlatformTimeNow();
+			mDNSs32 interval = mDNS_Execute(m) - mDNS_TimeNow(m);
+			if (m->p->idleThreadCallback)
+			{
+				interval = m->p->idleThreadCallback(m, interval);
+			}
 			if      (interval < 0)						interval = 0;
 			else if (interval > (0x7FFFFFFF / 1000))	interval = 0x7FFFFFFF / mDNSPlatformOneSecond;
 			else										interval = (interval * 1000) / mDNSPlatformOneSecond;
@@ -1850,6 +2115,14 @@ mDNSlocal unsigned WINAPI	ProcessingThread( LPVOID inParam )
 				dlog( kDebugLevelChatty - 1, DEBUG_NAME "wakeup for mDNS_Execute\n" );
 				continue;
 			}
+			else if ( result == kWaitListRegEvent )
+			{
+				//
+				// The computer description might have changed
+				//
+				ProcessingThreadRegistryChanged( m );
+				break;
+			}
 			else
 			{
 				int		waitItemIndex;
@@ -1966,6 +2239,7 @@ mDNSlocal mStatus	ProcessingThreadSetupWaitList( mDNS * const inMDNS, HANDLE **o
 	*waitItemPtr++ = inMDNS->p->cancelEvent;
 	*waitItemPtr++ = inMDNS->p->interfaceListChangedEvent;
 	*waitItemPtr++ = inMDNS->p->wakeupEvent;
+	*waitItemPtr++ = inMDNS->p->regEvent;
 	
 	// Append all the dynamic wait items to the list.
 	
@@ -2066,10 +2340,6 @@ mDNSlocal void	ProcessingThreadProcessPacket( mDNS *inMDNS, mDNSInterfaceData *i
 				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
@@ -2094,7 +2364,7 @@ mDNSlocal void	ProcessingThreadProcessPacket( mDNS *inMDNS, mDNSInterfaceData *i
 	dlog( kDebugLevelChatty, DEBUG_NAME "\n" );
 	
 	end = ( (mDNSu8 *) &packet ) + n;
-	mDNSCoreReceive( inMDNS, &packet, end, &srcAddr, srcPort, &dstAddr, dstPort, inIFD->interfaceInfo.InterfaceID, ttl );
+	mDNSCoreReceive( inMDNS, &packet, end, &srcAddr, srcPort, &dstAddr, dstPort, inIFD->interfaceInfo.InterfaceID );
 	
 exit:
 	return;
@@ -2110,6 +2380,11 @@ mDNSlocal void	ProcessingThreadInterfaceListChanged( mDNS *inMDNS )
 	
 	dlog( kDebugLevelInfo, DEBUG_NAME "interface list changed\n" );
 	check( inMDNS );
+
+	if (inMDNS->p->interfaceListChangedCallback)
+	{
+		inMDNS->p->interfaceListChangedCallback(inMDNS);
+	}
 	
 	mDNSPlatformLock( inMDNS );
 	
@@ -2135,6 +2410,38 @@ mDNSlocal void	ProcessingThreadInterfaceListChanged( mDNS *inMDNS )
 	mDNSCoreMachineSleep( inMDNS, mDNSfalse );
 }
 
+
+//===========================================================================================================================
+//	ProcessingThreadRegistryChanged
+//===========================================================================================================================
+mDNSlocal void	ProcessingThreadRegistryChanged( mDNS *inMDNS )
+{
+	mStatus		err;
+	
+	dlog( kDebugLevelInfo, DEBUG_NAME "registry has changed\n" );
+	check( inMDNS );
+
+	mDNSPlatformLock( inMDNS );
+
+	// redo the names
+	SetupNiceName( inMDNS );
+
+	if (inMDNS->p->hostDescriptionChangedCallback)
+	{
+		inMDNS->p->hostDescriptionChangedCallback(inMDNS);
+	}
+	
+	// and reset the event handler
+	if ((inMDNS->p->regKey != NULL) && (inMDNS->p->regEvent))
+	{
+		err = RegNotifyChangeKeyValue(inMDNS->p->regKey, TRUE, REG_NOTIFY_CHANGE_LAST_SET, inMDNS->p->regEvent, TRUE);
+		check_noerr( err );
+	}
+
+	mDNSPlatformUnlock( inMDNS );
+}
+
+
 #if 0
 #pragma mark -
 #pragma mark == Utilities ==
@@ -2330,6 +2637,12 @@ mDNSlocal int	getifaddrs_ipv6( struct ifaddrs **outAddrs )
 					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 );
+
+					ifa->ifa_netmask = (struct sockaddr *) calloc( 1, sizeof(struct sockaddr) );
+					require_action( ifa->ifa_netmask, exit, err = WSAENOBUFS );
+					err = getifnetmask_ipv6(ifa);
+					require_noerr(err, exit);
+
 					break;
 				
 				default:
@@ -2358,6 +2671,60 @@ exit:
 	}
 	return( (int) err );
 }
+
+mDNSlocal int
+getifnetmask_ipv6( struct ifaddrs * ifa )
+{
+	PMIB_IPADDRTABLE	pIPAddrTable	=	NULL;
+	DWORD				dwSize			=	0;
+	DWORD				dwRetVal;
+	DWORD				i;
+	int					err				=	0;
+
+	// Make an initial call to GetIpAddrTable to get the
+	// necessary size into the dwSize variable
+
+	dwRetVal = GetIpAddrTable(NULL, &dwSize, 0);
+	require_action( dwRetVal == ERROR_INSUFFICIENT_BUFFER, exit, err = WSAENOBUFS );
+
+	pIPAddrTable = (MIB_IPADDRTABLE *) malloc ( dwSize );
+	require_action( pIPAddrTable != NULL, exit, err = WSAENOBUFS );
+
+	// Make a second call to GetIpAddrTable to get the
+	// actual data we want
+
+	dwRetVal = GetIpAddrTable( pIPAddrTable, &dwSize, 0 );
+	require_action(dwRetVal == NO_ERROR, exit, err = WSAENOBUFS);
+
+	// Now try and find the correct IP Address
+
+	for (i = 0; i < pIPAddrTable->dwNumEntries; i++)
+	{
+		struct sockaddr_in sa;
+
+		memset(&sa, 0, sizeof(sa));
+		sa.sin_family = AF_INET;
+		sa.sin_addr.s_addr = pIPAddrTable->table[i].dwAddr;
+
+		if (memcmp(ifa->ifa_addr, &sa, sizeof(sa)) == 0)
+		{
+			// Found the right one, so copy the subnet mask information
+
+			sa.sin_addr.s_addr = pIPAddrTable->table[i].dwMask;
+			memcpy( ifa->ifa_netmask, &sa, sizeof(sa) );
+			break;
+		}
+	}
+
+exit:
+
+	if ( pIPAddrTable != NULL )
+	{
+		free(pIPAddrTable);
+	}
+
+	return err;
+}
 #endif	// MDNS_WINDOWS_USE_IPV6_IF_ADDRS
 
 #if( !TARGET_OS_WINDOWS_CE )
@@ -2454,6 +2821,12 @@ mDNSlocal int	getifaddrs_ipv4( struct ifaddrs **outAddrs )
 				ifa->ifa_addr = (struct sockaddr *) calloc( 1, sizeof( *sa4 ) );
 				require_action( ifa->ifa_addr, exit, err = WSAENOBUFS );
 				memcpy( ifa->ifa_addr, sa4, sizeof( *sa4 ) );
+
+				sa4 = &ifInfo->iiNetmask.AddressIn;
+				ifa->ifa_netmask = (struct sockaddr*) calloc(1, sizeof( *sa4 ) );
+				require_action( ifa->ifa_netmask, exit, err = WSAENOBUFS );
+				memcpy( ifa->ifa_netmask, sa4, sizeof( *sa4 ) );
+
 				break;
 			}
 			
@@ -2696,7 +3069,7 @@ mDNSlocal mDNSBool	CanReceiveUnicast( void )
 //	GetWindowsVersionString
 //===========================================================================================================================
 
-mDNSlocal OSStatus	GetWindowsVersionString( char *inBuffer, size_t inBufferSize )
+OSStatus	GetWindowsVersionString( char *inBuffer, size_t inBufferSize )
 {
 #if( !defined( VER_PLATFORM_WIN32_CE ) )
 	#define VER_PLATFORM_WIN32_CE		3
diff --git a/mDNSWindows/mDNSWin32.h b/mDNSWindows/mDNSWin32.h
index 946fd7e..70dbe22 100755
--- a/mDNSWindows/mDNSWin32.h
+++ b/mDNSWindows/mDNSWin32.h
@@ -3,8 +3,6 @@
  *
  * @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
@@ -25,6 +23,33 @@
     Change History (most recent first):
     
 $Log: mDNSWin32.h,v $
+Revision 1.18  2004/10/11 21:53:15  shersche
+<rdar://problem/3832450> Change GetWindowsVersionString link scoping from static to non-static so that it can be accessed from other compilation units. The information returned in this function will be used to determine what service dependencies to use when calling CreateService().
+Bug #: 3832450
+
+Revision 1.17  2004/09/17 01:08:57  cheshire
+Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
+  The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
+  declared in that file are ONLY appropriate to single-address-space embedded applications.
+  For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
+
+Revision 1.16  2004/08/05 05:43:01  shersche
+<rdar://problem/3751566> Add HostDescriptionChangedCallback so callers can choose to handle it when mDNSWin32 core detects that the computer description string has changed
+Bug #: 3751566
+
+Revision 1.15  2004/07/26 05:42:50  shersche
+use "Computer Description" for nicename if available, track dynamic changes to "Computer Description"
+
+Revision 1.14  2004/07/13 21:24:25  rpantos
+Fix for <rdar://problem/3701120>.
+
+Revision 1.13  2004/06/24 15:23:24  shersche
+Add InterfaceListChanged callback.  This callback is used in Service.c to add link local routes to the routing table
+Submitted by: herscher
+
+Revision 1.12  2004/06/18 05:22:16  rpantos
+Integrate Scott's changes
+
 Revision 1.11  2004/01/30 02:44:32  bradley
 Added support for IPv6 (v4 & v6, v4-only, v6-only, AAAA over v4, etc.). Added support for DNS-SD
 InterfaceID<->Interface Index mappings. Added support for loopback usage when no other interfaces
@@ -37,7 +62,7 @@ Revision 1.10  2003/10/24 23:23:02  bradley
 Removed legacy port 53 support as it is no longer needed.
 
 Revision 1.9  2003/08/20 06:21:25  bradley
-Updated to latest internal version of the Rendezvous for Windows platform plugin: Added support
+Updated to latest internal version of the mDNSWindows platform layer: Added support
 for Windows CE/PocketPC 2003; re-did interface-related code to emulate getifaddrs/freeifaddrs for
 restricting usage to only active, multicast-capable, and non-point-to-point interfaces and to ease
 the addition of IPv6 support in the future; Changed init code to serialize thread initialization to
@@ -80,7 +105,7 @@ Multicast DNS platform plugin for Win32
 	#include	<mswsock.h>
 #endif
 
-#include	"mDNSClientAPI.h"
+#include	"mDNSEmbeddedAPI.h"
 
 #ifdef	__cplusplus
 	extern "C" {
@@ -109,6 +134,35 @@ struct	mDNSInterfaceData
 	mDNSBool					hostRegistered;
 };
 
+//---------------------------------------------------------------------------------------------------------------------------
+/*!	@typedef	IdleThreadCallback
+
+	@abstract	mDNSWin32 core will call out through this function pointer
+				after calling mDNS_Execute
+*/
+typedef mDNSs32 (*IdleThreadCallback)(mDNS * const inMDNS, mDNSs32 interval);
+//---------------------------------------------------------------------------------------------------------------------------
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!	@typedef	InterfaceListChangedCallback
+
+	@abstract	mDNSWin32 core will call out through this function pointer
+				after detecting an interface list changed event
+*/
+typedef void (*InterfaceListChangedCallback)(mDNS * const inMDNS);
+//---------------------------------------------------------------------------------------------------------------------------
+
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!	@typedef	HostDescriptionChangedCallback
+
+	@abstract	mDNSWin32 core will call out through this function pointer
+				after detecting that the computer description has changed
+*/
+typedef void (*HostDescriptionChangedCallback)(mDNS * const inMDNS);
+//---------------------------------------------------------------------------------------------------------------------------
+
+
 //---------------------------------------------------------------------------------------------------------------------------
 /*!	@struct		mDNS_PlatformSupport_struct
 
@@ -122,13 +176,19 @@ struct	mDNS_PlatformSupport_struct
 	HANDLE						cancelEvent;
 	HANDLE						quitEvent;
 	HANDLE						interfaceListChangedEvent;
+	HANDLE						regEvent;
 	HANDLE						wakeupEvent;
 	HANDLE						initEvent;
+	HKEY						regKey;
 	mStatus						initStatus;
 	SocketRef					interfaceListChangedSocket;
 	int							interfaceCount;
 	mDNSInterfaceData *			interfaceList;
+	mDNSInterfaceData *			inactiveInterfaceList;
 	DWORD						threadID;
+	IdleThreadCallback			idleThreadCallback;
+	InterfaceListChangedCallback	interfaceListChangedCallback;
+	HostDescriptionChangedCallback	hostDescriptionChangedCallback;
 };
 
 //---------------------------------------------------------------------------------------------------------------------------
@@ -155,6 +215,16 @@ struct ifaddrs
 	}	ifa_extra;
 };
 
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!	@function	GetWindowsVersionString
+
+	@abstract	Stores Windows version information in the string passed in (inBuffer)
+*/
+
+OSStatus	GetWindowsVersionString( char *inBuffer, size_t inBufferSize );
+
+
 //---------------------------------------------------------------------------------------------------------------------------
 /*!	@function	getifaddrs
 
diff --git a/mDNSWindows/mdnsNSP/ReadMe.txt b/mDNSWindows/mdnsNSP/ReadMe.txt
new file mode 100644
index 0000000..7a6e2cc
--- /dev/null
+++ b/mDNSWindows/mdnsNSP/ReadMe.txt
@@ -0,0 +1,15 @@
+The mdnsNSP is a NameSpace Provider. It hooks into the Windows name resolution infrastructure to allow any software using the standard Windows APIs for resolving names to work with DNS-SD. For example, when the mdnsNSP is installed, you can type "http://computer.local./" in Internet Explorer and it will resolve "computer.local." using DNS-SD and go to the web site (assuming you have a computer named "computer" on the local network and advertised via DNS-SD).
+
+NSP's are implemented DLLs and must be installed to work. NSP DLLs export an NSPStartup function, which is called when the NSP is used, and NSPStartup provides information about itself (e.g. version number, compatibility information, and a list of function pointers for each of the supported NSP routines).
+
+If you need to register the mdnsNSP, you can use the NSPTool (sources for it are provided along with the mdnsNSP) with the following line from the DOS command line prompt ("<path>" is the actual parent path of the DLL):
+
+NSPTool -install "mdnsNSP" "B600E6E9-553B-4a19-8696-335E5C896153" "<path>"
+
+You can remove remove the mdnsNSP with the following line:
+
+NSPTool -remove "B600E6E9-553B-4a19-8696-335E5C896153"
+
+For more information, check out the following URL:
+
+<http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winsock/winsock/name_space_service_providers_2.asp>
diff --git a/mDNSWindows/mdnsNSP/mdnsNSP.aps b/mDNSWindows/mdnsNSP/mdnsNSP.aps
new file mode 100644
index 0000000000000000000000000000000000000000..2e3b63a468e1c1a3626c28c5381eb781b4838db0
GIT binary patch
literal 34332
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
avfeynUH_ej<--hrPUHD(j5wR-v;PNMMRDr@

literal 0
HcmV?d00001

diff --git a/mDNSWindows/Applications/mdnsNSP/mdnsNSP.c b/mDNSWindows/mdnsNSP/mdnsNSP.c
similarity index 90%
rename from mDNSWindows/Applications/mdnsNSP/mdnsNSP.c
rename to mDNSWindows/mdnsNSP/mdnsNSP.c
index 71fa70e..34311f1 100644
--- a/mDNSWindows/Applications/mdnsNSP/mdnsNSP.c
+++ b/mDNSWindows/mdnsNSP/mdnsNSP.c
@@ -3,8 +3,6 @@
  *
  * @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
@@ -25,12 +23,33 @@
     Change History (most recent first):
     
 $Log: mdnsNSP.c,v $
+Revision 1.6  2004/12/06 01:56:53  shersche
+<rdar://problem/3789425> Use the DNS types and classes defined in dns_sd.h
+Bug #: 3789425
+
+Revision 1.5  2004/07/13 21:24:28  rpantos
+Fix for <rdar://problem/3701120>.
+
+Revision 1.4  2004/07/09 18:03:33  shersche
+removed extraneous DNSServiceQueryRecord call
+
+Revision 1.3  2004/07/07 17:03:49  shersche
+<rdar://problem/3715582> Check for LUP_RETURN_ADDR as well as LUP_RETURN_BLOB in NSPLookupServiceBegin
+Bug #: 3715582
+
+Revision 1.2  2004/06/24 19:18:07  shersche
+Rename to mdnsNSP
+Submitted by: herscher
+
+Revision 1.1  2004/06/18 04:13:44  rpantos
+Move up one level.
+
 Revision 1.2  2004/04/08 09:43:43  bradley
 Changed callback calling conventions to __stdcall so they can be used with C# delegates.
 
 Revision 1.1  2004/01/30 03:00:33  bradley
-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.
+mDNS NameSpace Provider (NSP). Hooks into the Windows name resolution system to perform
+.local name lookups using Multicast DNS in all Windows apps.
 
 */
 
@@ -44,7 +63,7 @@ Rendezvous name lookups using Multicast DNS so .local names work in all Windows
 #include	<guiddef.h>
 #include	<ws2spi.h>
 
-#include	"DNSSD.h"
+#include	"dns_sd.h"
 
 #if 0
 #pragma mark == Structures ==
@@ -176,7 +195,7 @@ DEBUG_LOCAL size_t	QueryCopyQuerySetSize( QueryRef inRef, const WSAQUERYSETW *in
 //===========================================================================================================================
 
 // {B600E6E9-553B-4a19-8696-335E5C896153}
-// GUID		kRendezvousNSPGUID = { 0xb600e6e9, 0x553b, 0x4a19, { 0x86, 0x96, 0x33, 0x5e, 0x5c, 0x89, 0x61, 0x53 } };
+// GUID		kmdnsNSPGUID = { 0xb600e6e9, 0x553b, 0x4a19, { 0x86, 0x96, 0x33, 0x5e, 0x5c, 0x89, 0x61, 0x53 } };
 
 DEBUG_LOCAL LONG					gRefCount			= 0;
 DEBUG_LOCAL CRITICAL_SECTION		gLock;
@@ -200,7 +219,7 @@ BOOL APIENTRY	DllMain( HINSTANCE inInstance, DWORD inReason, LPVOID inReserved )
 	switch( inReason )
 	{
 		case DLL_PROCESS_ATTACH:			
-			debug_initialize( kDebugOutputTypeWindowsEventLog, "Rendezvous NSP", inInstance );
+			debug_initialize( kDebugOutputTypeWindowsEventLog, "mDNS NSP", inInstance );
 			debug_set_property( kDebugPropertyTagPrintLevel, kDebugLevelInfo );
 			dlog( kDebugLevelTrace, "\n" );
 			dlog( kDebugLevelVerbose, "%s: process attach\n", __ROUTINE__ );
@@ -319,7 +338,6 @@ int	WSPAPI	NSPCleanup( LPGUID inProviderID )
 	if( gDNSSDInitialized )
 	{
 		gDNSSDInitialized = false;
-		DNSServiceFinalize();
 	}
 	if( gLockInitialized )
 	{
@@ -376,7 +394,7 @@ DEBUG_LOCAL int WSPAPI
 	// 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 );
+	require_action_quiet( inFlags & (LUP_RETURN_ADDR|LUP_RETURN_BLOB), exit, err = WSASERVICE_NOT_FOUND );
 	
 	type = inQuerySet->dwNameSpace;
 	require_action_quiet( ( type == NS_DNS ) || ( type == NS_ALL ), exit, err = WSASERVICE_NOT_FOUND );
@@ -409,21 +427,71 @@ DEBUG_LOCAL int WSPAPI
 	
 	p = name + ( size - 1 );
 	p = ( *p == '.' ) ? ( p - sizeof_string( ".local" ) ) : ( ( p - sizeof_string( ".local" ) ) + 1 );
+	if	( ( ( p[ 0 ] != '.' )						||
+		( ( p[ 1 ] != 'L' ) && ( p[ 1 ] != 'l' ) )	||
+		( ( p[ 2 ] != 'O' ) && ( p[ 2 ] != 'o' ) )	||
+		( ( p[ 3 ] != 'C' ) && ( p[ 3 ] != 'c' ) )	||
+		( ( p[ 4 ] != 'A' ) && ( p[ 4 ] != 'a' ) )	||
+		( ( p[ 5 ] != 'L' ) && ( p[ 5 ] != 'l' ) ) ) )
+	{
+		require_action_quiet( size > sizeof_string( ".0.8.e.f.ip6.arpa" ), exit, err = WSASERVICE_NOT_FOUND );
+ 
+		p = name + ( size - 1 );
+		p = ( *p == '.' ) ? ( p - sizeof_string( ".0.8.e.f.ip6.arpa" ) ) : ( ( p - sizeof_string( ".0.8.e.f.ip6.arpa" ) ) + 1 );
+	
+		if	( ( ( p[ 0 ] != '.' )							||
+			( ( p[ 1 ] != '0' ) )							||
+			( ( p[ 2 ] != '.' ) )							||
+			( ( p[ 3 ] != '8' ) )							||
+			( ( p[ 4 ] != '.' ) )							||
+			( ( p[ 5 ] != 'E' ) && ( p[ 5 ] != 'e' ) )		||
+			( ( p[ 6 ] != '.' ) )							||
+			( ( p[ 7 ] != 'F' ) && ( p[ 7 ] != 'f' ) )		||
+			( ( p[ 8 ] != '.' ) )							||
+			( ( p[ 9 ] != 'I' ) && ( p[ 9 ] != 'i' ) )		||
+			( ( p[ 10 ] != 'P' ) && ( p[ 10 ] != 'p' ) )	||	
+			( ( p[ 11 ] != '6' ) )							||
+			( ( p[ 12 ] != '.' ) )							||
+			( ( p[ 13 ] != 'A' ) && ( p[ 13 ] != 'a' ) )	||
+			( ( p[ 14 ] != 'R' ) && ( p[ 14 ] != 'r' ) )	||
+			( ( p[ 15 ] != 'P' ) && ( p[ 15 ] != 'p' ) )	||
+			( ( p[ 16 ] != 'A' ) && ( p[ 16 ] != 'a' ) ) ) )
+		{
+			require_action_quiet( size > sizeof_string( ".254.169.in-addr.arpa" ), exit, err = WSASERVICE_NOT_FOUND );
+ 
+			p = name + ( size - 1 );
+			p = ( *p == '.' ) ? ( p - sizeof_string( ".254.169.in-addr.arpa" ) ) : ( ( p - sizeof_string( ".254.169.in-addr.arpa" ) ) + 1 );
+	
 	require_action_quiet( ( ( p[ 0 ] == '.' )						 &&
-						  ( ( p[ 1 ] == '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.
+									( ( p[ 1 ] == '2' ) )							&&
+									( ( p[ 2 ] == '5' ) )							&&
+									( ( p[ 3 ] == '4' ) )							&&
+									( ( p[ 4 ] == '.' ) )							&&
+									( ( p[ 5 ] == '1' ) )							&&
+									( ( p[ 6 ] == '6' ) )							&&
+									( ( p[ 7 ] == '9' ) )							&&
+									( ( p[ 8 ] == '.' ) )							&&
+									( ( p[ 9 ] == 'I' ) || ( p[ 9 ] == 'i' ) )		&&
+									( ( p[ 10 ] == 'N' ) || ( p[ 10 ] == 'n' ) )	&&	
+									( ( p[ 11 ] == '-' ) )							&&
+									( ( p[ 12 ] == 'A' ) || ( p[ 12 ] == 'a' ) )	&&
+									( ( p[ 13 ] == 'D' ) || ( p[ 13 ] == 'd' ) )	&&
+									( ( p[ 14 ] == 'D' ) || ( p[ 14 ] == 'd' ) )	&&
+									( ( p[ 15 ] == 'R' ) || ( p[ 15 ] == 'r' ) )	&&
+									( ( p[ 16 ] == '.' ) )							&&
+									( ( p[ 17 ] == 'A' ) || ( p[ 17 ] == 'a' ) )	&&
+									( ( p[ 18 ] == 'R' ) || ( p[ 18 ] == 'r' ) )	&&
+									( ( p[ 19 ] == 'P' ) || ( p[ 19 ] == 'p' ) )	&&
+									( ( p[ 20 ] == 'A' ) || ( p[ 20 ] == 'a' ) ) ),
+									exit, err = WSASERVICE_NOT_FOUND );
+		}
+	}
+
+	// The name ends in .local, .0.8.e.f.ip6.arpa, or .254.169.in-addr.arpa so start the resolve operation. Lazy initialize DNS-SD if needed.
 		
 	NSPLock();
 	if( !gDNSSDInitialized )
 	{
-		err = DNSServiceInitialize( kDNSServiceInitializeFlagsNoServerCheck, 0 );
-		require_noerr( err, exit );
 		gDNSSDInitialized = true;
 	}
 	
@@ -485,6 +553,7 @@ DEBUG_LOCAL int WSPAPI
 	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 );
+	DNSServiceProcessResult(obj->resolver);
 	require_action_quiet( obj->addrValid, exit, err = WSA_E_NO_MORE );
 	
 	// Copy the externalized query results to the callers buffer (if it fits).
@@ -687,6 +756,16 @@ DEBUG_LOCAL OSStatus	QueryCreate( const WSAQUERYSETW *inQuerySet, DWORD inQueryS
 	obj->cancelEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
 	require_action( obj->cancelEvent, exit, err = WSA_NOT_ENOUGH_MEMORY );
 	
+	// Start the query.
+
+	err = DNSServiceQueryRecord( &obj->resolver, 0, 0, name, kDNSServiceType_A, kDNSServiceClass_IN, 
+		QueryRecordCallback, obj );
+	require_noerr( err, exit );
+
+	// Attach the socket to the event
+
+	WSAEventSelect(DNSServiceRefSockFD(obj->resolver), obj->dataEvent, FD_READ|FD_CLOSE);
+	
 	obj->waitCount = 0;
 	obj->waitHandles[ obj->waitCount++ ] = obj->dataEvent;
 	obj->waitHandles[ obj->waitCount++ ] = obj->cancelEvent;
@@ -699,12 +778,6 @@ DEBUG_LOCAL OSStatus	QueryCreate( const WSAQUERYSETW *inQuerySet, DWORD inQueryS
 	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;
@@ -849,8 +922,8 @@ DEBUG_LOCAL void CALLBACK_COMPAT
 	check( obj );
 	require_noerr( inErrorCode, exit );
 	require_quiet( inFlags & kDNSServiceFlagsAdd, exit );
-	require( inRRClass   == kDNSServiceDNSClass_IN, exit );
-	require( inRRType    == kDNSServiceDNSType_A, exit );
+	require( inRRClass   == kDNSServiceClass_IN, exit );
+	require( inRRType    == kDNSServiceType_A, exit );
 	require( inRDataSize == 4, exit );
 	
 	dlog( kDebugLevelTrace, "%s (flags=0x%08X, name=%s, rrType=%d, rDataSize=%d)\n", 
diff --git a/mDNSWindows/Applications/mdnsNSP/mdnsNSP.def b/mDNSWindows/mdnsNSP/mdnsNSP.def
similarity index 77%
rename from mDNSWindows/Applications/mdnsNSP/mdnsNSP.def
rename to mDNSWindows/mdnsNSP/mdnsNSP.def
index 948f863..16f4f18 100644
--- a/mDNSWindows/Applications/mdnsNSP/mdnsNSP.def
+++ b/mDNSWindows/mdnsNSP/mdnsNSP.def
@@ -23,13 +23,19 @@
 ;	Change History (most recent first):
 ;    
 ; $Log: mdnsNSP.def,v $
+; Revision 1.2  2004/07/13 21:24:28  rpantos
+; Fix for <rdar://problem/3701120>.
+;
+; Revision 1.1  2004/06/18 04:13:44  rpantos
+; Move up one level.
+;
 ; Revision 1.1  2004/01/30 03:00:33  bradley
-; 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.
+; mDNS NameSpace Provider (NSP). Hooks into the Windows name resolution system to 
+; perform .local name lookups using Multicast DNS in all Windows apps.
 ;
 ;
 
-LIBRARY		RendezvousNSP
+LIBRARY		mdnsNSP
 
 EXPORTS
 	NSPStartup
diff --git a/mDNSWindows/mdnsNSP/mdnsNSP.rc b/mDNSWindows/mdnsNSP/mdnsNSP.rc
new file mode 100644
index 0000000..e0d4772
--- /dev/null
+++ b/mDNSWindows/mdnsNSP/mdnsNSP.rc
@@ -0,0 +1,104 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+#include "WinVersRes.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE 
+BEGIN
+    "resource.h\0"
+END
+
+2 TEXTINCLUDE 
+BEGIN
+    "#include ""afxres.h""\r\n"
+    "#include ""WinVersRes.h""\r\n"
+    "\0"
+END
+
+3 TEXTINCLUDE 
+BEGIN
+    "\r\n"
+    "\0"
+END
+
+#endif    // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION MASTER_PROD_VERS
+ PRODUCTVERSION MASTER_PROD_VERS
+ FILEFLAGSMASK 0x17L
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+    BLOCK "StringFileInfo"
+    BEGIN
+        BLOCK "040904b0"
+        BEGIN
+            VALUE "CompanyName", "Apple Computer, Inc."
+            VALUE "FileDescription", "mdnsNSP Dynamic Link Library"
+            VALUE "FileVersion", MASTER_PROD_VERS_STR
+            VALUE "InternalName", "mdnsNSP"
+            VALUE "LegalCopyright", "Copyright (C) 2004"
+            VALUE "OriginalFilename", "mdnsNSP.dll"
+            VALUE "ProductName", MASTER_PROD_NAME
+            VALUE "ProductVersion", MASTER_PROD_VERS_STR
+        END
+    END
+    BLOCK "VarFileInfo"
+    BEGIN
+        VALUE "Translation", 0x409, 1200
+    END
+END
+
+#endif    // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif    // not APSTUDIO_INVOKED
+
diff --git a/mDNSWindows/mdnsNSP/mdnsNSP.vcproj b/mDNSWindows/mdnsNSP/mdnsNSP.vcproj
new file mode 100644
index 0000000..5e49db5
--- /dev/null
+++ b/mDNSWindows/mdnsNSP/mdnsNSP.vcproj
@@ -0,0 +1,160 @@
+<?xml version="1.0" encoding = "Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="7.00"
+	Name="mdnsNSP"
+	ProjectGUID="{F4F15529-F0EB-402F-8662-73C5797EE557}"
+	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=".;../;../../mDNSShared"
+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;NSP_EXPORTS;DEBUG;WIN32_LEAN_AND_MEAN"
+				StringPooling="TRUE"
+				MinimalRebuild="TRUE"
+				ExceptionHandling="FALSE"
+				BasicRuntimeChecks="3"
+				SmallerTypeCheck="TRUE"
+				RuntimeLibrary="1"
+				BufferSecurityCheck="TRUE"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				Detect64BitPortabilityProblems="TRUE"
+				DebugInformationFormat="4"
+				CallingConvention="2"/>
+			<Tool
+				Name="VCCustomBuildTool"/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="../DLL/Debug/dnssd.lib ws2_32.lib iphlpapi.lib"
+				OutputFile="$(OutDir)/mdnsNSP.dll"
+				LinkIncremental="2"
+				ModuleDefinitionFile="mdnsNSP.def"
+				GenerateDebugInformation="TRUE"
+				ProgramDatabaseFile="$(OutDir)/mdnsNSP.pdb"
+				SubSystem="2"
+				ImportLibrary="$(OutDir)/mdnsNSP.lib"
+				TargetMachine="1"/>
+			<Tool
+				Name="VCMIDLTool"/>
+			<Tool
+				Name="VCPostBuildEventTool"/>
+			<Tool
+				Name="VCPreBuildEventTool"/>
+			<Tool
+				Name="VCPreLinkEventTool"/>
+			<Tool
+				Name="VCResourceCompilerTool"
+				AdditionalIncludeDirectories="../"/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"/>
+			<Tool
+				Name="VCWebDeploymentTool"/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="Release"
+			IntermediateDirectory="Release"
+			ConfigurationType="2"
+			CharacterSet="2">
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories=".;../;../../mDNSShared"
+				PreprocessorDefinitions="WIN32;_WINDOWS;_USRDLL;NSP_EXPORTS;WIN32_LEAN_AND_MEAN"
+				StringPooling="TRUE"
+				MinimalRebuild="TRUE"
+				ExceptionHandling="FALSE"
+				BasicRuntimeChecks="0"
+				SmallerTypeCheck="FALSE"
+				RuntimeLibrary="0"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				Detect64BitPortabilityProblems="TRUE"
+				DebugInformationFormat="3"
+				CallingConvention="2"/>
+			<Tool
+				Name="VCCustomBuildTool"/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="../DLL/Release/dnssd.lib ws2_32.lib iphlpapi.lib"
+				OutputFile="$(OutDir)/mdnsNSP.dll"
+				LinkIncremental="1"
+				ModuleDefinitionFile="mdnsNSP.def"
+				GenerateDebugInformation="TRUE"
+				SubSystem="2"
+				OptimizeReferences="0"
+				EnableCOMDATFolding="0"
+				ImportLibrary="$(OutDir)/mdnsNSP.lib"
+				TargetMachine="1"/>
+			<Tool
+				Name="VCMIDLTool"/>
+			<Tool
+				Name="VCPostBuildEventTool"/>
+			<Tool
+				Name="VCPreBuildEventTool"/>
+			<Tool
+				Name="VCPreLinkEventTool"/>
+			<Tool
+				Name="VCResourceCompilerTool"
+				AdditionalIncludeDirectories="../"/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"/>
+			<Tool
+				Name="VCWebDeploymentTool"/>
+		</Configuration>
+	</Configurations>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
+			<File
+				RelativePath="..\DebugServices.c">
+			</File>
+			<File
+				RelativePath=".\mdnsNSP.c">
+			</File>
+			<File
+				RelativePath=".\mdnsNSP.def">
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
+			<File
+				RelativePath="..\CommonServices.h">
+			</File>
+			<File
+				RelativePath="..\DebugServices.h">
+			</File>
+			<File
+				RelativePath="..\..\..\mDNSShared\dns_sd.h">
+			</File>
+			<File
+				RelativePath=".\resource.h">
+			</File>
+		</Filter>
+		<Filter
+			Name="Resource Files"
+			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
+			UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">
+			<File
+				RelativePath=".\mdnsNSP.rc">
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
diff --git a/mDNSWindows/mdnsNSP/resource.h b/mDNSWindows/mdnsNSP/resource.h
new file mode 100644
index 0000000..818f083
--- /dev/null
+++ b/mDNSWindows/mdnsNSP/resource.h
@@ -0,0 +1,27 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by mdnsNSP.rc
+//
+#define IDS_PROJNAME                    100
+#define IDR_WMDMLOGGER                  101
+#define IDS_LOG_SEV_INFO                201
+#define IDS_LOG_SEV_WARN                202
+#define IDS_LOG_SEV_ERROR               203
+#define IDS_LOG_DATETIME                204
+#define IDS_LOG_SRCNAME                 205
+#define IDS_DEF_LOGFILE                 301
+#define IDS_DEF_MAXSIZE                 302
+#define IDS_DEF_SHRINKTOSIZE            303
+#define IDS_DEF_LOGENABLED              304
+#define IDS_MUTEX_TIMEOUT               401
+
+// Next default values for new objects
+// 
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE        201
+#define _APS_NEXT_COMMAND_VALUE         32768
+#define _APS_NEXT_CONTROL_VALUE         201
+#define _APS_NEXT_SYMED_VALUE           101
+#endif
+#endif
-- 
2.47.2

