]> git.saurik.com Git - apple/mdnsresponder.git/commitdiff
mDNSResponder-58.3.tar.gz v58.3
authorApple <opensource@apple.com>
Sat, 20 Dec 2003 02:16:26 +0000 (02:16 +0000)
committerApple <opensource@apple.com>
Sat, 20 Dec 2003 02:16:26 +0000 (02:16 +0000)
77 files changed:
Makefile
mDNSCore/mDNS.c
mDNSCore/mDNSClientAPI.h
mDNSCore/mDNSDebug.h
mDNSCore/mDNSPlatformFunctions.h
mDNSMacOS9/CarbonResource.r
mDNSMacOS9/Mac OS Test Responder.c
mDNSMacOS9/Mac OS Test Searcher.c
mDNSMacOS9/mDNSMacOS9.c
mDNSMacOS9/mDNSMacOS9.h
mDNSMacOS9/mDNSPrefixCarbon.h
mDNSMacOS9/mDNSPrefixCarbonDebug.h
mDNSMacOS9/mDNSPrefixClassic.h
mDNSMacOSX/Applications/DNSServiceBrowser/BrowserController.h
mDNSMacOSX/Applications/DNSServiceBrowser/BrowserController.m
mDNSMacOSX/Applications/DNSServiceBrowser/main.m
mDNSMacOSX/Applications/DNSServiceRegistration/RegistrationController.h
mDNSMacOSX/Applications/DNSServiceRegistration/RegistrationController.m
mDNSMacOSX/Applications/DNSServiceRegistration/main.m
mDNSMacOSX/Applications/HAAutomounter/HAAutomounter.h
mDNSMacOSX/Applications/HAAutomounter/HAAutomounter.m
mDNSMacOSX/Applications/HAAutomounter/main.m
mDNSMacOSX/CFSocket.c
mDNSMacOSX/CFSocketPuma.c
mDNSMacOSX/DNSServiceDiscoveryDefines.h
mDNSMacOSX/DNSServiceDiscoveryReply.defs
mDNSMacOSX/DNSServiceDiscoveryRequest.defs
mDNSMacOSX/SampleUDSClient.c
mDNSMacOSX/SamplemDNSClient.c
mDNSMacOSX/daemon.c
mDNSMacOSX/dns_sd.h
mDNSMacOSX/dnssd_clientstub.c
mDNSMacOSX/dnssd_ipc.c
mDNSMacOSX/dnssd_ipc.h
mDNSMacOSX/mDNSMacOSX.h
mDNSMacOSX/uds_daemon.c
mDNSPosix/Client.c
mDNSPosix/ExampleClientApp.c
mDNSPosix/ExampleClientApp.h
mDNSPosix/Identify.c
mDNSPosix/NetMonitor.c
mDNSPosix/ProxyResponder.c
mDNSPosix/Responder.c
mDNSPosix/mDNSPosix.c
mDNSPosix/mDNSPosix.h
mDNSPosix/mDNSUNP.c
mDNSPosix/mDNSUNP.h
mDNSShared/dns_sd.h [new file with mode: 0755]
mDNSShared/dnssd_clientstub.c [new file with mode: 0755]
mDNSShared/dnssd_ipc.c [new file with mode: 0644]
mDNSShared/dnssd_ipc.h [new file with mode: 0644]
mDNSShared/uds_daemon.c [new file with mode: 0644]
mDNSVxWorks/mDNSVxWorks.c
mDNSVxWorks/mDNSVxWorks.h
mDNSWindows/Applications/RendezvousBrowser/Windows/Sources/AboutDialog.cpp
mDNSWindows/Applications/RendezvousBrowser/Windows/Sources/AboutDialog.h
mDNSWindows/Applications/RendezvousBrowser/Windows/Sources/Application.cpp
mDNSWindows/Applications/RendezvousBrowser/Windows/Sources/Application.h
mDNSWindows/Applications/RendezvousBrowser/Windows/Sources/ChooserDialog.cpp
mDNSWindows/Applications/RendezvousBrowser/Windows/Sources/ChooserDialog.h
mDNSWindows/Applications/RendezvousBrowser/Windows/Sources/StdAfx.cpp
mDNSWindows/Applications/RendezvousBrowser/Windows/Sources/StdAfx.h
mDNSWindows/Applications/RendezvousBrowser/WindowsCE/Sources/Application.cpp
mDNSWindows/Applications/RendezvousBrowser/WindowsCE/Sources/Application.h
mDNSWindows/Applications/RendezvousBrowser/WindowsCE/Sources/BrowserDialog.cpp
mDNSWindows/Applications/RendezvousBrowser/WindowsCE/Sources/BrowserDialog.h
mDNSWindows/Applications/RendezvousBrowser/WindowsCE/Sources/StdAfx.cpp
mDNSWindows/Applications/RendezvousBrowser/WindowsCE/Sources/StdAfx.h
mDNSWindows/Applications/RendezvousTest/Tool.c
mDNSWindows/Applications/RendezvousTest/ToolPrefixWindows.h
mDNSWindows/Applications/RendezvousTest/ToolPrefixWindowsDebug.h
mDNSWindows/DNSServices/DNSServiceDiscovery.c
mDNSWindows/DNSServices/DNSServiceDiscovery.h
mDNSWindows/DNSServices/DNSServices.c
mDNSWindows/DNSServices/DNSServices.h
mDNSWindows/mDNSWin32.c
mDNSWindows/mDNSWin32.h

index 0e843e9764ae375400d0a513e711ac29a67bf247..4a5b090601c2ec9c87b7ebc20d304a29ce6e8050 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -16,7 +16,7 @@
 
 include /Developer/Makefiles/pb_makefiles/platform.make
 
-MVERS = "mDNSResponder-58.1"
+MVERS = "mDNSResponder-58.3"
 
 install:
        cd "$(SRCROOT)/mDNSMacOSX"; pbxbuild install     OBJROOT=$(OBJROOT) SYMROOT=$(SYMROOT) DSTROOT=$(DSTROOT) MVERS=$(MVERS)
index 13ff2f08ed710928f7b630471a78b6582efca588..8edb17079c71e7af46bef81d031a6735b72fc6aa 100755 (executable)
@@ -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
     Change History (most recent first):
 
 $Log: mDNS.c,v $
+Revision 1.307.2.2  2003/12/20 01:51:40  cheshire
+<rdar://problem/3515876>: Error putting additional records into packets
+Another fix from Rampi: responseptr needs to be updated inside the "for" loop,
+after every record, not once at the end.
+
 Revision 1.307.2.1  2003/12/03 11:20:27  cheshire
 <rdar://problem/3457718>: Stop and start of a service uses old ip address (with old port number)
 
@@ -3481,10 +3484,10 @@ mDNSlocal void SendResponses(mDNS *const m)
                                                        rr->resrec.rrclass |= kDNSClass_UniqueRRSet;    // Temporarily set the cache flush bit so PutResourceRecord will set it
                                                }
                                        newptr = PutResourceRecord(&response, newptr, &response.h.numAdditionals, &rr->resrec);
+                                       if (newptr) responseptr = newptr;
                                        rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet;                   // Make sure to clear cache flush bit back to normal state
                                        }
                                }
-               if (newptr) responseptr = newptr;
        
                if (response.h.numAnswers > 0)  // We *never* send a packet with only additionals in it
                        {
index e7e56cfa6749493fc217209c0e60fd397377b831..1297a2186266da279b3d7766f0a9df92ac6021eb 100755 (executable)
@@ -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
index 0ac194ffd571e68df70dafeb8c4f660be3479536..65b6daf479bc29e3a40571fb19fccd953f19bff8 100755 (executable)
@@ -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
index 71645b2c21d40283c85da106f480acd996642824..8f07d59aac7c2195f71c728bb28fba359a0f8539 100755 (executable)
@@ -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
index 853a4aca834a3a4cf10d7b5ba156c961223c65d1..105a3985f47c2c0bad966d472dbb83093816873e 100644 (file)
@@ -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
index bd8f376016e4d21e6322f43057984a0bc4297afd..7c55ca3420ab84a90ba287a810b0144eaa6691eb 100644 (file)
@@ -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
index fc5d803ef77a2df191f5a4662e0036e00b28ea7d..d55dcd5969751ef77d67d7a98447bccad51f7720 100644 (file)
@@ -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
index efef8b85723c38c5809164a2da857648fdb4b7e9..cdb49b36bdcb67e13f3b34e64843618181f20e23 100644 (file)
@@ -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
index 1256183e33f38c18620247145a35d5b994307547..d707f9ffbf4bb28c8d4d0bca29b78f9fbc790523 100755 (executable)
@@ -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
index d05d2571fdcc69faded12cf648770330d289eba1..95f1a48cc2b36bd27a8079eede3cb3adec173faa 100644 (file)
@@ -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
index 4824cc2f41dc06b2057b6b903f81343dc7dcde34..2c31a97df156273c7f5cc38b6e6f6b0ebc2a7ebd 100644 (file)
@@ -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
index 9cc2013bc168d27656e51354c58cd65866dfe7c1..d2753617f86fb4078428a93e4cc1d29059c4b51f 100644 (file)
@@ -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
index 8f81a9f43d3f24ddb670cb96ccfa0cefcabb87d7..f58c9148dc9bfab13dde17df5b6601d16603d336 100755 (executable)
@@ -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
index a3e9cb0f95cac036bb8bc14c020efb980e292dd4..1dbe2a4ae239db9c519e61e643e2587dc585b0b2 100755 (executable)
@@ -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
index 492c5c2331336a89785e5faab9de08c24242bc2f..c340509bd53847db273aaf3a07b5bb160518d72b 100644 (file)
@@ -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
index df059d8f86af46d960430023a6968c73742e99ff..ca53bf25cabd0fbe1e0d6133edcb4f72446dea04 100644 (file)
@@ -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
index 3b2226ccc508e9468cf9818fe9d7ab8665479681..6255179964de2e9a3ce0f4d08bb6b5e924485763 100644 (file)
@@ -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
index 492c5c2331336a89785e5faab9de08c24242bc2f..c340509bd53847db273aaf3a07b5bb160518d72b 100644 (file)
@@ -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
index 928cf0225b2f250bf488972494c4a81863400933..7bb3e9051ba3b57fc9dc95f651213767f817d186 100644 (file)
@@ -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
index 9647f6f29ef3a05d1ec97dd81852f86b4964b8d2..4aae5ed382c85d1d5a9660eba5aa185c0061b195 100644 (file)
@@ -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
index 53b9e68dee301507f3de8630b5a4f4e2908fa772..6ad4471fc5989dfef9ba3bd2961fd0d2fa35bc66 100644 (file)
@@ -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
index 0552040c4c9d653065bd54cbbb4d5c6ffa436259..519a899752b2f73b521fdbd3b40d496f76cee107 100644 (file)
@@ -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
index 3a7e266589af5f772c80d14cb95268baec015d5f..e0cf87c1560b65a6c9b014c87e5a715f6b406bb8 100644 (file)
@@ -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
index bd5b11bf7b0818fbd9311320c6057c3992e0d94c..b6d3a9a8d5b85482229c049654d15963682b3c9a 100644 (file)
@@ -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
index 6ae6004e76dfe581119b72753676fb5cdcb68801..942fb6b1802216ce7d783fb7dbc84257a8ccf931 100644 (file)
@@ -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
index a4596af2a82e22031a3c29e440507eae62ec8158..eb400b1fd9a0c7fba74fddadaac23a1b3b48ab12 100644 (file)
@@ -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
index bca8eeaff2b8f4f324341586fdbc3c231ae27190..7838fc15fc138a9624733fb1daefcd3d6a7396ae 100755 (executable)
@@ -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
index 1b824ddd184816f1f44ae259d96deb1b07c935f6..f905bd79e86d860737f2c03de3d87e1edeeef4d4 100644 (file)
@@ -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
index d0af244f12dfe70d64eb12ce4beb461c2280e990..35baa0de0f78c13069575fb252dd0a47d2c856c3 100644 (file)
@@ -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,9 @@
     Change History (most recent first):
 
 $Log: daemon.c,v $
+Revision 1.134.2.3  2003/12/12 01:21:30  cheshire
+<rdar://problem/3491108> mDNSResponder should not run as root
+
 Revision 1.134.2.2  2003/12/05 00:03:35  cheshire
 <rdar://problem/3487869> Use buffer size MAX_ESCAPED_DOMAIN_NAME instead of 256
 
@@ -204,6 +205,7 @@ Add $Log header
 #include <unistd.h>
 #include <paths.h>
 #include <fcntl.h>
+#include <pwd.h>
 
 #include "DNSServiceDiscoveryRequestServer.h"
 #include "DNSServiceDiscoveryReply.h"
@@ -1658,6 +1660,13 @@ mDNSexport int main(int argc, char **argv)
        LogMsg("%s starting", mDNSResponderVersionString);
        status = mDNSDaemonInitialize();
 
+       // Now that we're finished with anything privileged, switch over to running as "nobody"
+       const struct passwd *pw = getpwnam( "nobody");
+       if ( pw != NULL)
+               setuid( pw->pw_uid);
+       else
+               status = mStatus_Incompatible;          // refuse to run as root
+
        if (status == 0)
                {
                int numevents = 0;
index 9b9c037e354bd2de5f6f4b47af1e904d877ebb45..eaed335d8531a6cb6017bd050220fe1d775a69a0 100755 (executable)
@@ -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
index a5b1ef7ffa30113af665617ef975be8d92868e8a..7277eda7c058decc09d8cba0a3444291a892f3ea 100755 (executable)
@@ -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
index 3ee14b5239a9ab16487c48f1f5d2b0b6c49abc13..186f4d332a772100b6d34abab53ab3a93fa4949d 100644 (file)
@@ -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
index 45852848a0148cd3c2fc7bc7c4b49d4439e4caec..2b7b323539a8b3177ffc1ae1b01530c5df1c8c4c 100644 (file)
@@ -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
index f5a7656a4cc4e27acb670b0fe6037e7bf8bd686d..b255cd0166c66b75bcc5271e878c3e38c6163833 100644 (file)
@@ -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
index 9c5a6537fb3d7935fc81b8b1dc83bba6e3628271..5cc63fc937f7181dda6b3814d25496247685f3c0 100644 (file)
@@ -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
index 193272d27237ed33d9a9bffc1b0f23e4f029b335..bf223d1eb4c256ef82474066cad77c7d1c1cd04f 100755 (executable)
@@ -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
index 85613882e1d850979e8664c4f72a3ab43c0edf88..a0531bccc67dbfc6ade814e04a0ca78be1373d3d 100644 (file)
@@ -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
index d9b20c5bb569ae93f1c448c0aad0706ad964a3cb..4274a46cc37686dda140d49e46ccc9ada1052bad 100644 (file)
@@ -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
index f773796a58504e7863328595801001e53b84ff99..412f82932a1d88a79a0bd0bfe76a960e8921dbd7 100644 (file)
@@ -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
index 3b7aff09fd1dfab03fa3adf1bb98356e8ac47506..8a90d249376ff988bc126df6a05de48742a092e2 100644 (file)
@@ -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
index 193b082574f628c5ff3c4fd92bf858dcc4daef69..a9824239d142d3dc0a70c723ae0bc5ef331105cf 100644 (file)
@@ -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
index d6446755f0560fa3c182a6a86a6799a4ba0e62d4..6130e0c925005532c7630fcb730a6e4e35d80a78 100755 (executable)
@@ -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
index 3d289e66d05d1fb2306a2cc0f262d81a61bc36fa..9092fdd1867aafa8d5d0276e6fcdb27b97c3808e 100755 (executable)
@@ -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
index 915acb72b174af0779849d650efe4fdeb98b0860..a2545683ad6fc4d51863af16f822797cd6ae317c 100755 (executable)
@@ -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
index 26699f086029b7ad68571015c649cd753dfb8e11..fa9bda0682509ab3d30f275583f6b074e7221f7e 100755 (executable)
@@ -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
index a764aa0f9baf3738bb7ecd6a0b080dd959f946e0..21d13f1966fa28b7f51d26463ee3ce92e86c9bb2 100755 (executable)
@@ -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/dns_sd.h b/mDNSShared/dns_sd.h
new file mode 100755 (executable)
index 0000000..eaed335
--- /dev/null
@@ -0,0 +1,1006 @@
+/*
+ * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+
+$Log: dns_sd.h,v $
+Revision 1.3  2003/08/12 19:51:51  cheshire
+Update to APSL 2.0
+
+
+ */
+
+#ifndef _DNS_SD_H
+#define _DNS_SD_H
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <stdint.h>
+#include <netinet/in.h>
+
+
+/* DNSServiceRef, DNSRecordRef
+ *
+ * Opaque internal data types.
+ * Note: client is responsible for serializing access to these structures if
+ * they are shared between concurrent threads.
+ */
+
+typedef struct _DNSServiceRef_t *DNSServiceRef;
+typedef struct _DNSRecordRef_t *DNSRecordRef;
+
+/* General flags used in functions defined below */
+enum
+    {
+    kDNSServiceFlagsMoreComing          = 1,
+    kDNSServiceFlagsFinished            = 0,  /* i.e. bit not set */
+    /* MoreComing indicates to a Browse callback that another result is
+     * queued.  Applications should not update their UI to display browse
+     * results when the MoreComing flag is set, instead deferring the update
+     * until the callback's flag is Finished. */
+
+    kDNSServiceFlagsAdd                 = 2,
+    kDNSServiceFlagsDefault             = 4,
+    kDNSServiceFlagsRemove              = 0,  /* i.e. bit not set */
+    /* Flags for domain enumeration and browse reply callbacks.
+     * "Default" applies only to enumeration and is only valid in
+     * conjuction with "Add" 
+     */
+
+    kDNSServiceFlagsNoAutoRename        = 8,
+    kDNSServiceFlagsAutoRename          = 0,  /* i.e. bit not set */
+    /* Flag for specifying renaming behavior on name conflict when registering
+     * non-shared records. NoAutorename is only valid if a name is explicitly
+     * specified when registering a service (ie the default name is not used.)
+     */
+
+
+    kDNSServiceFlagsShared              = 16,
+    kDNSServiceFlagsUnique              = 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).
+     */
+
+    kDNSServiceFlagsBrowseDomains       = 64,
+    kDNSServiceFlagsRegistrationDomains = 128
+    /* Flags for specifying domain enumeration type in DNSServiceEnumerateDomains.
+     * BrowseDomains enumerates domains recommended for browsing, RegistrationDomains
+     * enumerates domains recommended for registration.
+     */
+    };
+
+/* possible error code values */
+enum
+    {
+    kDNSServiceErr_NoError             = 0,
+    kDNSServiceErr_Unknown             = -65537,       /* 0xFFFE FFFF */
+    kDNSServiceErr_NoSuchName          = -65538,
+    kDNSServiceErr_NoMemory            = -65539,
+    kDNSServiceErr_BadParam            = -65540,
+    kDNSServiceErr_BadReference        = -65541,
+    kDNSServiceErr_BadState            = -65542,
+    kDNSServiceErr_BadFlags            = -65543,
+    kDNSServiceErr_Unsupported         = -65544,
+    kDNSServiceErr_NotInitialized      = -65545,
+    kDNSServiceErr_AlreadyRegistered   = -65547,
+    kDNSServiceErr_NameConflict        = -65548,
+    kDNSServiceErr_Invalid             = -65549,
+    kDNSServiceErr_Incompatible        = -65551,        /* client library incompatible with daemon */
+    kDNSServiceErr_BadinterfaceIndex   = -65552
+    /* mDNS Error codes are in the range
+     * FFFE FF00 (-65792) to FFFE FFFF (-65537) */
+    };
+    
+
+/* Maximum length, in bytes, of a domain name represented as an escaped C-String */
+#define kDNSServiceMaxDomainName 1005
+
+
+typedef uint32_t DNSServiceFlags;
+typedef int32_t DNSServiceErrorType;
+
+
+/*********************************************************************************************
+ *
+ * Unix Domain Socket access, DNSServiceRef deallocation, and data processing functions
+ *
+ *********************************************************************************************/
+
+
+/* DNSServiceRefSockFD()
+ *
+ * Access underlying Unix domain socket for an initialized DNSServiceRef.
+ * The DNS Service Discovery implmementation uses this socket to communicate between 
+ * the client and the mDNSResponder daemon.  The application MUST NOT directly read from
+ * or write to this socket.  Access to the socket is provided so that it can be used as a
+ * run loop source, or in a select() loop: when data is available for reading on the socket, 
+ * DNSServiceProcessResult() should be called, which will extract the daemon's reply from 
+ * the socket, and pass it to the appropriate application callback.  By using a run loop or
+ * select(), results from the daemon can be processed asynchronously.  Without using these
+ * constructs, DNSServiceProcessResult() will block until the response from the daemon arrives.
+ * The client is responsible for ensuring that the data on the socket is processed in a timely
+ * fashion - the daemon may terminate its connection with a client that does not clear its
+ * socket buffer.
+ *
+ * sdRef:            A DNSServiceRef initialized by any of the DNSService calls.
+ * 
+ * return value:    The DNSServiceRef's underlying socket descriptor, or -1 on 
+ *                  error.
+ */
+int DNSServiceRefSockFD(DNSServiceRef sdRef);
+
+/* DNSServiceProcessResult()
+ *
+ * Read a reply from the daemon, calling the appropriate application callback.  This call will
+ * block until the daemon's response is received.  Use DNSServiceRefSockFD() in 
+ * 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.
+ *
+ * sdRef:           A DNSServiceRef initialized by any of the DNSService calls
+ *                  that take a callback parameter.
+ *
+ * return value:    Returns kDNSServiceErr_NoError on success, otherwise returns
+ *                  an error code indicating the specific failure that occurred.
+ */
+
+DNSServiceErrorType DNSServiceProcessResult(DNSServiceRef sdRef);
+
+/* DNSServiceRefDeallocate()
+ *
+ * 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.  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: 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.
+ *
+ * sdRef:           A DNSServiceRef initialized by any of the DNSService calls.
+ *
+ */
+
+void DNSServiceRefDeallocate(DNSServiceRef sdRef); 
+
+
+/*********************************************************************************************
+ * 
+ * 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.
+ *
+ *
+ * DNSServiceDomainEnumReply Callback Parameters:
+ *
+ * sdRef:           The DNSServiceRef initialized by DNSServiceEnumerateDomains().
+ *
+ * flags:           Possible values are:
+ *                  1 (MoreComing)
+ *                  2 (Add/Remove)
+ *                  4 (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 kDNSServiceErr_NoError (0) on success, otherwise indicates 
+ *                  the failure that occurred (other parameters are undefined if errorCode is nonzero).
+ *
+ * replyDomain:     The name of the domain.
+ *
+ * context:         The context pointer passed to DNSServiceEnumerateDomains.
+ * 
+ */
+
+typedef void (*DNSServiceDomainEnumReply)
+    (
+    DNSServiceRef                       sdRef,
+    DNSServiceFlags                     flags,
+    uint32_t                            interfaceIndex,
+    DNSServiceErrorType                 errorCode,
+    const char                          *replyDomain,  
+    void                                *context       
+    );
+    
+/* DNSServiceEnumerateDomains() Parameters:
+ *
+ *
+ * sdRef:           A pointer to an uninitialized sdRef.  May be passed to 
+ *                  DNSServiceRefDeallocate() to cancel the enumeration.
+ *
+ * flags:           Possible values are:
+ *                  0 (BrowseDomains) to enumerate domains recommended for browsing.
+ *                  32 (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 function to be called when a domain is found or the call asynchronously 
+ *                  fails.
+ *
+ * context:         An application context pointer which is passed to the callback function 
+ *                  (may be NULL).
+ *
+ * return value:    Returns kDNSServiceErr_NoError on succeses (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 DNSServiceEnumerateDomains
+    (
+    DNSServiceRef                       *sdRef,
+    DNSServiceFlags                     flags,
+    uint32_t                            interfaceIndex,
+    DNSServiceDomainEnumReply           callBack,
+    void                                *context  /* may be NULL */
+    );
+
+/*********************************************************************************************
+ *
+ *  Service Registration
+ *
+ *********************************************************************************************/
+/* Register a service that is discovered via Browse() and Resolve() calls.
+ *
+ *
+ * DNSServiceRegisterReply() Callback Parameters:
+ * 
+ * sdRef:           The DNSServiceRef initialized by DNSServiceRegister().
+ *
+ * flags:           Currently unused, reserved for future use.
+ *
+ * errorCode:       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.
+ *
+ * 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 DNSServiceRegister(), this indicates the default domain
+ *                  on which the service was registered).
+ *
+ * context:         The context pointer that was passed to the callout.
+ *
+ */
+typedef void (*DNSServiceRegisterReply)
+    (
+    DNSServiceRef                       sdRef,
+    DNSServiceFlags                     flags,
+    DNSServiceErrorType                 errorCode,
+    const char                          *name,     
+    const char                          *regtype,  
+    const char                          *domain,   
+    void                                *context  
+    );
+    
+/* DNSServiceRegister()  Parameters:
+ *
+ * sdRef:           A pointer to an uninitialized sdRef.  If this call succeeds, the reference
+ *                  may be passed to 
+ *                  DNSServiceRefDeallocate() to deregister the service.
+ *        
+ * interfaceIndex:  If non-zero, specifies the interface on which to register the service
+ *                  (the index for a given interface is determined via the if_nametoindex()
+ *                  family of calls.)  Most applications will pass 0 to register on all 
+ *                  available interfaces.  Pass -1 to register a service only on the local 
+ *                  machine (service will not be visible to remote hosts.)
+ *
+ * flags:           Indicates the renaming behavior on name conflict (most applications
+ *                  will pass 0).  See flag definitions above for details.
+ *
+ * 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".
+ *
+ * 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 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.
+ *
+ * txtLen:          The length of the txtRecord, in bytes.  Must be zero if the txtRecord is NULL.
+ *
+ * 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 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().
+ *
+ * context:         An application context pointer which is passed to the callback function 
+ *                  (may be NULL).
+ *
+ * return value:    Returns kDNSServiceErr_NoError on succeses (any subsequent, asynchronous
+ *                  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                       *sdRef,
+    DNSServiceFlags                     flags,
+    uint32_t                            interfaceIndex,
+    const char                          *name,         /* may be NULL */
+    const char                          *regtype,  
+    const char                          *domain,       /* may be NULL */
+    const char                          *host,         /* may be NULL */
+    uint16_t                            port,
+    uint16_t                            txtLen,
+    const void                          *txtRecord,    /* may be NULL */
+    DNSServiceRegisterReply             callBack,      /* may be NULL */
+    void                                *context       /* may be NULL */
+    );
+    
+/* DNSServiceAddRecord()
+ *
+ * Add a record to a registered service.  The name of the record will be the same as the
+ * registered service's name.
+ * The record can later be updated or deregistered by passing the RecordRef initialized 
+ * by this function to DNSServiceUpdateRecord() or DNSServiceRemoveRecord().
+ *
+ * 
+ * Parameters;
+ *
+ * sdRef:           A DNSServiceRef initialized by DNSServiceRegister().
+ * 
+ * RecordRef:       A pointer to an uninitialized DNSRecordRef.  Upon succesfull completion of this 
+ *                  call, this ref may be passed to DNSServiceUpdateRecord() or DNSServiceRemoveRecord().
+ *
+ * flags:           Currently ignored, reserved for future use.
+ *
+ * rrtype:          The type of the record (e.g. TXT, SRV, etc), as defined in nameser.h.
+ *
+ * rdlen:           The length, in bytes, of the rdata.
+ *
+ * rdata:           The raw rdata to be contained in the added resource record.
+ *
+ * ttl:             The time to live of the resource record, in seconds.
+ *
+ * return value:    Returns kDNSServiceErr_NoError on success, otherwise returns an
+ *                  error code indicating the error that occurred (the RecordRef is not initialized).
+ */
+
+DNSServiceErrorType DNSServiceAddRecord
+    (
+    DNSServiceRef                       sdRef,
+    DNSRecordRef                        *RecordRef,
+    DNSServiceFlags                     flags,
+    uint16_t                            rrtype,
+    uint16_t                            rdlen,
+    const void                          *rdata,
+    uint32_t                            ttl
+    );
+
+/* DNSServiceUpdateRecord
+ *
+ * Update a registered resource record.  The record must either be:
+ *   - The primary txt record of a service registered via DNSServiceRegister()
+ *   - A record added to a registered service via DNSServiceAddRecord()
+ *   - An individual record registered by DNSServiceRegisterRecord()
+ *
+ *
+ * Parameters:
+ *
+ * sdRef:           A DNSServiceRef that was initialized by DNSServiceRegister()
+ *                  or DNSServiceCreateConnection().
+ *
+ * RecordRef:       A DNSRecordRef initialized by DNSServiceAddRecord, or NULL to update the
+ *                  service's primary txt record.
+ *
+ * flags:           Currently ignored, reserved for future use.
+ *
+ * rdlen:           The length, in bytes, of the new rdata.
+ *
+ * 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:    Returns kDNSServiceErr_NoError on success, otherwise returns an
+ *                  error code indicating the error that occurred.
+ */
+
+DNSServiceErrorType DNSServiceUpdateRecord
+    (
+    DNSServiceRef                       sdRef,
+    DNSRecordRef                        RecordRef,     /* may be NULL */
+    DNSServiceFlags                     flags,
+    uint16_t                            rdlen,
+    const void                          *rdata,
+    uint32_t                            ttl
+    );
+
+/* DNSServiceRemoveRecord
+ *
+ * Remove a record previously added to a service record set via DNSServiceAddRecord(), or deregister 
+ * an record registered individually via DNSServiceRegisterRecord().
+ *
+ * Parameters:
+ *
+ * sdRef:           A DNSServiceRef initialized by DNSServiceRegister() (if the
+ *                  record being removed was registered via DNSServiceAddRecord()) or by
+ *                  DNSServiceCreateConnection() (if the record being removed was registered via
+ *                  DNSServiceRegisterRecord()).
+ *
+ * recordRef:       A DNSRecordRef initialized by a successful call to DNSServiceAddRecord() 
+ *                  or DNSServiceRegisterRecord().
+ *   
+ * flags:           Currently ignored, reserved for future use.
+ *
+ * return value:    Returns kDNSServiceErr_NoError on success, otherwise returns an
+ *                  error code indicating the error that occurred.
+ */
+
+DNSServiceErrorType DNSServiceRemoveRecord
+    (
+    DNSServiceRef                 sdRef,
+    DNSRecordRef                  RecordRef,
+    DNSServiceFlags               flags
+    );
+
+
+/*********************************************************************************************
+ *
+ *  Service Discovery
+ *
+ *********************************************************************************************/
+
+
+/* Browse for instances of a service.
+ *
+ *
+ * DNSServiceBrowseReply() Parameters:
+ *
+ * sdRef:           The DNSServiceRef initialized by DNSServiceBrowse().
+ *
+ * flags:           Possible values are MoreComing and Add/Remove.  See flag definitions
+ *                  for details.
+ *
+ * interfaceIndex:  The interface on which the service is advertised.  This index should
+ *                  be passed to DNSServiceResolve() when resolving the service. 
+ *
+ * errorCode:       Will be kDNSServiceErr_NoError (0) on success, otherwise will 
+ *                  indicate the failure that occurred.  Other parameters are undefined if
+ *                  the errorCode is nonzero.
+ *
+ * serviceName:     The service name discovered.
+ *
+ * regtype:         The service type, as passed in to DNSServiceBrowse().
+ *
+ * domain:          The domain on which the service was discovered (if the application did not
+ *                  specify a domain in DNSServicBrowse(), this indicates the domain on which the
+ *                  service was discovered.)
+ *
+ * context:         The context pointer that was passed to the callout.
+ *
+ */
+
+typedef void (*DNSServiceBrowseReply)
+    (
+    DNSServiceRef                       sdRef,
+    DNSServiceFlags                     flags,
+    uint32_t                            interfaceIndex,
+    DNSServiceErrorType                 errorCode,
+    const char                          *serviceName,  
+    const char                          *regtype,    
+    const char                          *replyDomain,  
+    void                                *context  
+    );
+    
+/* DNSServiceBrowse() Parameters:
+ *
+ * sdRef:           A pointer to an uninitialized sdRef.  May be passed to 
+ *                  DNSServiceRefDeallocate() to terminate the browse.
+ *
+ * flags:           Currently ignored, reserved for future use.
+ *
+ * interfaceIndex:  If non-zero, specifies the interface on which to browse for services
+ *                  (the index for a given interface is determined via the if_nametoindex()
+ *                  family of calls.)  Most applications will pass 0 to browse on all available
+ *                  interfaces.  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 function to be called when an instance of the service being browsed for 
+ *                  is found, or if the call asynchronously fails.
+ *
+ * context:         An application context pointer which is passed to the callback function 
+ *                  (may be NULL).
+ *
+ * return value:    Returns kDNSServiceErr_NoError on succeses (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                       *sdRef,
+    DNSServiceFlags                     flags,
+    uint32_t                            interfaceIndex,
+    const char                          *regtype,   
+    const char                          *domain,    /* may be NULL */
+    DNSServiceBrowseReply               callBack,
+    void                                *context    /* may be NULL */
+    );
+
+/* DNSServiceResolve()
+ *
+ * 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.
+ *
+ * DNSServiceResolveReply Callback Parameters:
+ *
+ * sdRef:           The DNSServiceRef initialized by DNSServiceResolve().
+ *
+ * flags:           Possible values are MoreComing and Add/Remove.  See flag definitions
+ *                  for details.
+ *
+ * interfaceIndex:  The interface on which the service was resolved.   
+ *
+ * errorCode:       Will be kDNSServiceErr_NoError (0) on success, otherwise will 
+ *                  indicate the failure that occurred.  Other parameters are undefined if
+ *                  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 number on which connections are accepted for this service.
+ *
+ * txtLen:          The length of the txt record, in bytes.
+ *
+ * txtRecord:       The service's primary txt record, in standard txt record format.
+ *
+ * context:         The context pointer that was passed to the callout.
+ *
+ */
+
+typedef void (*DNSServiceResolveReply)
+    (
+    DNSServiceRef                       sdRef,
+    DNSServiceFlags                     flags,
+    uint32_t                            interfaceIndex,
+    DNSServiceErrorType                 errorCode,
+    const char                          *fullname,    
+    const char                          *hosttarget,
+    uint16_t                            port,
+    uint16_t                            txtLen,
+    const char                          *txtRecord,
+    void                                *context  
+    );
+  
+/* DNSServiceResolve() Parameters
+ *
+ * sdRef:           A pointer to an uninitialized sdRef.  May be passed to 
+ *                  DNSServiceRefDeallocate() to terminate the resolve.
+ *
+ * flags:           Currently ignored, reserved for future use.
+ *
+ * interfaceIndex:  The interface on which to resolve the service.  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 function to be called when a result is found, or if the call 
+ *                  asynchronously fails.
+ *
+ * context:         An application context pointer which is passed to the callback function 
+ *                  (may be NULL).
+ *
+ * return value:    Returns kDNSServiceErr_NoError on succeses (any subsequent, asynchronous
+ *                  errors are delivered to the callback), otherwise returns an error code indicating 
+ *                  the error that occurred (the callback is never invoked and the DNSServiceRef
+ *                  is not initialized.)
+ */
+
+
+DNSServiceErrorType DNSServiceResolve
+    (
+    DNSServiceRef                       *sdRef,
+    DNSServiceFlags                     flags,
+    uint32_t                            interfaceIndex,
+    const char                          *name,     
+    const char                          *regtype,  
+    const char                          *domain,   
+    DNSServiceResolveReply              callBack,
+    void                                *context  /* may be NULL */
+    );
+
+
+/*********************************************************************************************
+ *
+ *  Special Purpose Calls (most applications will not use these)
+ *
+ *********************************************************************************************/
+
+/* 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.)
+ */
+
+/* DNSServiceConstructFullName()
+ *
+ * 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.
+ *
+ * Parameters:
+ *
+ * fullName:        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.
+ *
+ * service:         The service name - any dots or slashes must NOT be escaped.
+ *                  May be NULL (to construct a PTR record name, e.g.
+ *                  "_ftp._tcp.apple.com").
+ *
+ * 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.
+ *
+ * return value:    Returns 0 on success, -1 on error.
+ *
+ */
+int DNSServiceConstructFullName 
+    (
+    char                            *fullName,
+    const char                      *service,      /* may be NULL */
+    const char                      *regtype,
+    const char                      *domain
+    );
+    
+/* DNSServiceCreateConnection()
+ *
+ * Create a connection to the daemon allowing efficient registration of
+ * multiple individual records.
+ *
+ *
+ * Parameters:
+ *
+ * sdRef:           A pointer to an uninitialized DNSServiceRef.  Deallocating
+ *                  the reference (via DNSServiceRefDeallocate()) severs the
+ *                  connection and deregisters all records registered on this connection.
+ *
+ * return value:    Returns kDNSServiceErr_NoError on success, otherwise returns
+ *                  an error code indicating the specific failure that occurred (in which
+ *                  case the DNSServiceRef is not initialized).
+ */
+
+DNSServiceErrorType DNSServiceCreateConnection(DNSServiceRef *sdRef);
+
+
+/* DNSServiceRegisterRecord
+ *
+ * Register an individual resource record on a connected DNSServiceRef.  
+ *
+ * Note that name conflicts occurring for records registered via this call must be handled
+ * by the client in the callback.
+ *
+ *
+ * DNSServiceRegisterRecordReply() parameters:
+ *
+ * sdRef:           The connected DNSServiceRef initialized by
+ *                  DNSServiceDiscoveryConnect().
+ * 
+ * RecordRef:       The DNSRecordRef initialized by DNSServiceRegisterRecord().
+ *
+ * flags:           Currently unused, reserved for future use.
+ *
+ * errorCode:       Will be kDNSServiceErr_NoError on success, otherwise will 
+ *                  indicate the failure that occurred (including name conflicts.)
+ *                  Other parameters are undefined if errorCode is nonzero.
+ *
+ * context:         The context pointer that was passed to the callout.
+ *
+ */
+ typedef void (*DNSServiceRegisterRecordReply)
+    (
+    DNSServiceRef                       sdRef,
+    DNSRecordRef                        RecordRef,
+    DNSServiceFlags                     flags,
+    DNSServiceErrorType                 errorCode,
+    void                                *context  
+    );
+
+/* DNSServiceRegisterRecord() Parameters:         
+ *
+ * sdRef:           A DNSServiceRef initialized by DNSServiceCreateConnection().
+ *
+ * RecordRef:       A pointer to an uninitialized DNSRecordRef.  Upon succesfull completion of this 
+ *                  call, this ref may be passed to DNSServiceUpdateRecord() or DNSServiceRemoveRecord().
+ *                  (To deregister ALL records registered on a single connected DNSServiceRef 
+ *                  and deallocate each of their corresponding DNSServiceRecordRefs, call
+ *                  DNSServiceRefDealloocate()).
+ *
+ * flags:           Possible values are Shared/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).
+ *
+ * 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.
+ *
+ * callBack:        The function to be called when a result is found, or if the call 
+ *                  asynchronously fails (e.g. because of a name conflict.)
+ *
+ * context:         An application context pointer which is passed to the callback function 
+ *                  (may be NULL).
+ *
+ * return value:    Returns kDNSServiceErr_NoError on succeses (any subsequent, asynchronous
+ *                  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.)
+ */
+
+DNSServiceErrorType DNSServiceRegisterRecord
+    (
+    DNSServiceRef                       sdRef,
+    DNSRecordRef                        *RecordRef,
+    DNSServiceFlags                     flags,
+    uint32_t                            interfaceIndex,
+    const char                          *fullname,   
+    uint16_t                            rrtype,
+    uint16_t                            rrclass,
+    uint16_t                            rdlen,
+    const void                          *rdata,
+    uint32_t                            ttl,
+    DNSServiceRegisterRecordReply       callBack,
+    void                                *context    /* may be NULL */
+    );
+
+
+/* DNSServiceQueryRecord
+ *
+ * Query for an arbitrary DNS record.
+ *
+ *
+ * DNSServiceQueryRecordReply() Callback Parameters:
+ *
+ * sdRef:           The DNSServiceRef initialized by DNSServiceQueryRecord().
+ * 
+ * flags:           Possible values are Finished/MoreComing.
+ *
+ * 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).
+ *
+ * rdlen:           The length, in bytes, of the resource record rdata.
+ *
+ * rdata:           The raw rdata of the resource record.
+ *
+ * ttl:             The resource record's time to live, in seconds.
+ *
+ * context:         The context pointer that was passed to the callout.
+ *
+ */
+
+typedef void (*DNSServiceQueryRecordReply)
+    (
+    DNSServiceRef                       DNSServiceRef,
+    DNSServiceFlags                     flags,
+    uint32_t                            interfaceIndex,
+    DNSServiceErrorType                 errorCode,
+    const char                          *fullname,    
+    uint16_t                            rrtype,
+    uint16_t                            rrclass,
+    uint16_t                            rdlen,
+    const void                          *rdata,
+    uint32_t                            ttl,
+    void                                *context  
+    );
+
+/* DNSServiceQueryRecord() Parameters:
+ *
+ * sdRef:           A pointer to an uninitialized DNSServiceRef.
+ *
+ * flags:           Currently unused, reserved for future use.
+ * 
+ * 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 function to be called when a result is found, or if the call 
+ *                  asynchronously fails.
+ *
+ * context:         An application context pointer which is passed to the callback function 
+ *                  (may be NULL).
+ *
+ * return value:    Returns kDNSServiceErr_NoError on succeses (any subsequent, asynchronous
+ *                  errors are delivered to the callback), otherwise returns an error code indicating 
+ *                  the error that occurred (the callback is never invoked and the DNSServiceRef
+ *                  is not initialized.)
+ */
+DNSServiceErrorType DNSServiceQueryRecord
+    (
+    DNSServiceRef                       *sdRef,
+    DNSServiceFlags                     flags,
+    uint32_t                            interfaceIndex,
+    const char                          *fullname,     
+    uint16_t                            rrtype,
+    uint16_t                            rrclass,
+    DNSServiceQueryRecordReply          callBack,
+    void                                *context  /* may be NULL */
+    );
+
+/* DNSServiceReconfirmRecord
+ *
+ * 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).
+ *
+ * rdlen:           The length, in bytes, of the resource record rdata.
+ *
+ * rdata:           The raw rdata of the resource record.
+ *
+ */
+void DNSServiceReconfirmRecord
+    (
+    DNSServiceFlags                    flags,
+    uint32_t                           interfaceIndex,
+    const char                         *fullname,   
+    uint16_t                           rrtype,
+    uint16_t                           rrclass,
+    uint16_t                           rdlen,
+    const void                         *rdata
+    );
+
+
+#endif  // _DNS_SD_H
+
diff --git a/mDNSShared/dnssd_clientstub.c b/mDNSShared/dnssd_clientstub.c
new file mode 100755 (executable)
index 0000000..7277eda
--- /dev/null
@@ -0,0 +1,998 @@
+/*
+ * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+
+$Log: dnssd_clientstub.c,v $
+Revision 1.9  2003/08/15 21:30:39  cheshire
+Bring up to date with LibInfo version
+
+Revision 1.8  2003/08/13 23:54:52  ksekar
+Bringing dnssd_clientstub.c up to date with Libinfo, per radar 3376640
+
+Revision 1.7  2003/08/12 19:56:25  cheshire
+Update to APSL 2.0
+
+ */
+
+#include "dnssd_ipc.h"
+
+#define CTL_PATH_PREFIX "/tmp/dnssd_clippath."
+// error socket (if needed) is named "dnssd_clipath.[pid].xxx:n" where xxx are the
+// last 3 digits of the time (in seconds) and n is the 6-digit microsecond time
+
+// general utility functions
+static DNSServiceRef connect_to_server(void);
+DNSServiceErrorType deliver_request(void *msg, DNSServiceRef sdr, int reuse_sd);
+static ipc_msg_hdr *create_hdr(int op, int *len, char **data_start, int reuse_socket);
+static int my_read(int sd, char *buf, int len);
+static int my_write(int sd, char *buf, int len);
+static int domain_ends_in_dot(const char *dom);
+// server response handlers
+static void handle_query_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *msg);
+static void handle_browse_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data);
+static void handle_regservice_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data);
+static void handle_regrecord_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data);
+static void handle_enumeration_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data);
+static void handle_resolve_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data);
+
+typedef struct _DNSServiceRef_t
+    {
+    int sockfd;  // connected socket between client and daemon
+    int op;      // request/reply_op_t
+    process_reply_callback process_reply;
+    void *app_callback;
+    void *app_context;
+    uint32_t max_index;  //largest assigned record index - 0 if no additl. recs registered
+    } _DNSServiceRef_t;
+
+typedef struct _DNSRecordRef_t
+    {
+    void *app_context;
+    DNSServiceRegisterRecordReply app_callback;
+    DNSRecordRef recref;
+    int record_index;  // index is unique to the ServiceDiscoveryRef
+    DNSServiceRef sdr;
+    } _DNSRecordRef_t;
+
+
+// exported functions
+
+int DNSServiceRefSockFD(DNSServiceRef sdRef)
+    {
+    if (!sdRef) return -1;
+    return sdRef->sockfd;
+    }
+
+// handle reply from server, calling application client callback.  If there is no reply
+// from the daemon on the socket contained in sdRef, the call will block.
+DNSServiceErrorType DNSServiceProcessResult(DNSServiceRef sdRef)
+    {
+    ipc_msg_hdr hdr;
+    char *data;
+
+    if (!sdRef || sdRef->sockfd < 0 || !sdRef->process_reply) 
+        return kDNSServiceErr_BadReference;
+
+    if (my_read(sdRef->sockfd, (void *)&hdr, sizeof(hdr)) < 0) 
+        return kDNSServiceErr_Unknown;
+    if (hdr.version != VERSION)
+        return kDNSServiceErr_Incompatible;
+    data = malloc(hdr.datalen);
+    if (!data) return kDNSServiceErr_NoMemory;
+    if (my_read(sdRef->sockfd, data, hdr.datalen) < 0) 
+        return kDNSServiceErr_Unknown;
+    sdRef->process_reply(sdRef, &hdr, data);
+    return kDNSServiceErr_Unknown;
+    }
+
+
+void DNSServiceRefDeallocate(DNSServiceRef sdRef)
+    {
+    if (!sdRef) return;
+    if (sdRef->sockfd > 0) close(sdRef->sockfd);
+    free(sdRef);
+    }
+
+
+DNSServiceErrorType DNSServiceResolve
+    (
+    DNSServiceRef                       *sdRef,
+    const DNSServiceFlags               flags,
+    const uint32_t                      interfaceIndex,
+    const char                          *name,
+    const char                          *regtype,
+    const char                          *domain,
+    const DNSServiceResolveReply        callBack,
+    void                                *context
+    )
+    {
+    char *msg = NULL, *ptr;
+    int len;
+    ipc_msg_hdr *hdr;
+    DNSServiceRef sdr;
+    DNSServiceErrorType err;
+    
+    if (!sdRef) return kDNSServiceErr_BadParam;
+    *sdRef = NULL;
+    
+    // calculate total message length
+    len = sizeof(flags);
+    len += sizeof(interfaceIndex);
+    len += strlen(name) + 1;
+    len += strlen(regtype) + 1;
+    len += strlen(domain) + 1;
+
+    hdr = create_hdr(resolve_request, &len, &ptr, 1);
+    if (!hdr) goto error;
+    msg = (void *)hdr;
+
+    put_flags(flags, &ptr);
+    put_long(interfaceIndex, &ptr);
+    put_string(name, &ptr);
+    put_string(regtype, &ptr);
+    put_string(domain, &ptr);
+    
+    sdr = connect_to_server();
+    if (!sdr) goto error;
+    err = deliver_request(msg, sdr, 1);
+    if (err)
+        {
+        DNSServiceRefDeallocate(sdr);
+        return err;
+        }
+    sdr->op = resolve_request;
+    sdr->process_reply = handle_resolve_response;
+    sdr->app_callback = callBack;
+    sdr->app_context = context;
+    *sdRef = sdr;
+    
+    return err;
+
+error:
+    if (msg) free(msg);
+    if (*sdRef) { free(*sdRef);  *sdRef = NULL; }
+    return kDNSServiceErr_Unknown;
+    }
+    
+    
+static void handle_resolve_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data)
+    {
+    DNSServiceFlags flags;
+    char fullname[kDNSServiceMaxDomainName];
+    char target[kDNSServiceMaxDomainName];
+    uint16_t port, txtlen;
+    uint32_t ifi;
+    DNSServiceErrorType err;
+    char *txtrecord;
+    
+    (void)hdr;          //unused
+    
+    flags = get_flags(&data);
+    ifi = get_long(&data);
+    err = get_error_code(&data);
+    get_string(&data, fullname, kDNSServiceMaxDomainName);
+    get_string(&data, target, kDNSServiceMaxDomainName);
+    port = get_short(&data);
+    txtlen = get_short(&data);
+    txtrecord = get_rdata(&data, txtlen);
+    
+    ((DNSServiceResolveReply)sdr->app_callback)(sdr, flags, ifi, err, fullname, target, port, txtlen, txtrecord, sdr->app_context);
+    }
+    
+    
+
+
+DNSServiceErrorType DNSServiceQueryRecord
+(
+ DNSServiceRef                          *sdRef,
+ const DNSServiceFlags                   flags,
+ const uint32_t                         interfaceIndex,
+ const char                             *name,
+ const uint16_t                         rrtype,
+ const uint16_t                         rrclass,
+ const DNSServiceQueryRecordReply       callBack,
+ void                                   *context
+ )
+    {
+    char *msg = NULL, *ptr;
+    int len;
+    ipc_msg_hdr *hdr;
+    DNSServiceRef sdr;
+    DNSServiceErrorType err;
+    
+    if (!sdRef) return kDNSServiceErr_BadParam;
+    *sdRef = NULL;
+
+    if (!name) name = "\0";
+
+    // calculate total message length
+    len = sizeof(flags);
+    len += sizeof(uint32_t);  //interfaceIndex
+    len += strlen(name) + 1;
+    len += 2 * sizeof(uint16_t);  // rrtype, rrclass
+
+    hdr = create_hdr(query_request, &len, &ptr, 1);
+    if (!hdr) goto error;
+    msg = (void *)hdr;
+
+    put_flags(flags, &ptr);
+    put_long(interfaceIndex, &ptr);
+    put_string(name, &ptr);
+    put_short(rrtype, &ptr);
+    put_short(rrclass, &ptr);
+
+    sdr = connect_to_server();
+    if (!sdr) goto error;
+    err = deliver_request(msg, sdr, 1);
+    if (err)
+        {
+        DNSServiceRefDeallocate(sdr);
+        return err;
+        }
+
+    sdr->op = query_request;
+    sdr->process_reply = handle_query_response;
+    sdr->app_callback = callBack;
+    sdr->app_context = context;
+    *sdRef = sdr;
+    return err;
+
+error:
+    if (msg) free(msg);
+    if (*sdRef) { free(*sdRef);  *sdRef = NULL; }
+    return kDNSServiceErr_Unknown;
+    }
+
+
+static void handle_query_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data)
+    {
+    DNSServiceFlags flags;
+    uint32_t interfaceIndex, ttl;
+    DNSServiceErrorType errorCode;
+    char name[256]; 
+    uint16_t rrtype, rrclass, rdlen;
+    char *rdata;
+    (void)hdr;//Unused
+
+    flags = get_flags(&data);
+    interfaceIndex = get_long(&data);
+    errorCode = get_error_code(&data);
+    (get_string(&data, name, 256) < 0);
+    rrtype = get_short(&data);
+    rrclass = get_short(&data);
+    rdlen = get_short(&data);
+    rdata = get_rdata(&data, rdlen);
+    ttl = get_long(&data);
+    if (!rdata) return;
+    ((DNSServiceQueryRecordReply)sdr->app_callback)(sdr, flags, interfaceIndex, errorCode, name, rrtype, rrclass,
+                                              rdlen, rdata, ttl, sdr->app_context);
+    return;
+    }
+
+DNSServiceErrorType DNSServiceBrowse
+(
+ DNSServiceRef                      *sdRef,
+ const DNSServiceFlags              flags,
+ const uint32_t                     interfaceIndex,
+ const char                         *regtype,
+ const char                         *domain,
+ const DNSServiceBrowseReply        callBack,
+ void                               *context
+ )
+    {
+    char *msg = NULL, *ptr;
+    int len;
+    ipc_msg_hdr *hdr;
+    DNSServiceRef sdr;
+    DNSServiceErrorType err;
+
+    if (!sdRef) return kDNSServiceErr_BadParam;
+    *sdRef = NULL;
+
+    if (!domain) domain = "";
+
+    len = sizeof(flags);
+    len += sizeof(interfaceIndex);
+    len += strlen(regtype) + 1;
+    len += strlen(domain) + 1;
+
+    hdr = create_hdr(browse_request, &len, &ptr, 1);
+    if (!hdr) goto error;
+    msg = (char *)hdr;
+    put_flags(flags, &ptr);
+    put_long(interfaceIndex, &ptr);
+    put_string(regtype, &ptr);
+    put_string(domain, &ptr);
+
+    sdr = connect_to_server();
+    if (!sdr) goto error;
+    err = deliver_request(msg, sdr, 1);
+    if (err)
+        {
+        DNSServiceRefDeallocate(sdr);
+        return err;
+        }
+    sdr->op = browse_request;
+    sdr->process_reply = handle_browse_response;
+    sdr->app_callback = callBack;
+    sdr->app_context = context;
+    *sdRef = sdr;
+    return err;
+
+error:
+    if (msg) free(msg);
+    if (*sdRef) { free(*sdRef);  *sdRef = NULL; }
+    return kDNSServiceErr_Unknown;
+    }
+
+
+
+
+static void handle_browse_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data)
+    {
+    DNSServiceFlags      flags;
+    uint32_t                      interfaceIndex;
+    DNSServiceErrorType      errorCode;
+    char replyName[256], replyType[256], replyDomain[256];
+        (void)hdr;//Unused
+
+    flags = get_flags(&data);
+    interfaceIndex = get_long(&data);
+    errorCode = get_error_code(&data);
+    get_string(&data, replyName, 256);
+    get_string(&data, replyType, 256);
+    get_string(&data, replyDomain, 256);
+    ((DNSServiceBrowseReply)sdr->app_callback)(sdr, flags, interfaceIndex, errorCode, replyName, replyType, replyDomain, sdr->app_context);
+    }
+
+
+DNSServiceErrorType DNSServiceRegister
+    (
+    DNSServiceRef                       *sdRef,
+    const DNSServiceFlags               flags,
+    const uint32_t                      interfaceIndex,
+    const char                          *name,         
+    const char                          *regtype,  
+    const char                          *domain,       
+    const char                          *host,         
+    const uint16_t                      port,
+    const uint16_t                      txtLen,
+    const void                          *txtRecord,    
+    const DNSServiceRegisterReply       callBack,      
+    void                                *context       
+    )
+    {
+    char *msg = NULL, *ptr;
+    int len;
+    ipc_msg_hdr *hdr;
+    DNSServiceRef sdr;
+    DNSServiceErrorType err;
+
+    if (!sdRef) return kDNSServiceErr_BadParam;
+    *sdRef = NULL;
+
+    if (!name) name = "";
+    if (!regtype) return kDNSServiceErr_BadParam;
+    if (!domain) domain = "";
+    if (!host) host = "";
+    if (!txtRecord) (char *)txtRecord = "";
+    
+    // auto-name must also have auto-rename
+    if (!name[0]  && (flags & kDNSServiceFlagsNoAutoRename))
+        return kDNSServiceErr_BadParam;
+
+    // no callback must have auto-name
+    if (!callBack && name[0]) return kDNSServiceErr_BadParam;
+
+    len = sizeof(DNSServiceFlags);
+    len += sizeof(uint32_t);  // interfaceIndex
+    len += strlen(name) + strlen(regtype) + strlen(domain) + strlen(host) + 4;
+    len += 2 * sizeof(uint16_t);  // port, txtLen
+    len += txtLen;
+
+    hdr = create_hdr(reg_service_request, &len, &ptr, 1);
+    if (!hdr) goto error;
+    if (!callBack) hdr->flags |= IPC_FLAGS_NOREPLY;
+    msg = (char *)hdr;
+    put_flags(flags, &ptr);
+    put_long(interfaceIndex, &ptr);
+    put_string(name, &ptr);
+    put_string(regtype, &ptr);
+    put_string(domain, &ptr);
+    put_string(host, &ptr);
+    put_short(port, &ptr);
+    put_short(txtLen, &ptr);
+    put_rdata(txtLen, txtRecord, &ptr);
+
+    sdr = connect_to_server();
+    if (!sdr) goto error;
+    err = deliver_request(msg, sdr, 1);
+    if (err)
+        {
+        DNSServiceRefDeallocate(sdr);
+        return err;
+        }
+        
+    sdr->op = reg_service_request;
+    sdr->process_reply = callBack ? handle_regservice_response : NULL;
+    sdr->app_callback = callBack;
+    sdr->app_context = context;
+    *sdRef = sdr;
+
+    return err;
+    
+error:
+    if (msg) free(msg);
+    if (*sdRef)         { free(*sdRef);  *sdRef = NULL; }
+    return kDNSServiceErr_Unknown;
+    }
+
+
+static void handle_regservice_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data)
+    {
+    DNSServiceFlags flags;
+    uint32_t interfaceIndex;
+    DNSServiceErrorType errorCode;
+    char name[256], regtype[256], domain[256];
+        (void)hdr;//Unused
+
+    flags = get_flags(&data);
+    interfaceIndex = get_long(&data);
+    errorCode = get_error_code(&data);
+    get_string(&data, name, 256);
+    get_string(&data, regtype, 256);
+    get_string(&data, domain, 256);
+    ((DNSServiceRegisterReply)sdr->app_callback)(sdr, flags, errorCode, name, regtype, domain, sdr->app_context);
+    }
+
+DNSServiceErrorType DNSServiceEnumerateDomains
+(
+ DNSServiceRef                    *sdRef,
+ const DNSServiceFlags            flags,
+ const uint32_t                   interfaceIndex,
+ const DNSServiceDomainEnumReply  callBack,
+ void                             *context
+ )
+    {
+    char *msg = NULL, *ptr;
+    int len;
+    ipc_msg_hdr *hdr;
+    DNSServiceRef sdr;
+    DNSServiceErrorType err;
+
+
+    if (!sdRef) return kDNSServiceErr_BadParam;
+    *sdRef = NULL;
+
+    len = sizeof(DNSServiceFlags);
+    len += sizeof(uint32_t);
+
+    hdr = create_hdr(enumeration_request, &len, &ptr, 1);
+    if (!hdr) goto error;
+    msg = (void *)hdr;
+
+    put_flags(flags, &ptr);
+    put_long(interfaceIndex, &ptr);
+
+    sdr = connect_to_server();
+    if (!sdr) goto error;
+    err = deliver_request(msg, sdr, 1);
+    if (err)
+        {
+        DNSServiceRefDeallocate(sdr);
+        return err;
+        }
+
+    sdr->op = enumeration_request;
+    sdr->process_reply = handle_enumeration_response;
+    sdr->app_callback = callBack;
+    sdr->app_context = context;
+    *sdRef = sdr;
+    return err;
+
+error:
+    if (msg) free(msg);
+    if (*sdRef) { free(*sdRef);  *sdRef = NULL; }
+    return kDNSServiceErr_Unknown;
+    }
+
+
+static void handle_enumeration_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data)
+    {
+    DNSServiceFlags flags;
+    uint32_t interfaceIndex;
+    DNSServiceErrorType err;
+    char domain[256];
+        (void)hdr;//Unused
+
+    flags = get_flags(&data);
+    interfaceIndex = get_long(&data);
+    err = get_error_code(&data);
+    get_string(&data, domain, 256);
+    ((DNSServiceDomainEnumReply)sdr->app_callback)(sdr, flags, interfaceIndex, err, domain, sdr->app_context);
+    }
+
+
+DNSServiceErrorType DNSServiceCreateConnection(DNSServiceRef *sdRef)
+    {
+    if (!sdRef) return kDNSServiceErr_BadParam;
+    *sdRef = connect_to_server();
+    if (!*sdRef)
+            return kDNSServiceErr_Unknown;
+    (*sdRef)->op = connection;
+    (*sdRef)->process_reply = handle_regrecord_response;
+    return 0;
+    }
+
+
+
+static void handle_regrecord_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data)
+    {
+    DNSServiceFlags flags;
+    uint32_t interfaceIndex;
+    DNSServiceErrorType errorCode;
+    DNSRecordRef rref = hdr->client_context.context;
+    
+    if (sdr->op != connection) 
+        {
+        rref->app_callback(rref->sdr, rref, 0, kDNSServiceErr_Unknown, rref->app_context);
+        return;
+        }
+    flags = get_flags(&data);
+    interfaceIndex = get_long(&data);
+    errorCode = get_error_code(&data);
+
+    rref->app_callback(rref->sdr, rref, flags, errorCode, rref->app_context);
+    }
+
+DNSServiceErrorType DNSServiceRegisterRecord
+(
+ const DNSServiceRef                    sdRef,
+ DNSRecordRef                           *RecordRef,  
+ const DNSServiceFlags                  flags,
+ const uint32_t                         interfaceIndex,
+ const char                             *fullname,
+ const uint16_t                         rrtype,
+ const uint16_t                         rrclass,
+ const uint16_t                         rdlen,
+ const void                             *rdata,
+ const uint32_t                         ttl,
+ const DNSServiceRegisterRecordReply    callBack,
+ void                                   *context
+ )
+    {
+    char *msg = NULL, *ptr;
+    int len;
+    ipc_msg_hdr *hdr = NULL;
+    DNSServiceRef tmp = NULL;
+    DNSRecordRef rref = NULL;
+    
+    if (!sdRef || sdRef->op != connection || sdRef->sockfd < 0) 
+        return kDNSServiceErr_BadReference;
+    *RecordRef = NULL;
+    
+    len = sizeof(DNSServiceFlags);
+    len += 2 * sizeof(uint32_t);  // interfaceIndex, ttl
+    len += 3 * sizeof(uint16_t);  // rrtype, rrclass, rdlen
+    len += strlen(fullname) + 1;
+    len += rdlen;
+
+    hdr = create_hdr(reg_record_request, &len, &ptr, 0);
+    if (!hdr) goto error;
+    msg = (char *)hdr;
+    put_flags(flags, &ptr);
+    put_long(interfaceIndex, &ptr);
+    put_string(fullname, &ptr);
+    put_short(rrtype, &ptr);
+    put_short(rrclass, &ptr);
+    put_short(rdlen, &ptr);
+    put_rdata(rdlen, rdata, &ptr);
+    put_long(ttl, &ptr);
+
+    rref = malloc(sizeof(_DNSRecordRef_t));
+    if (!rref) goto error;
+    rref->app_context = context;
+    rref->app_callback = callBack;
+    rref->record_index = sdRef->max_index++;
+    rref->sdr = sdRef;
+    *RecordRef = rref;
+    hdr->client_context.context = rref;
+    hdr->reg_index = rref->record_index;  
+    
+    return deliver_request(msg, sdRef, 0);
+
+error:
+    if (rref) free(rref);
+    if (tmp) free(tmp);
+    if (hdr) free(hdr);
+    return kDNSServiceErr_Unknown;
+    }
+
+//sdRef returned by DNSServiceRegister()
+DNSServiceErrorType DNSServiceAddRecord
+    (
+    const DNSServiceRef                 sdRef,
+    DNSRecordRef                        *RecordRef,
+    const DNSServiceFlags               flags,
+    const uint16_t                      rrtype,
+    const uint16_t                      rdlen,
+    const void                          *rdata,
+    const uint32_t                      ttl
+    )
+    {
+    ipc_msg_hdr *hdr;
+    int len = 0;
+    char *ptr;
+    DNSRecordRef rref;
+
+    if (!sdRef || (sdRef->op != reg_service_request) || !RecordRef) 
+        return kDNSServiceErr_BadReference;
+    *RecordRef = NULL;
+    
+    len += 2 * sizeof(uint16_t);  //rrtype, rdlen
+    len += rdlen;
+    len += sizeof(uint32_t);
+    len += sizeof(DNSServiceFlags);
+
+    hdr = create_hdr(add_record_request, &len, &ptr, 0);
+    if (!hdr) return kDNSServiceErr_Unknown;
+    put_flags(flags, &ptr);
+    put_short(rrtype, &ptr);
+    put_short(rdlen, &ptr);
+    put_rdata(rdlen, rdata, &ptr);
+    put_long(ttl, &ptr);
+
+    rref = malloc(sizeof(_DNSRecordRef_t));
+    if (!rref) goto error;
+    rref->app_context = NULL;
+    rref->app_callback = NULL;
+    rref->record_index = sdRef->max_index++;
+    rref->sdr = sdRef;
+    *RecordRef = rref;
+    hdr->client_context.context = rref;
+    hdr->reg_index = rref->record_index;  
+    return deliver_request((char *)hdr, sdRef, 0);
+
+error:
+    if (hdr) free(hdr);
+    if (rref) free(rref);
+    if (*RecordRef) *RecordRef = NULL;
+    return kDNSServiceErr_Unknown;
+}
+    
+
+//DNSRecordRef returned by DNSServiceRegisterRecord or DNSServiceAddRecord
+DNSServiceErrorType DNSServiceUpdateRecord
+    (
+    const DNSServiceRef                 sdRef,
+    DNSRecordRef                        RecordRef,
+    const DNSServiceFlags               flags,
+    const uint16_t                      rdlen,
+    const void                          *rdata,
+    const uint32_t                      ttl
+    )
+    {
+    ipc_msg_hdr *hdr;
+    int len = 0;
+    char *ptr;
+
+    if (!sdRef || !RecordRef || !sdRef->max_index) 
+        return kDNSServiceErr_BadReference;
+    
+    len += sizeof(uint16_t);
+    len += rdlen;
+    len += sizeof(uint32_t);
+    len += sizeof(DNSServiceFlags);
+
+    hdr = create_hdr(update_record_request, &len, &ptr, 0);
+    if (!hdr) return kDNSServiceErr_Unknown;
+    hdr->reg_index = RecordRef ? RecordRef->record_index : TXT_RECORD_INDEX;
+    put_flags(flags, &ptr);
+    put_short(rdlen, &ptr);
+    put_rdata(rdlen, rdata, &ptr);
+    put_long(ttl, &ptr);
+    return deliver_request((char *)hdr, sdRef, 0);
+    }
+    
+
+
+DNSServiceErrorType DNSServiceRemoveRecord
+(
+ const DNSServiceRef            sdRef,
+ const DNSRecordRef             RecordRef,
+ const DNSServiceFlags          flags
+ )
+    {
+    ipc_msg_hdr *hdr;
+    int len = 0;
+    char *ptr;
+    DNSServiceErrorType err;
+
+    if (!sdRef || !RecordRef || !sdRef->max_index) 
+        return kDNSServiceErr_BadReference;
+    
+    len += sizeof(flags);
+    hdr = create_hdr(remove_record_request, &len, &ptr, 0);
+    if (!hdr) return kDNSServiceErr_Unknown;
+    hdr->reg_index = RecordRef->record_index;
+    put_flags(flags, &ptr);
+    err = deliver_request((char *)hdr, sdRef, 0);
+    if (!err) free(RecordRef);
+    return err;
+    }
+
+
+void DNSServiceReconfirmRecord
+(
+ const DNSServiceFlags              flags,
+ const uint32_t                     interfaceIndex,
+ const char                         *fullname,
+ const uint16_t                     rrtype,
+ const uint16_t                     rrclass,
+ const uint16_t                     rdlen,
+ const void                         *rdata
+ )
+    {
+    char *ptr;
+    int len;
+    ipc_msg_hdr *hdr;
+    DNSServiceRef tmp;
+
+    len = sizeof(DNSServiceFlags);
+    len += sizeof(uint32_t);
+    len += strlen(fullname) + 1;
+    len += 3 * sizeof(uint16_t);
+    len += rdlen;
+    tmp = connect_to_server();
+    if (!tmp) return;
+    hdr = create_hdr(reconfirm_record_request, &len, &ptr, 1);
+    if (!hdr) return;
+
+    put_flags(flags, &ptr);
+    put_long(interfaceIndex, &ptr);
+    put_string(fullname, &ptr);
+    put_short(rrtype, &ptr);
+    put_short(rrclass, &ptr);
+    put_short(rdlen, &ptr);
+    put_rdata(rdlen, rdata, &ptr);
+    my_write(tmp->sockfd, (char *)hdr, len);
+    DNSServiceRefDeallocate(tmp);
+    }
+        
+        
+int DNSServiceConstructFullName 
+    (
+    char                      *fullName,
+    const char                *service,      /* may be NULL */
+    const char                *regtype,
+    const char                *domain
+    )
+    {
+    int len;
+    u_char c;
+    char *fn = fullName;
+    const char *s = service;
+    const char *r = regtype;
+    const char *d = domain;
+    
+    if (service)
+        {
+        while(*s)
+            {
+            c = *s++;
+            if (c == '.' || (c == '\\')) *fn++ = '\\';          // escape dot and backslash literals
+            else if (c <= ' ')                                  // escape non-printable characters
+                {
+                *fn++ = '\\';
+                *fn++ = (char) ('0' + (c / 100));
+                *fn++ = (char) ('0' + (c / 10) % 10);
+                c = (u_char)('0' + (c % 10));
+                }
+                *fn++ = c;
+            }
+        *fn++ = '.';
+        }
+
+    if (!regtype) return -1;
+    len = strlen(regtype);
+    if (domain_ends_in_dot(regtype)) len--;
+    if (len < 4) return -1;                                     // regtype must end in _udp or _tcp
+    if (strncmp((regtype + len - 4), "_tcp", 4) && strncmp((regtype + len - 4), "_udp", 4)) return -1;
+    while(*r)
+        *fn++ = *r++;                                                                                                                                                                                        
+    if (!domain_ends_in_dot(regtype)) *fn++ = '.';
+                                                                                        
+    if (!domain) return -1;
+    len = strlen(domain);
+    if (!len) return -1;
+    while(*d) 
+        *fn++ = *d++;                                           
+    if (!domain_ends_in_dot(domain)) *fn++ = '.';
+    *fn = '\0';
+    return 0;
+    }
+        
+static int domain_ends_in_dot(const char *dom)
+    {
+    while(*dom && *(dom + 1))
+        {
+        if (*dom == '\\')       // advance past escaped byte sequence
+            {           
+            if (*(dom + 1) >= '0' && *(dom + 1) <= '9') dom += 4;
+            else dom += 2;
+            }
+        else dom++;             // else read one character
+        }
+        return (*dom == '.');
+    }
+
+
+
+    // return a connected service ref (deallocate with DNSServiceRefDeallocate)
+static DNSServiceRef connect_to_server(void)
+    {
+    struct sockaddr_un saddr;
+    DNSServiceRef sdr;
+
+    sdr = malloc(sizeof(_DNSServiceRef_t));
+    if (!sdr) return NULL;
+
+    if ((sdr->sockfd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0) 
+        {
+        free(sdr);
+        return NULL;
+        }
+
+    saddr.sun_family = AF_LOCAL;
+    strcpy(saddr.sun_path, MDNS_UDS_SERVERPATH);
+    if (connect(sdr->sockfd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0)
+        {
+        free(sdr);
+        return NULL;
+        }
+    return sdr; 
+    }
+
+
+
+
+int my_write(int sd, char *buf, int len)
+    {
+    if (send(sd, buf, len, MSG_WAITALL) != len)   return -1;
+    return 0;
+    }
+
+
+// read len bytes.  return 0 on success, -1 on error
+int my_read(int sd, char *buf, int len)
+    {
+    if (recv(sd, buf, len, MSG_WAITALL) != len)  return -1;
+    return 0;
+    }
+
+
+DNSServiceErrorType deliver_request(void *msg, DNSServiceRef sdr, int reuse_sd)
+    {
+    ipc_msg_hdr *hdr = msg;
+    mode_t mask;
+    struct sockaddr_un caddr, daddr;  // (client and daemon address structs)
+    char *path = NULL;
+    int listenfd = -1, errsd = -1, len;
+    DNSServiceErrorType err = kDNSServiceErr_Unknown;
+    
+    if (!hdr || sdr->sockfd < 0) return kDNSServiceErr_Unknown;
+
+    if (!reuse_sd) 
+        {
+        // setup temporary error socket
+        if ((listenfd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0) 
+            goto cleanup;
+
+        bzero(&caddr, sizeof(caddr));
+        caddr.sun_family = AF_LOCAL;
+        caddr.sun_len = sizeof(struct sockaddr_un);
+        path = (char *)msg + sizeof(ipc_msg_hdr);
+        strcpy(caddr.sun_path, path);
+        mask = umask(0);
+        if (bind(listenfd, (struct sockaddr *)&caddr, sizeof(caddr)) < 0)
+          {
+            umask(mask);
+            goto cleanup;
+          }
+        umask(mask);
+        listen(listenfd, 1);
+        }
+        
+    if (my_write(sdr->sockfd, msg, hdr->datalen + sizeof(ipc_msg_hdr)) < 0)  
+        goto cleanup;
+    free(msg);
+    msg = NULL;
+
+    if (reuse_sd) errsd = sdr->sockfd;
+    else 
+        {
+        len = sizeof(daddr);
+        errsd = accept(listenfd, (struct sockaddr *)&daddr, &len);
+        if (errsd < 0)  goto cleanup;
+        }
+    
+    len = recv(errsd, &err, sizeof(err), MSG_WAITALL);
+    if (len != sizeof(err))
+        {
+        err = kDNSServiceErr_Unknown;
+        }
+cleanup:
+    if (!reuse_sd && listenfd > 0) close(listenfd);
+    if (!reuse_sd && errsd > 0) close(errsd);   
+    if (!reuse_sd && path) unlink(path);
+    if (msg) free(msg);
+    return err;
+    }
+    
+    
+    
+/* create_hdr
+ *
+ * allocate and initialize an ipc message header.  value of len should initially be the
+ * length of the data, and is set to the value of the data plus the header.  data_start 
+ * is set to point to the beginning of the data section.  reuse_socket should be non-zero
+ * for calls that can receive an immediate error return value on their primary socket.
+ * if zero, the path to a control socket is appended at the beginning of the message buffer.
+ * data_start is set past this string.
+ */
+     
+static ipc_msg_hdr *create_hdr(int op, int *len, char **data_start, int reuse_socket)
+    {
+    char *msg = NULL;
+    ipc_msg_hdr *hdr;
+    int datalen;
+    char ctrl_path[256];
+    struct timeval time;
+
+    if (!reuse_socket)
+        {
+        if (gettimeofday(&time, NULL) < 0) return NULL;
+        sprintf(ctrl_path, "%s%d-%.3x-%.6u", CTL_PATH_PREFIX, (int)getpid(), 
+                time.tv_sec & 0xFFF, time.tv_usec);
+
+        *len += strlen(ctrl_path) + 1;
+        }
+    
+        
+    datalen = *len;
+    *len += sizeof(ipc_msg_hdr);
+
+    // write message to buffer
+    msg = malloc(*len);
+    if (!msg) return NULL;
+
+    bzero(msg, *len);
+    hdr = (void *)msg;
+    hdr->datalen = datalen;
+    hdr->version = VERSION;
+    hdr->op.request_op = op;
+    if (reuse_socket) hdr->flags |= IPC_FLAGS_REUSE_SOCKET;
+    *data_start = msg + sizeof(ipc_msg_hdr);
+    if (!reuse_socket)  put_string(ctrl_path, data_start);
+    return hdr;
+    }
diff --git a/mDNSShared/dnssd_ipc.c b/mDNSShared/dnssd_ipc.c
new file mode 100644 (file)
index 0000000..186f4d3
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+
+$Log: dnssd_ipc.c,v $
+Revision 1.7  2003/08/12 19:56:25  cheshire
+Update to APSL 2.0
+
+ */
+
+#include "dnssd_ipc.h"
+
+void put_flags(const DNSServiceFlags flags, char **ptr)
+    {
+    memcpy(*ptr, &flags, sizeof(DNSServiceFlags));
+    *ptr += sizeof(flags);
+    }
+
+DNSServiceFlags get_flags(char **ptr)
+    {
+    DNSServiceFlags flags;
+       
+    flags = *(DNSServiceFlags *)*ptr;
+    *ptr += sizeof(DNSServiceFlags);
+    return flags;
+    }
+
+void put_long(const uint32_t l, char **ptr)
+    {
+
+    *(uint32_t *)(*ptr) = l;
+    *ptr += sizeof(uint32_t);
+    }
+
+uint32_t get_long(char **ptr)
+    {
+    uint32_t l;
+       
+    l = *(uint32_t *)(*ptr);
+    *ptr += sizeof(uint32_t);
+    return l;
+    }
+
+void put_error_code(const DNSServiceErrorType error, char **ptr)
+    {
+    memcpy(*ptr, &error, sizeof(error));
+    *ptr += sizeof(DNSServiceErrorType);
+    }
+
+DNSServiceErrorType get_error_code(char **ptr)
+    {
+    DNSServiceErrorType error;
+       
+    error = *(DNSServiceErrorType *)(*ptr);
+    *ptr += sizeof(DNSServiceErrorType);
+    return error;
+    }
+
+void put_short(const uint16_t s, char **ptr)
+    {
+    *(uint16_t *)(*ptr) = s;
+    *ptr += sizeof(uint16_t);
+    }
+
+uint16_t get_short(char **ptr)
+    {
+    uint16_t s;
+
+    s = *(uint16_t *)(*ptr);
+    *ptr += sizeof(uint16_t);
+    return s;
+    }
+
+
+int put_string(const char *str, char **ptr)
+    {
+    if (!str) str = "";
+    strcpy(*ptr, str);
+    *ptr += strlen(str) + 1;
+    return 0;
+    }
+
+// !!!KRS we don't properly handle the case where the string is longer than the buffer!!!      
+int get_string(char **ptr, char *buffer, int buflen)
+    {
+    int overrun;
+    
+    overrun = (int)strlen(*ptr) <  buflen ? 0 : -1;
+    strncpy(buffer, *ptr,  buflen - 1);
+    buffer[buflen - 1] = '\0';
+    *ptr += strlen(buffer) + 1;
+    return overrun;
+    }  
+
+void put_rdata(const int rdlen, const char *rdata, char **ptr)
+    {
+    memcpy(*ptr, rdata, rdlen);
+    *ptr += rdlen;     
+    }
+
+char *get_rdata(char **ptr, int rdlen)
+    {
+    char *rd;
+               
+    rd = *ptr;
+    *ptr += rdlen;
+    return rd;
+    }
+
+
+
+
+
+
+
+
+
diff --git a/mDNSShared/dnssd_ipc.h b/mDNSShared/dnssd_ipc.h
new file mode 100644 (file)
index 0000000..2b7b323
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+
+$Log: dnssd_ipc.h,v $
+Revision 1.6  2003/08/12 19:56:25  cheshire
+Update to APSL 2.0
+
+ */
+
+#ifndef DNSSD_IPC_H
+#define DNSSD_IPC_H
+
+#include "dns_sd.h"
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/un.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+
+//#define UDSDEBUG  // verbose debug output
+
+// General UDS constants
+#define MDNS_UDS_SERVERPATH "/var/run/mDNSResponder" 
+#define LISTENQ 100
+#define TXT_RECORD_INDEX -1    // record index for default text record
+#define MAX_CTLPATH 256            // longest legal control path length
+
+// IPC data encoding constants and types
+#define VERSION 1
+#define IPC_FLAGS_NOREPLY 1    // set flag if no asynchronous replies are to be sent to client
+#define IPC_FLAGS_REUSE_SOCKET 2 // set flag if synchronous errors are to be sent via the primary socket
+                                // (if not set, first string in message buffer must be path to error socket
+
+
+typedef enum
+    {
+    connection = 1,           // connected socket via DNSServiceConnect()
+    reg_record_request,          // reg/remove record only valid for connected sockets
+    remove_record_request,
+    enumeration_request,
+    reg_service_request,
+    browse_request,
+    resolve_request,
+    query_request,
+    reconfirm_record_request,
+    add_record_request,
+    update_record_request
+    } request_op_t;
+
+typedef enum
+    {
+    enumeration_reply = 64,
+    reg_service_reply,
+    browse_reply,
+    resolve_reply,
+    query_reply,
+    reg_record_reply
+    } reply_op_t;
+
+
+typedef struct ipc_msg_hdr_struct ipc_msg_hdr;
+
+
+// client stub callback to process message from server and deliver results to
+// client application
+
+typedef void (*process_reply_callback)
+    (
+    DNSServiceRef sdr,
+    ipc_msg_hdr *hdr,
+    char *msg
+    );
+
+// allow 64-bit client to interoperate w/ 32-bit daemon
+typedef union
+    {
+    void *context;
+    uint32_t ptr64[2];
+    } client_context_t;
+
+
+typedef struct ipc_msg_hdr_struct
+    {
+    uint32_t version;
+    uint32_t datalen;
+    uint32_t flags;
+    union
+       {
+        request_op_t request_op;
+        reply_op_t reply_op;
+       } op;
+    client_context_t client_context; // context passed from client, returned by server in corresponding reply
+    int reg_index;                   // identifier for a record registered via DNSServiceRegisterRecord() on a
+    // socket connected by DNSServiceConnect().  Must be unique in the scope of the connection, such that and
+    // index/socket pair uniquely identifies a record.  (Used to select records for removal by DNSServiceRemoveRecord())
+    } ipc_msg_hdr_struct;                      
+
+
+
+
+// routines to write to and extract data from message buffers.
+// caller responsible for bounds checking.  
+// ptr is the address of the pointer to the start of the field.
+// it is advanced to point to the next field, or the end of the message
+
+
+void put_flags(const DNSServiceFlags flags, char **ptr);
+DNSServiceFlags get_flags(char **ptr);
+
+void put_long(const uint32_t l, char **ptr);
+uint32_t get_long(char **ptr);
+
+void put_error_code(const DNSServiceErrorType, char **ptr);
+DNSServiceErrorType get_error_code(char **ptr);
+
+int put_string(const char *str, char **ptr);
+int get_string(char **ptr, char *buffer, int buflen);
+
+void put_rdata(const int rdlen, const char *rdata, char **ptr);
+char *get_rdata(char **ptr, int rdlen);  // return value is rdata pointed to by *ptr - 
+                                         // rdata is not copied from buffer.
+
+void put_short(uint16_t s, char **ptr);
+uint16_t get_short(char **ptr);
+
+
+
+#endif // DNSSD_IPC_H
+
+
+
+
+
+
+
+
+
+
+
diff --git a/mDNSShared/uds_daemon.c b/mDNSShared/uds_daemon.c
new file mode 100644 (file)
index 0000000..5cc63fc
--- /dev/null
@@ -0,0 +1,2217 @@
+/*
+ * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+
+$Log: uds_daemon.c,v $
+Revision 1.22.2.1  2003/12/05 00:03:35  cheshire
+<rdar://problem/3487869> Use buffer size MAX_ESCAPED_DOMAIN_NAME instead of 256
+
+Revision 1.22  2003/08/19 16:03:55  ksekar
+Bug #: <rdar://problem/3380097>: ER: SIGINFO dump should include resolves started by DNSServiceQueryRecord
+Check termination_context for NULL before dereferencing.
+
+Revision 1.21  2003/08/19 05:39:43  cheshire
+<rdar://problem/3380097> SIGINFO dump should include resolves started by DNSServiceQueryRecord
+
+Revision 1.20  2003/08/16 03:39:01  cheshire
+<rdar://problem/3338440> InterfaceID -1 indicates "local only"
+
+Revision 1.19  2003/08/15 20:16:03  cheshire
+<rdar://problem/3366590> mDNSResponder takes too much RPRVT
+We want to avoid touching the rdata pages, so we don't page them in.
+1. RDLength was stored with the rdata, which meant touching the page just to find the length.
+   Moved this from the RData to the ResourceRecord object.
+2. To avoid unnecessarily touching the rdata just to compare it,
+   compute a hash of the rdata and store the hash in the ResourceRecord object.
+
+Revision 1.18  2003/08/15 00:38:00  ksekar
+Bug #: <rdar://problem/3377005>: Bug: buffer overrun when reading long rdata from client
+
+Revision 1.17  2003/08/14 02:18:21  cheshire
+<rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
+
+Revision 1.16  2003/08/13 23:58:52  ksekar
+Bug #: <rdar://problem/3374911>: Bug: UDS Sub-type browsing works, but not sub-type registration
+Fixed pointer increment error, moved subtype reading for-loop for easier error bailout.
+
+Revision 1.15  2003/08/13 17:30:33  ksekar
+Bug #: <rdar://problem/3374671>: DNSServiceAddRecord doesn't work
+Fixed various problems with handling the AddRecord request and freeing the ExtraResourceRecords.
+
+Revision 1.14  2003/08/12 19:56:25  cheshire
+Update to APSL 2.0
+
+ */
+
+#include "mDNSClientAPI.h"
+#include "mDNSMacOSX.h"
+#include "dns_sd.h"
+#include "dnssd_ipc.h"
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+// Types and Data Structures
+// ----------------------------------------------------------------------
+
+typedef enum
+    {
+    t_uninitialized,
+    t_morecoming,
+    t_complete,
+    t_error,
+    t_terminated
+    } transfer_state;
+
+typedef void (*req_termination_fn)(void *);
+
+
+typedef struct registered_record_entry
+    {
+    int key;
+    AuthRecord *rr;
+    struct registered_record_entry *next;
+    } registered_record_entry;
+
+typedef struct registered_service
+    {
+    //struct registered_service *next;
+    int autoname;
+    int renameonconflict;
+    int rename_on_memfree;     // set flag on config change when we deregister original name
+    domainlabel name;
+    ServiceRecordSet *srs;
+    struct request_state *request;
+    AuthRecord *subtypes;
+    } registered_service;
+    
+typedef struct 
+    {
+    mStatus err;
+    int nwritten;
+    int sd;
+    } undelivered_error_t;
+
+typedef struct request_state
+    {
+    // connection structures
+    CFRunLoopSourceRef rls;
+    CFSocketRef sr;            
+    int sd;    
+    int errfd;         
+                                
+    // state of read (in case message is read over several recv() calls)                            
+    transfer_state ts;
+    uint32_t hdr_bytes;                // bytes of header already read
+    ipc_msg_hdr hdr;
+    uint32_t data_bytes;       // bytes of message data already read
+    char *msgbuf;              // pointer to data storage to pass to free()
+    char *msgdata;             // pointer to data to be read from (may be modified)
+    int bufsize;               // size of data storage
+
+    // reply, termination, error, and client context info
+    int no_reply;              // don't send asynchronous replies to client
+    void *client_context;      // don't touch this - pointer only valid in client's addr space
+    struct reply_state *replies;  // corresponding (active) reply list
+    undelivered_error_t *u_err;
+    void *termination_context;
+    req_termination_fn terminate;
+    
+    //!!!KRS toss these pointers in a union
+    // registration context associated with this request (null if not applicable)
+    registered_record_entry *reg_recs;  // muliple registrations for a connection-oriented request
+    registered_service *service;  // service record set and flags
+    struct resolve_result_t *resolve_results;
+    
+    struct request_state *next;
+    } request_state;
+
+// struct physically sits between ipc message header and call-specific fields in the message buffer
+typedef struct
+    {
+    DNSServiceFlags flags;
+    uint32_t ifi;
+    DNSServiceErrorType error;
+    } reply_hdr;
+    
+
+typedef struct reply_state
+    {
+    // state of the transmission
+    int sd;
+    transfer_state ts;
+    uint32_t nwriten;
+    uint32_t len;
+    // context of the reply
+    struct request_state *request;  // the request that this answers
+    struct reply_state *next;   // if there are multiple unsent replies
+    // pointer into message buffer - allows fields to be changed after message is formatted
+    ipc_msg_hdr *mhdr;
+    reply_hdr *rhdr;
+    char *sdata;  // pointer to start of call-specific data
+    // pointer to malloc'd buffer
+    char *msgbuf;      
+    } reply_state;
+
+
+// domain enumeration and resolv calls require 2 mDNSCore calls, so we need separate interconnected
+// structures to handle callbacks
+typedef struct
+    {
+    DNSQuestion question;
+    mDNS_DomainType type;
+    request_state *rstate;
+    } domain_enum_t;
+
+typedef struct
+    {
+    domain_enum_t *all;
+    domain_enum_t *def;
+    request_state *rstate;
+    } enum_termination_t;
+
+typedef struct
+    {
+    DNSQuestion question;
+    uint16_t   qtype;
+    request_state *rstate;
+    } resolve_t;
+    
+typedef struct
+    {
+    resolve_t *txt;
+    resolve_t *srv;
+    request_state *rstate;
+    } resolve_termination_t;
+    
+typedef struct resolve_result_t
+    {
+    const ResourceRecord *txt;
+    const ResourceRecord *srv;
+    } resolve_result_t;
+
+typedef struct
+    {
+    request_state *rstate;
+    client_context_t client_context;
+    } regrecord_callback_context;
+
+
+
+
+// globals
+static int listenfd = -1;  
+static request_state *all_requests = NULL;  
+//!!!KRS we should keep a separate list containing only the requests that need to be examined
+//in the idle() routine.
+
+
+#define MAX_OPENFILES 1024
+
+// private function prototypes
+static void connect_callback(CFSocketRef sr, CFSocketCallBackType t, CFDataRef dr, const void *c, void *i);
+static int read_msg(request_state *rs);
+static int send_msg(reply_state *rs);
+static void abort_request(request_state *rs);
+static void request_callback(CFSocketRef sr, CFSocketCallBackType t, CFDataRef dr, const void *c, void *i);
+static void handle_resolve_request(request_state *rstate);
+static void question_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord);
+static void question_termination_callback(void *context);
+static void handle_browse_request(request_state *request);
+static void browse_termination_callback(void *context);
+static void browse_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord);
+static void handle_regservice_request(request_state *request);
+static void regservice_termination_callback(void *context);
+static void process_service_registration(ServiceRecordSet *const srs);
+static void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, mStatus result);
+static void handle_add_request(request_state *rstate);
+static void handle_update_request(request_state *rstate);
+static mStatus gen_rr_response(domainname *servicename, mDNSInterfaceID id, request_state *request, reply_state **rep);
+static void append_reply(request_state *req, reply_state *rep);
+static int build_domainname_from_strings(domainname *srv, char *name, char *regtype, char *domain);
+static void enum_termination_callback(void *context);
+static void enum_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord);
+static void handle_query_request(request_state *rstate);
+static mStatus do_question(request_state *rstate, domainname *name, uint32_t ifi, uint16_t rrtype, int16_t rrclass);
+static reply_state *format_enumeration_reply(request_state *rstate, char *domain,                                              DNSServiceFlags flags, uint32_t ifi, DNSServiceErrorType err);
+static void handle_enum_request(request_state *rstate);
+static void handle_regrecord_request(request_state *rstate);
+static void regrecord_callback(mDNS *const m, AuthRecord *const rr, mStatus result);
+static void connected_registration_termination(void *context);
+static void handle_reconfirm_request(request_state *rstate);
+static AuthRecord *read_rr_from_ipc_msg(char *msgbuf, int ttl);
+static void handle_removerecord_request(request_state *rstate);
+static void reset_connected_rstate(request_state *rstate);
+static int deliver_error(request_state *rstate, mStatus err);
+static int deliver_async_error(request_state *rs, reply_op_t op, mStatus err);
+static transfer_state send_undelivered_error(request_state *rs);
+static reply_state *create_reply(reply_op_t op, int datalen, request_state *request);
+static void update_callback(mDNS *const m, AuthRecord *const rr, RData *oldrd);
+static void my_perror(char *errmsg);
+static void unlink_request(request_state *rs);
+static void resolve_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord);
+static void resolve_termination_callback(void *context);
+
+// initialization, setup/teardown functions
+
+int udsserver_init(void)  
+    {
+    mode_t mask;
+    struct sockaddr_un laddr;
+    struct rlimit maxfds;
+
+    if ((listenfd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0) 
+            goto error;
+    unlink(MDNS_UDS_SERVERPATH);  //OK if this fails
+    bzero(&laddr, sizeof(laddr));
+    laddr.sun_family = AF_LOCAL;
+    laddr.sun_len = sizeof(struct sockaddr_un);
+    strcpy(laddr.sun_path, MDNS_UDS_SERVERPATH);
+    mask = umask(0);
+    if (bind(listenfd, (struct sockaddr *)&laddr, sizeof(laddr)) < 0)
+        goto error;
+    umask(mask);
+
+    if (fcntl(listenfd, F_SETFL, O_NONBLOCK) < 0)
+        {
+        my_perror("ERROR: could not set listen socket to non-blocking mode");
+        goto error;
+        }
+    listen(listenfd, LISTENQ);
+    
+    
+    // set maximum file descriptor to 1024
+    if (getrlimit(RLIMIT_NOFILE, &maxfds) < 0)
+        {
+        my_perror("ERROR: Unable to get file descriptor limit");
+        return 0;
+        }
+    if (maxfds.rlim_max >= MAX_OPENFILES && maxfds.rlim_cur == maxfds.rlim_max)
+        {
+        // proper values already set
+        return 0;
+        }
+    maxfds.rlim_max = MAX_OPENFILES;
+    maxfds.rlim_cur = MAX_OPENFILES;   
+    if (setrlimit(RLIMIT_NOFILE, &maxfds) < 0)
+        my_perror("ERROR: Unable to set maximum file descriptor limit");
+    return 0;
+       
+error:
+    my_perror("ERROR: udsserver_init");
+    return -1;
+    }
+
+int udsserver_exit(void)
+    {
+    close(listenfd);
+    unlink(MDNS_UDS_SERVERPATH);
+    return 0;
+    }
+
+
+// add the named socket as a runloop source
+int udsserver_add_rl_source(void)
+    {
+    CFSocketContext context =  { 0, NULL, NULL, NULL, NULL };
+    CFSocketRef sr = CFSocketCreateWithNative(kCFAllocatorDefault, listenfd, kCFSocketReadCallBack, connect_callback, &context);
+    if (!sr)
+        {
+        debugf("ERROR: udsserver_add_rl_source - CFSocketCreateWithNative");
+        return -1;
+       }
+    CFRunLoopSourceRef rls = CFSocketCreateRunLoopSource(kCFAllocatorDefault, sr, 0);
+  
+    if (!rls)
+       {
+        debugf("ERROR: udsserver_add_rl_source - CFSocketCreateRunLoopSource");
+        return -1;
+       }
+    CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
+    return 0;
+    }
+
+mDNSs32 udsserver_idle(mDNSs32 nextevent)
+    {
+    request_state *req = all_requests, *tmp, *prev = NULL;
+    reply_state *fptr;
+    transfer_state result; 
+    mDNSs32 now = mDNSPlatformTimeNow();
+
+
+    while(req)
+        {
+        result = t_uninitialized;
+        if (req->u_err) 
+            result = send_undelivered_error(req);
+        if (result != t_error && result != t_morecoming &&             // don't try to send msg if send_error failed
+            (req->ts == t_complete || req->ts == t_morecoming))
+            {
+            while(req->replies)
+                {
+                if (req->replies->next) req->replies->rhdr->flags |= kDNSServiceFlagsMoreComing;
+                else req->replies->rhdr->flags |= kDNSServiceFlagsFinished;
+                result = send_msg(req->replies);
+                if (result == t_complete)
+                    {
+                    fptr = req->replies;
+                    req->replies = req->replies->next;
+                    freeL("udsserver_idle", fptr);
+                    }
+                else if (result == t_terminated || result == t_error)
+                    {
+                    abort_request(req);
+                    break;
+                    }
+                else if (result == t_morecoming)                       // client's queues are full, move to next
+                    {
+                    if (nextevent - now > mDNSPlatformOneSecond)
+                        nextevent = now + mDNSPlatformOneSecond;
+                    break;                                     // start where we left off in a second
+                    }
+                }
+            }
+        if (result == t_terminated || result == t_error)  
+        //since we're already doing a list traversal, we unlink the request manunally instead of calling unlink_request()
+            {
+            tmp = req;
+            if (prev) prev->next = req->next;
+            if (req == all_requests) all_requests = all_requests->next;
+            req = req->next;
+            freeL("udsserver_idle", tmp);
+            }
+        else 
+            {
+            prev = req;
+            req = req->next;
+            }
+        }
+    return nextevent;
+    }
+
+void udsserver_info(void)
+    {
+    request_state *req;
+    for (req = all_requests; req; req=req->next)
+        {
+        void *t = req->termination_context;
+        if (!t) continue;
+        if (req->terminate == regservice_termination_callback)
+            LogMsg("DNSServiceRegister         %##s", ((registered_service *)   t)->srs->RR_SRV.resrec.name.c);
+        else if (req->terminate == browse_termination_callback)
+            LogMsg("DNSServiceBrowse           %##s", ((DNSQuestion *)          t)->qname.c);
+        else if (req->terminate == resolve_termination_callback)
+            LogMsg("DNSServiceResolve          %##s", ((resolve_termination_t *)t)->srv->question.qname.c);
+        else if (req->terminate == question_termination_callback)
+            LogMsg("DNSServiceQueryRecord      %##s", ((DNSQuestion *)          t)->qname.c);
+        else if (req->terminate == enum_termination_callback)
+            LogMsg("DNSServiceEnumerateDomains %##s", ((enum_termination_t *)   t)->all->question.qname.c);
+        }
+    }
+
+void udsserver_handle_configchange(void)
+    {
+    registered_service *srv;
+    request_state *req;
+    mStatus err;
+    
+    for (req = all_requests; req; req = req->next)
+        {
+        srv = req->service;
+        if (srv->autoname && !SameDomainLabel(srv->name.c, mDNSStorage.nicelabel.c))
+            {
+            srv->rename_on_memfree = 1;
+            err = mDNS_DeregisterService(&mDNSStorage, srv->srs);
+            if (err) LogMsg("ERROR: udsserver_handle_configchange: DeregisterService returned error %d.  Continuing.", err);
+            // error should never occur - safest to log and continue
+            }
+        }
+    }
+    
+    
+    
+
+// accept a connection on the named socket, adding the new descriptor to the runloop and passing the error
+// descriptor to the client
+static void connect_callback(CFSocketRef s, CFSocketCallBackType t, CFDataRef dr, const void *c, void *i)
+    {
+    int sd, clilen, optval;
+    struct sockaddr_un cliaddr;
+    CFSocketContext context =  { 0, NULL, NULL, NULL, NULL     };
+    request_state *rstate;
+//    int errpipe[2];
+    
+    #pragma unused(s, t, dr, c, i)
+
+    clilen = sizeof(cliaddr);
+    sd = accept(listenfd, (struct sockaddr *)&cliaddr, &clilen);
+
+    if (sd < 0)
+        {
+        if (errno == EWOULDBLOCK) return; 
+        my_perror("ERROR: accept");
+        return;
+       }
+    optval = 1;
+    if (setsockopt(sd, SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)) < 0)
+       {
+        my_perror("ERROR: setsockopt - SOL_NOSIGPIPE - aborting client");  
+        close(sd);
+        return;
+       }
+
+    if (fcntl(sd, F_SETFL, O_NONBLOCK) < 0)
+       {
+        my_perror("ERROR: could not set connected socket to non-blocking mode - aborting client");
+        close(sd);     
+        return;
+        }
+
+/*
+    // open a pipe to deliver error messages, pass descriptor to client
+    if (pipe(errpipe) < 0)
+        {
+        my_perror("ERROR: could not create pipe");
+        exit(1);
+        }
+    
+    if (ioctl(sd, I_SENDFD, errpipe[0]) < 0)
+        {
+        my_perror("ERROR: could not pass pipe descriptor to client.  Aborting client.\n");
+        close(sd);
+        return;
+        }
+    if (fcntl(errpipe[1], F_SETFL, O_NONBLOCK) < 0)
+       {
+        my_perror("ERROR: could not set error pipe to non-blocking mode - aborting client");
+        close(sd);     
+        close(errpipe[1]);
+        return;
+        }
+  */
+  
+      // allocate a request_state struct that will live with the socket
+    rstate = mallocL("connect_callback", sizeof(request_state));
+    if (!rstate)
+       {
+        my_perror("ERROR: malloc");
+        exit(1);
+       }
+    bzero(rstate, sizeof(request_state));
+    rstate->ts = t_morecoming;
+    rstate->sd = sd;
+    //rstate->errfd = errpipe[1];
+    
+    //now create CFSocket wrapper and add to run loop
+    context.info = rstate;
+    rstate->sr = CFSocketCreateWithNative(kCFAllocatorDefault, sd, kCFSocketReadCallBack, request_callback, &context);
+    if (!rstate->sr)
+       {
+        debugf("ERROR: connect_callback - CFSocketCreateWithNative");
+        freeL("connect_callback", rstate);
+        close(sd);
+        return;
+       }
+    rstate->rls = CFSocketCreateRunLoopSource(kCFAllocatorDefault, rstate->sr, 0);
+    if (!rstate->rls)
+       {
+        debugf("ERROR: connect_callback - CFSocketCreateRunLoopSource");
+        CFSocketInvalidate(rstate->sr);  // automatically closes socket
+        CFRelease(rstate->sr);
+        freeL("connect_callback", rstate);
+        return;
+       }
+    CFRunLoopAddSource(CFRunLoopGetCurrent(), rstate->rls, kCFRunLoopDefaultMode);
+    if (!CFRunLoopContainsSource(CFRunLoopGetCurrent(), rstate->rls, kCFRunLoopDefaultMode))
+        {
+        LogMsg("ERROR: connect_callback, CFRunLoopAddSource");
+        abort_request(rstate);
+        return;
+        }
+    rstate->next = all_requests;
+    all_requests = rstate;
+    }
+
+
+// main client request handling routine.  reads request and calls the appropriate request-specific
+// handler
+static void request_callback(CFSocketRef sr, CFSocketCallBackType t, CFDataRef dr, const void *context, void *info)
+    {
+    request_state *rstate = info;
+    transfer_state result;
+    struct sockaddr_un cliaddr;
+    char ctrl_path[MAX_CTLPATH];
+    
+    #pragma unused(sr, t, dr, context)
+
+    int native = CFSocketGetNative(sr);
+    if (native != rstate->sd)
+        {
+        LogMsg("ERROR: request_callback - CFSocket's native descriptor does not match rstate member descriptor.");
+        abort_request(rstate);
+        unlink_request(rstate);
+        return;
+        }
+
+    result = read_msg(rstate);
+    if (result == t_morecoming)
+       {
+        return;
+       }
+    if (result == t_terminated)
+       {
+        abort_request(rstate);
+        unlink_request(rstate);
+        return;
+       }
+    if (result == t_error)
+       {
+        abort_request(rstate);
+        unlink_request(rstate);
+        return;
+       }
+
+    if (rstate->hdr.version != VERSION)
+    {
+        LogMsg("ERROR: client incompatible with daemon (client version = %d, "
+                "daemon version = %d)\n", rstate->hdr.version, VERSION);
+        abort_request(rstate);
+        unlink_request(rstate);
+        return;
+    }
+    
+    // check if client wants silent operation
+    if (rstate->hdr.flags & IPC_FLAGS_NOREPLY) rstate->no_reply = 1;
+
+    // check if primary socket is to be used for synchronous errors, else open new socket
+    if (rstate->hdr.flags & IPC_FLAGS_REUSE_SOCKET)
+        rstate->errfd = rstate->sd;
+    else
+       {
+        if ((rstate->errfd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0)
+            {
+            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;
+            }        
+        get_string(&rstate->msgdata, ctrl_path, 256);  // path is first element in message buffer
+        bzero(&cliaddr, sizeof(cliaddr));
+        cliaddr.sun_family = AF_LOCAL;
+        strcpy(cliaddr.sun_path, ctrl_path);
+        if (connect(rstate->errfd, (struct sockaddr *)&cliaddr, sizeof(cliaddr)) < 0)
+            {
+            my_perror("ERROR: connect");
+            abort_request(rstate);
+            unlink_request(rstate);
+            }
+        }
+
+        
+
+
+    switch(rstate->hdr.op.request_op)
+       {
+        case resolve_request: handle_resolve_request(rstate); break;
+        case query_request: handle_query_request(rstate);  break;
+        case browse_request: handle_browse_request(rstate); break;
+        case reg_service_request: handle_regservice_request(rstate);  break;
+        case enumeration_request: handle_enum_request(rstate); break;
+        case reg_record_request: handle_regrecord_request(rstate);  break;
+        case add_record_request: handle_add_request(rstate); break;
+        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;
+        default:
+            debugf("ERROR: udsserver_recv_request - unsupported request type: %d", rstate->hdr.op.request_op);
+       }
+    }
+
+// mDNS operation functions.  Each operation has 3 associated functions - a request handler that parses
+// the client's request and makes the appropriate mDNSCore call, a result handler (passed as a callback
+// to the mDNSCore routine) that sends results back to the client, and a termination routine that aborts
+// the mDNSCore operation if the client dies or closes its socket.
+
+
+// query and resolve calls have separate request handlers that parse the arguments from the client and
+// massage the name parameters appropriately, but the rest of the operations (making the query call,
+// delivering the result to the client, and termination) are identical.
+
+static void handle_query_request(request_state *rstate)
+    {
+    DNSServiceFlags flags;
+    uint32_t interfaceIndex;
+    char name[256];
+    uint16_t rrtype, rrclass;
+    char *ptr;
+    domainname dname;
+    mStatus result;
+    
+    if (rstate->ts != t_complete)
+        {
+        LogMsg("ERROR: handle_query_request - transfer state != t_complete");
+        goto error;
+        }
+    ptr = rstate->msgdata;
+    if (!ptr)
+        {
+        LogMsg("ERROR: handle_query_request - NULL msgdata");
+        goto error;
+        }
+    flags = get_flags(&ptr);
+    interfaceIndex = get_long(&ptr);
+    if (get_string(&ptr, name, 256) < 0) goto bad_param;
+    rrtype = get_short(&ptr);
+    rrclass = get_short(&ptr);
+    if (!MakeDomainNameFromDNSNameString(&dname, name)) goto bad_param;
+    result = do_question(rstate, &dname, interfaceIndex, rrtype, rrclass);
+    if (result) rstate->terminate = NULL;
+    if (deliver_error(rstate, result) < 0) goto error;
+    return;
+    
+bad_param:
+    deliver_error(rstate, mStatus_BadParamErr);
+    rstate->terminate = NULL;  // don't try to terminate insuccessful Core calls
+error:
+    abort_request(rstate);
+    unlink_request(rstate);
+    return;
+    }
+
+static void handle_resolve_request(request_state *rstate)
+    {
+    DNSServiceFlags flags;
+    uint32_t interfaceIndex;
+    char name[256], regtype[MAX_ESCAPED_DOMAIN_NAME], domain[MAX_ESCAPED_DOMAIN_NAME];  
+    char *ptr;  // message data pointer
+    domainname fqdn;
+    resolve_t *srv, *txt;
+    resolve_termination_t *term;
+    mStatus err;
+    
+    if (rstate->ts != t_complete)
+        {
+        LogMsg("ERROR: handle_resolve_request - transfer state != t_complete");
+        abort_request(rstate);
+        unlink_request(rstate);
+        return;
+        }
+        
+    // extract the data from the message
+    ptr = rstate->msgdata;
+    if (!ptr)
+        {
+        LogMsg("ERROR: handle_resolve_request - NULL msgdata");
+        abort_request(rstate);
+        unlink_request(rstate);
+        return;
+        }
+    flags = get_flags(&ptr);
+    interfaceIndex = get_long(&ptr);
+    mDNSInterfaceID InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex);
+    if (interfaceIndex && !InterfaceID) goto bad_param;
+    if (get_string(&ptr, name, 256) < 0 ||
+        get_string(&ptr, regtype, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
+        get_string(&ptr, domain, MAX_ESCAPED_DOMAIN_NAME) < 0)
+        goto bad_param;
+
+    // free memory in rstate since we don't need it anymore
+    freeL("handle_resolve_request", rstate->msgbuf);
+    rstate->msgbuf = NULL;
+        
+    if (build_domainname_from_strings(&fqdn, name, regtype, domain) < 0)
+        goto bad_param;
+
+    // allocate question wrapper structs
+    srv = mallocL("handle_resolve_request", sizeof(resolve_t));
+    txt = mallocL("handle_resolve_request", sizeof(resolve_t));
+    if (!srv || !txt) goto malloc_error;
+    srv->qtype = kDNSType_SRV;
+    txt->qtype = kDNSType_TXT;
+    srv->rstate = rstate;
+    txt->rstate = rstate;
+    
+    // format questions
+    srv->question.QuestionContext = rstate;
+    srv->question.QuestionCallback = resolve_result_callback;
+    memcpy(&srv->question.qname, &fqdn, MAX_DOMAIN_NAME);
+    srv->question.qtype = kDNSType_SRV;
+    srv->question.qclass = kDNSClass_IN;
+    srv->question.InterfaceID = InterfaceID;
+
+    txt->question.QuestionContext = rstate;
+    txt->question.QuestionCallback = resolve_result_callback;
+    memcpy(&txt->question.qname, &fqdn, MAX_DOMAIN_NAME);
+    txt->question.qtype = kDNSType_TXT;
+    txt->question.qclass = kDNSClass_IN;
+    txt->question.InterfaceID = InterfaceID;
+
+    // set up termination info
+    term = mallocL("handle_resolve_request", sizeof(resolve_termination_t));
+    if (!term) goto malloc_error;
+    term->srv = srv;
+    term->txt = txt;
+    term->rstate = rstate;
+    rstate->termination_context = term;
+    rstate->terminate = resolve_termination_callback;
+    
+    // set up reply wrapper struct (since answer will come via 2 callbacks)
+    rstate->resolve_results = mallocL("handle_resolve_response", sizeof(resolve_result_t));
+    if (!rstate->resolve_results) goto malloc_error;
+    bzero(rstate->resolve_results, sizeof(resolve_result_t));
+
+    // ask the questions
+    err = mDNS_StartQuery(&mDNSStorage, &srv->question);
+    if (!err) err = mDNS_StartQuery(&mDNSStorage, &txt->question);
+
+    if (err)
+        {
+        freeL("handle_resolve_request", txt);
+        freeL("handle_resolve_request", srv);
+        freeL("handle_resolve_request", term);
+        freeL("handle_resolve_request", rstate->resolve_results);
+        rstate->terminate = NULL;  // prevent abort_request() from invoking termination callback
+        }
+    if (deliver_error(rstate, err) < 0 || err) 
+        {
+        abort_request(rstate);
+        unlink_request(rstate);
+        }
+    return;
+
+bad_param:
+    deliver_error(rstate, mStatus_BadParamErr);
+    abort_request(rstate);
+    unlink_request(rstate);
+    return;
+    
+malloc_error:
+    my_perror("ERROR: malloc");
+    exit(1);
+    }
+    
+static void resolve_termination_callback(void *context)
+    {
+    resolve_termination_t *term = context;
+    request_state *rs;
+    
+    if (!term) 
+        {
+        LogMsg("ERROR: resolve_termination_callback: double termination");
+        return;
+        }
+    rs = term->rstate;
+    
+    mDNS_StopQuery(&mDNSStorage, &term->txt->question);
+    mDNS_StopQuery(&mDNSStorage, &term->srv->question);
+    
+    freeL("resolve_termination_callback", term->txt);
+    freeL("resolve_termination_callback", term->srv);
+    freeL("resolve_termination_callback", term);
+    rs->termination_context = NULL;
+    freeL("resolve_termination_callback", rs->resolve_results);
+    rs->resolve_results = NULL;
+    }
+    
+    
+
+static void resolve_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
+{
+    int len = 0;
+    char fullname[MAX_ESCAPED_DOMAIN_NAME], target[MAX_ESCAPED_DOMAIN_NAME];
+    char *data;
+    transfer_state result;
+    reply_state *rep;
+    request_state *rs = question->QuestionContext;
+    resolve_result_t *res = rs->resolve_results;
+    #pragma unused(m)
+    
+       if (!AddRecord)
+               {
+               if (answer->rrtype == kDNSType_TXT && res->txt == answer) res->txt = mDNSNULL;
+               if (answer->rrtype == kDNSType_SRV && res->srv == answer) res->srv = mDNSNULL;
+               return;
+               }
+
+    if (answer->rrtype == kDNSType_TXT) res->txt = answer;
+    if (answer->rrtype == kDNSType_SRV) res->srv = answer;
+
+    if (!res->txt || !res->srv) return;                // only deliver result to client if we have both answers
+    
+    ConvertDomainNameToCString(&answer->name, fullname);
+    ConvertDomainNameToCString(&res->srv->rdata->u.srv.target, target);
+
+    // calculate reply length
+    len += sizeof(DNSServiceFlags);
+    len += sizeof(uint32_t);  // interface index
+    len += sizeof(DNSServiceErrorType);
+    len += strlen(fullname) + 1;
+    len += strlen(target) + 1;
+    len += 2 * sizeof(uint16_t);  // port, txtLen
+    len += res->txt->rdlength;
+    
+    // allocate/init reply header
+    rep =  create_reply(resolve_reply, len, rs);
+    rep->rhdr->flags = 0;
+    rep->rhdr->ifi =  mDNSPlatformInterfaceIndexfromInterfaceID(&mDNSStorage, answer->InterfaceID);
+    rep->rhdr->error = kDNSServiceErr_NoError;
+    data = rep->sdata;
+    
+    // write reply data to message
+    put_string(fullname, &data);
+    put_string(target, &data);
+    put_short(res->srv->rdata->u.srv.port.NotAnInteger, &data);
+    put_short(res->txt->rdlength, &data);
+    put_rdata(res->txt->rdlength, res->txt->rdata->u.txt.c, &data);
+    
+    result = send_msg(rep);
+    if (result == t_error || result == t_terminated) 
+        {  
+        abort_request(rs);  
+        unlink_request(rs);
+        freeL("resolve_result_callback", rep);  
+        }
+    else if (result == t_complete) freeL("resolve_result_callback", rep);
+    else append_reply(rs, rep);
+    }
+
+
+
+
+// common query issuing routine for resolve and query requests
+static mStatus do_question(request_state *rstate, domainname *name, uint32_t ifi, uint16_t rrtype, int16_t rrclass)
+    {
+    DNSQuestion *q;
+    mStatus result;
+    mDNSInterfaceID InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, ifi);
+    if (ifi && !InterfaceID) return(mStatus_BadParamErr);
+
+    q = mallocL("do_question", sizeof(DNSQuestion));
+    if (!q)
+       {
+        my_perror("ERROR: do_question - malloc");
+        exit(1);
+       }
+    bzero(q, sizeof(DNSQuestion));     
+
+    q->QuestionContext = rstate;
+    q->QuestionCallback = question_result_callback;
+    memcpy(&q->qname, name, MAX_DOMAIN_NAME);
+    q->qtype = rrtype;
+    q->qclass = rrclass;
+    q->InterfaceID = InterfaceID;
+
+
+    rstate->termination_context = q;
+    rstate->terminate = question_termination_callback;
+
+    result = mDNS_StartQuery(&mDNSStorage, q);
+    if (result != mStatus_NoError) LogMsg("ERROR: mDNS_StartQuery: %d", (int)result);
+    return result;
+    }
+    
+// what gets called when a resolve is completed and we need to send the data back to the client
+static void question_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
+    {
+    char *data;
+    char name[MAX_ESCAPED_DOMAIN_NAME];
+    request_state *req;
+    reply_state *rep;
+    int len;
+
+    #pragma unused(m)
+    //mDNS_StopQuery(m, question);
+    req = question->QuestionContext;
+    
+    // calculate reply data length
+    len = sizeof(DNSServiceFlags);
+    len += 2 * sizeof(uint32_t);  // if index + ttl
+    len += sizeof(DNSServiceErrorType);
+    len += 3 * sizeof(uint16_t); // type, class, rdlen
+    len += answer->rdlength;
+    ConvertDomainNameToCString(&answer->name, name);
+    len += strlen(name) + 1;
+    
+    rep =  create_reply(query_reply, len, req);
+    rep->rhdr->flags = AddRecord ? kDNSServiceFlagsAdd : kDNSServiceFlagsRemove;
+    rep->rhdr->ifi =  mDNSPlatformInterfaceIndexfromInterfaceID(&mDNSStorage, answer->InterfaceID);
+    rep->rhdr->error = kDNSServiceErr_NoError;
+    data = rep->sdata;
+    
+    put_string(name, &data);
+    put_short(answer->rrtype, &data);
+    put_short(answer->rrclass, &data);
+    put_short(answer->rdlength, &data);
+    put_rdata(answer->rdlength, (char *)&answer->rdata->u, &data);
+    put_long(AddRecord ? answer->rroriginalttl : 0, &data);
+
+    append_reply(req, rep);
+    return;
+    }
+
+static void question_termination_callback(void *context)
+    {
+    DNSQuestion *q = context;
+
+
+    mDNS_StopQuery(&mDNSStorage, q);  // no need to error check
+    freeL("question_termination_callback", q);
+    }
+
+
+static void handle_browse_request(request_state *request)
+    {
+    DNSServiceFlags flags;
+    uint32_t interfaceIndex;
+    char regtype[MAX_ESCAPED_DOMAIN_NAME], domain[MAX_ESCAPED_DOMAIN_NAME];
+    DNSQuestion *q;
+    domainname typedn, domdn;
+    char *ptr;
+    mStatus result;
+
+    if (request->ts != t_complete)
+        {
+        LogMsg("ERROR: handle_browse_request - transfer state != t_complete");
+        abort_request(request);
+        unlink_request(request);
+        return;
+        }
+    q = mallocL("handle_browse_request", sizeof(DNSQuestion));
+    if (!q)
+       {
+        my_perror("ERROR: handle_browse_request - malloc");
+        exit(1);
+       }
+    bzero(q, sizeof(DNSQuestion));
+
+    // extract data from message
+    ptr = request->msgdata;
+    flags = get_flags(&ptr);
+    interfaceIndex = get_long(&ptr);
+    if (get_string(&ptr, regtype, MAX_ESCAPED_DOMAIN_NAME) < 0 || 
+        get_string(&ptr, domain, MAX_ESCAPED_DOMAIN_NAME) < 0)
+        goto bad_param;
+        
+    freeL("handle_browse_request", request->msgbuf);
+    request->msgbuf = NULL;
+
+    mDNSInterfaceID InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex);
+    if (interfaceIndex && !InterfaceID) goto bad_param;
+    q->QuestionContext = request;
+    q->QuestionCallback = browse_result_callback;
+    if (!MakeDomainNameFromDNSNameString(&typedn, regtype) ||
+        !MakeDomainNameFromDNSNameString(&domdn, domain[0] ? domain : "local."))
+        goto bad_param;
+    request->termination_context = q;
+    request->terminate = browse_termination_callback;
+    result = mDNS_StartBrowse(&mDNSStorage, q, &typedn, &domdn, InterfaceID, browse_result_callback, request);
+    deliver_error(request, result);
+    return;
+    
+bad_param:
+    deliver_error(request, mStatus_BadParamErr);
+    abort_request(request);
+    unlink_request(request);
+    }
+
+static void browse_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
+    {
+    request_state *req;
+    reply_state *rep;
+    mStatus err;
+        
+    #pragma unused(m)
+    req = question->QuestionContext;
+
+    err = gen_rr_response(&answer->rdata->u.name, answer->InterfaceID, req, &rep);
+    if (err)
+        {
+        if (deliver_async_error(req, browse_reply, err) < 0) 
+            {
+            abort_request(req);
+            unlink_request(req);
+            }
+        return;
+        }
+    if (AddRecord) rep->rhdr->flags |= kDNSServiceFlagsAdd;  // non-zero TTL indicates add
+    append_reply(req, rep);
+    return;
+    }
+
+static void browse_termination_callback(void *context)
+    {
+    DNSQuestion *q = context;
+
+    mDNS_StopBrowse(&mDNSStorage, q);  // no need to error-check result
+    freeL("browse_termination_callback", q);
+    }
+
+// service registration
+static void handle_regservice_request(request_state *request)
+    {
+    DNSServiceFlags flags;
+    uint32_t ifi;
+    char name[256], regtype[MAX_ESCAPED_DOMAIN_NAME], domain[MAX_ESCAPED_DOMAIN_NAME], host[MAX_ESCAPED_DOMAIN_NAME];
+    uint16_t txtlen;
+    mDNSIPPort port;
+    void *txtdata;
+    char *ptr;
+    domainlabel n;
+    domainname t, d, h, srv;
+    registered_service *r_srv;
+    int srs_size;
+    mStatus result;
+
+    char *sub, *rtype_ptr;
+    int i, num_subtypes;
+    
+    
+    if (request->ts != t_complete)
+        {
+        LogMsg("ERROR: handle_regservice_request - transfer state != t_complete");
+        abort_request(request);
+        unlink_request(request);
+        return;
+        }
+
+    // extract data from message
+    ptr = request->msgdata;
+    flags = get_flags(&ptr);
+    ifi = get_long(&ptr);
+    mDNSInterfaceID InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, ifi);
+    if (ifi && !InterfaceID) goto bad_param;
+    if (get_string(&ptr, name, 256) < 0 ||
+        get_string(&ptr, regtype, MAX_ESCAPED_DOMAIN_NAME) < 0 || 
+        get_string(&ptr, domain, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
+        get_string(&ptr, host, MAX_ESCAPED_DOMAIN_NAME) < 0)
+        goto bad_param;
+        
+    port.NotAnInteger = get_short(&ptr);
+    txtlen = get_short(&ptr);
+    txtdata = get_rdata(&ptr, txtlen);
+
+    // count subtypes, replacing commas w/ whitespace
+    rtype_ptr = regtype;
+    num_subtypes = -1;
+    while((sub = strsep(&rtype_ptr, ",")))
+        if (*sub) num_subtypes++;
+        
+    if (!name[0]) n = (&mDNSStorage)->nicelabel;
+    else if (!MakeDomainLabelFromLiteralString(&n, name))  
+        goto bad_param;
+    if ((!regtype[0] || !MakeDomainNameFromDNSNameString(&t, regtype)) ||
+    (!MakeDomainNameFromDNSNameString(&d, *domain ? domain : "local.")) ||
+    (!ConstructServiceName(&srv, &n, &t, &d)))
+        goto bad_param;
+    if (host[0] && !MakeDomainNameFromDNSNameString(&h, host)) goto bad_param;
+
+    r_srv = mallocL("handle_regservice_request", sizeof(registered_service));
+    if (!r_srv) goto malloc_error;
+    srs_size = sizeof(ServiceRecordSet) + (sizeof(RDataBody) > txtlen ? 0 : txtlen - sizeof(RDataBody));
+    r_srv->srs = mallocL("handle_regservice_request", srs_size);
+    if (!r_srv->srs) goto malloc_error;
+    if (num_subtypes > 0)
+        {
+        r_srv->subtypes = mallocL("handle_regservice_request", num_subtypes * sizeof(AuthRecord));
+        if (!r_srv->subtypes) goto malloc_error;
+        sub = regtype + strlen(regtype) + 1;
+        for (i = 0; i < num_subtypes; i++)
+            {
+            if (!MakeDomainNameFromDNSNameString(&(r_srv->subtypes + i)->resrec.name, sub))
+                {
+                freeL("handle_regservice_request", r_srv->subtypes);
+                freeL("handle_regservice_request", r_srv);
+                r_srv = NULL;
+                goto bad_param;
+                }
+            sub += strlen(sub) + 1;
+            }
+        }
+    else r_srv->subtypes = NULL;
+    r_srv->request = request;
+    
+    r_srv->autoname = (!name[0]);
+    r_srv->rename_on_memfree = 0;
+    r_srv->renameonconflict = !(flags & kDNSServiceFlagsNoAutoRename);
+    r_srv->name = n;
+    request->termination_context = r_srv;
+    request->terminate = regservice_termination_callback;
+    request->service = r_srv;
+    
+    result = mDNS_RegisterService(&mDNSStorage, r_srv->srs, &n, &t, &d, host[0] ? &h : NULL, port,
+       txtdata, txtlen, r_srv->subtypes, num_subtypes, InterfaceID, regservice_callback, r_srv);
+    deliver_error(request, result);
+    if (result != mStatus_NoError) 
+        {
+        abort_request(request);
+        unlink_request(request);
+        }
+    else 
+        {
+        reset_connected_rstate(request);  // reset to receive add/remove messages
+        }
+    return;
+
+bad_param:
+    deliver_error(request, mStatus_BadParamErr);
+    abort_request(request);
+    unlink_request(request);
+return;
+
+malloc_error:
+    my_perror("ERROR: malloc");
+    exit(1);
+    }
+    
+// service registration callback performs three duties - frees memory for deregistered services,
+// handles name conflicts, and delivers completed registration information to the client (via
+// process_service_registraion())
+
+static void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, mStatus result)
+    {
+    mStatus err;
+    ExtraResourceRecord *extra;
+    registered_service *r_srv = srs->ServiceContext;
+    request_state *rs = r_srv->request;
+
+    #pragma unused(m)
+    
+    if (!rs && (result != mStatus_MemFree && !r_srv->rename_on_memfree))
+        {     
+        // error should never happen - safest to log and continue
+        LogMsg("ERROR: regservice_callback: received result %d with a NULL request pointer\n");
+        return;
+        }
+
+    if (result == mStatus_NoError)
+        return process_service_registration(srs);
+    else if (result == mStatus_MemFree)
+        {
+        if (r_srv->rename_on_memfree)
+            {
+            r_srv->rename_on_memfree = 0;
+            r_srv->name = mDNSStorage.nicelabel;
+            err = mDNS_RenameAndReregisterService(&mDNSStorage, srs, &r_srv->name);
+            if (err) LogMsg("ERROR: regservice_callback - RenameAndReregisterService returned %d", err);
+            // error should never happen - safest to log and continue
+            }
+        else 
+            {
+            while (r_srv->srs->Extras)
+                {
+                extra = r_srv->srs->Extras;
+                r_srv->srs->Extras = r_srv->srs->Extras->next;
+                freeL("regservice_callback", extra);
+                }
+            freeL("regservice_callback", r_srv->srs);
+            if (r_srv->subtypes) freeL("regservice_callback", r_srv->subtypes);
+            if (r_srv->request) r_srv->request->service = NULL;
+            freeL("regservice_callback", r_srv);
+            return;
+            }
+        }
+    else if (result == mStatus_NameConflict)
+       {
+        if (r_srv->autoname || r_srv->renameonconflict)
+            {
+            mDNS_RenameAndReregisterService(&mDNSStorage, srs, mDNSNULL);
+            return;
+            }
+        else
+            {
+            freeL("regservice_callback", r_srv);
+            freeL("regservice_callback", r_srv->srs);
+            if (r_srv->subtypes) freeL("regservice_callback", r_srv->subtypes);
+            if (r_srv->request) r_srv->request->service = NULL;
+            freeL("regservice_callback", r_srv);
+             if (deliver_async_error(rs, reg_service_reply, result) < 0) 
+                {
+                abort_request(rs);
+                unlink_request(rs);
+                }
+            return;
+            }
+       } 
+    else 
+        {
+        LogMsg("ERROR: unknown result in regservice_callback");
+        if (deliver_async_error(rs, reg_service_reply, result) < 0) 
+            {
+            abort_request(rs);
+            unlink_request(rs);
+            }
+        return;
+        }
+    }
+        
+static void handle_add_request(request_state *rstate)
+    {
+    registered_record_entry *re;
+    ExtraResourceRecord *extra;
+    uint32_t size, ttl;
+    uint16_t rrtype, rdlen;
+    char *ptr, *rdata;
+    mStatus result;
+    DNSServiceFlags flags;
+    ServiceRecordSet *srs = rstate->service->srs;
+    
+    if (!srs)
+        {
+        LogMsg("ERROR: handle_add_request - no service record set in request state");
+        deliver_error(rstate, mStatus_UnknownErr);
+        return;
+        }
+        
+    ptr = rstate->msgdata;
+    flags = get_flags(&ptr);
+    rrtype = get_short(&ptr);
+    rdlen = get_short(&ptr);
+    rdata = get_rdata(&ptr, rdlen);
+    ttl = get_long(&ptr);
+    
+    if (rdlen > sizeof(RDataBody)) size = rdlen;
+    else size = sizeof(RDataBody);
+    
+    extra = mallocL("hanle_add_request", sizeof(ExtraResourceRecord) - sizeof(RDataBody) + size);
+    if (!extra)
+        {
+        my_perror("ERROR: malloc");
+        exit(1);
+        }
+        
+    bzero(extra, sizeof(ExtraResourceRecord));  // OK if oversized rdata not zero'd
+    extra->r.resrec.rrtype = rrtype;
+    extra->r.rdatastorage.MaxRDLength = size;
+    extra->r.resrec.rdlength = rdlen;
+    memcpy(&extra->r.rdatastorage.u.data, rdata, rdlen);
+    result =  mDNS_AddRecordToService(&mDNSStorage, srs , extra, &extra->r.rdatastorage, ttl);
+    deliver_error(rstate, result);
+    reset_connected_rstate(rstate);
+    if (result) 
+        {
+        freeL("handle_add_request", rstate->msgbuf);
+        rstate->msgbuf = NULL;
+        freeL("handle_add_request", extra);
+        return;
+        }
+    re = mallocL("handle_add_request", sizeof(registered_record_entry));
+    if (!re)
+        {
+        my_perror("ERROR: malloc");
+        exit(1);
+        }
+    re->key = rstate->hdr.reg_index;
+    re->rr = &extra->r;
+    re->next = rstate->reg_recs;
+    rstate->reg_recs = re;
+    }
+    
+static void handle_update_request(request_state *rstate)
+    {
+    registered_record_entry *reptr;
+    AuthRecord *rr;
+    RData *newrd;
+    uint16_t rdlen, rdsize;
+    char *ptr, *rdata;
+    uint32_t ttl;
+    mStatus result;
+    
+    if (rstate->hdr.reg_index == TXT_RECORD_INDEX)
+        {
+        if (!rstate->service)
+            {
+            deliver_error(rstate, mStatus_BadParamErr);
+            return;
+            }
+        rr  = &rstate->service->srs->RR_TXT;
+        }
+    else
+        {
+        reptr = rstate->reg_recs;
+        while(reptr && reptr->key != rstate->hdr.reg_index) reptr = reptr->next;
+        if (!reptr) deliver_error(rstate, mStatus_BadReferenceErr); 
+        rr = reptr->rr;
+        }
+
+    ptr = rstate->msgdata;
+    get_flags(&ptr);   // flags unused
+    rdlen = get_short(&ptr);
+    rdata = get_rdata(&ptr, rdlen);
+    ttl = get_long(&ptr);
+
+    if (rdlen > sizeof(RDataBody)) rdsize = rdlen;
+    else rdsize = sizeof(RDataBody);
+    newrd = mallocL("handle_update_request", sizeof(RData) - sizeof(RDataBody) + rdsize);
+    if (!newrd)
+        {
+        my_perror("ERROR: malloc");
+        exit(1);
+        }
+    newrd->MaxRDLength = rdsize;
+    memcpy(&newrd->u, rdata, rdlen);
+    result = mDNS_Update(&mDNSStorage, rr, ttl, rdlen, newrd, update_callback);
+    deliver_error(rstate, result);
+    reset_connected_rstate(rstate);
+    }
+    
+static void update_callback(mDNS *const m, AuthRecord *const rr, RData *oldrd)
+    {
+    #pragma unused(m)
+    
+    if (oldrd != &rr->rdatastorage) freeL("update_callback", oldrd);
+    }
+    
+static void process_service_registration(ServiceRecordSet *const srs)
+    {
+    reply_state *rep;
+    transfer_state send_result;
+    mStatus err;
+    registered_service *r_srv = srs->ServiceContext;
+    request_state *req = r_srv->request;
+
+
+    err = gen_rr_response(&srs->RR_SRV.resrec.name, srs->RR_SRV.resrec.InterfaceID, req, &rep);
+    if (err) 
+        {
+        if (deliver_async_error(req, reg_service_reply, err) < 0)
+            {
+            abort_request(req);
+            unlink_request(req);
+            }
+        return;
+        }
+    send_result = send_msg(rep);
+    if (send_result == t_error || send_result == t_terminated) 
+        {  
+        abort_request(req);  
+        unlink_request(req);
+        freeL("process_service_registration", rep);  
+        }
+    else if (send_result == t_complete) freeL("process_service_registration", rep);
+    else append_reply(req, rep);
+    }
+
+static void regservice_termination_callback(void *context)
+    {
+    registered_service *srv = context;
+
+    // only safe to free memory if registration is not valid, ie deregister fails
+    if (mDNS_DeregisterService(&mDNSStorage, srv->srs) != mStatus_NoError)
+        {
+        freeL("regservice_callback", srv->srs);
+        if (srv->subtypes) freeL("regservice_callback", srv->subtypes);
+        freeL("regservice_callback", srv);
+        freeL("regservice_termination_callback", srv);
+        }
+    }
+
+
+static void handle_regrecord_request(request_state *rstate)
+    {
+    AuthRecord *rr;
+    regrecord_callback_context *rcc;
+    registered_record_entry *re;
+    mStatus result;
+    
+    if (rstate->ts != t_complete)
+        {
+        LogMsg("ERROR: handle_regrecord_request - transfer state != t_complete");
+        abort_request(rstate);
+        unlink_request(rstate);
+        return;
+        }
+        
+    rr = read_rr_from_ipc_msg(rstate->msgdata, 1);
+    if (!rr) 
+        {
+        deliver_error(rstate, mStatus_BadParamErr);
+        return;
+        }
+
+    rcc = mallocL("hanlde_regrecord_request", sizeof(regrecord_callback_context));
+    if (!rcc) goto malloc_error;
+    rcc->rstate = rstate;
+    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));
+    if (!re) goto malloc_error;
+    re->key = rstate->hdr.reg_index;
+    re->rr = rr;
+    re->next = rstate->reg_recs;
+    rstate->reg_recs = re;
+
+    if (!rstate->terminate)
+       {
+        rstate->terminate = connected_registration_termination;
+        rstate->termination_context = rstate;
+       }
+    
+    result = mDNS_Register(&mDNSStorage, rr);
+    deliver_error(rstate, result); 
+    reset_connected_rstate(rstate);
+    return;
+
+malloc_error:
+    my_perror("ERROR: malloc");
+    return;
+    }
+
+static void regrecord_callback(mDNS *const m, AuthRecord *const rr, mStatus result)
+    {
+    regrecord_callback_context *rcc;
+    int len;
+    reply_state *reply;
+    transfer_state ts;
+
+    #pragma unused(m)
+
+    if (result == mStatus_MemFree)     { freeL("regrecord_callback", rr);  return; }
+    rcc = rr->RecordContext;
+
+    // format result, add to the list for the request, including the client context in the header
+    len = sizeof(DNSServiceFlags);
+    len += sizeof(uint32_t);                //interfaceIndex
+    len += sizeof(DNSServiceErrorType);
+    
+    reply = create_reply(reg_record_reply, len, rcc->rstate);
+    reply->mhdr->client_context = rcc->client_context;
+    reply->rhdr->flags = 0;
+    reply->rhdr->ifi = mDNSPlatformInterfaceIndexfromInterfaceID(&mDNSStorage, rr->resrec.InterfaceID);
+    reply->rhdr->error = result;
+
+    ts = send_msg(reply);
+    if (ts == t_error || ts == t_terminated) 
+        {
+        abort_request(rcc->rstate);
+        unlink_request(rcc->rstate);
+        }
+    else if (ts == t_complete) freeL("regrecord_callback", reply);
+    else if (ts == t_morecoming) append_reply(rcc->rstate, reply);   // client is blocked, link reply into list
+    }
+
+static void connected_registration_termination(void *context)
+    {
+    registered_record_entry *fptr, *ptr = ((request_state *)context)->reg_recs;
+    while(ptr)
+       {
+        mDNS_Deregister(&mDNSStorage, ptr->rr);
+        fptr = ptr;
+        ptr = ptr->next;
+        freeL("connected_registration_termination", fptr);
+       }
+    }
+    
+
+
+static void handle_removerecord_request(request_state *rstate)
+    {
+    registered_record_entry *reptr, *prev = NULL;
+    mStatus err = mStatus_UnknownErr;
+    char *ptr;
+    reptr = rstate->reg_recs;
+
+    ptr = rstate->msgdata;
+    get_flags(&ptr);   // flags unused
+
+    while(reptr)
+       {
+        if (reptr->key == rstate->hdr.reg_index)  // found match
+            {
+            if (prev) prev->next = reptr->next;
+            else rstate->reg_recs = reptr->next;
+            err  = mDNS_Deregister(&mDNSStorage, reptr->rr);
+            freeL("handle_removerecord_request", reptr);  //rr gets freed by callback
+            break;
+            }
+        prev = reptr;
+        reptr = reptr->next;
+       }
+    reset_connected_rstate(rstate);
+    if (deliver_error(rstate, err) < 0)
+        {
+        abort_request(rstate);
+        unlink_request(rstate);
+        }
+    }
+
+
+// domain enumeration
+static void handle_enum_request(request_state *rstate)
+    {
+    DNSServiceFlags flags, add_default;
+    uint32_t ifi;
+    char *ptr = rstate->msgdata;
+    domain_enum_t *def, *all;
+    enum_termination_t *term;
+    reply_state *reply;  // initial default reply
+    transfer_state tr;
+    mStatus err;
+    int result;
+    
+    if (rstate->ts != t_complete)
+        {
+        LogMsg("ERROR: handle_enum_request - transfer state != t_complete");
+        abort_request(rstate);
+        unlink_request(rstate);
+        return;
+        }
+        
+    flags = get_flags(&ptr);
+    ifi = get_long(&ptr);
+    mDNSInterfaceID InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, ifi);
+    if (ifi && !InterfaceID)
+       {
+               deliver_error(rstate, mStatus_BadParamErr);
+               abort_request(rstate);
+               unlink_request(rstate);
+       }
+
+    // allocate context structures
+    def = mallocL("hanlde_enum_request", sizeof(domain_enum_t));
+    all = mallocL("handle_enum_request", sizeof(domain_enum_t));
+    term = mallocL("handle_enum_request", sizeof(enum_termination_t));
+    if (!def || !all || !term)
+       {
+        my_perror("ERROR: malloc");
+        exit(1);
+       }
+
+    // enumeration requires multiple questions, so we must link all the context pointers so that
+    // necessary context can be reached from the callbacks
+    def->rstate = rstate;
+    all->rstate = rstate;
+    term->def = def;
+    term->all = all;
+    term->rstate = rstate;
+    rstate->termination_context = term;
+    rstate->terminate = enum_termination_callback;
+    def->question.QuestionContext = def;
+    def->type = (flags & kDNSServiceFlagsRegistrationDomains) ? 
+        mDNS_DomainTypeRegistrationDefault: mDNS_DomainTypeBrowseDefault;
+    all->question.QuestionContext = all;
+    all->type = (flags & kDNSServiceFlagsRegistrationDomains) ? 
+        mDNS_DomainTypeRegistration : mDNS_DomainTypeBrowse;
+    
+    // make the calls
+    err = mDNS_GetDomains(&mDNSStorage, &all->question, all->type, InterfaceID, enum_result_callback, all);
+    if (err == mStatus_NoError)
+        err = mDNS_GetDomains(&mDNSStorage, &def->question, def->type, InterfaceID, enum_result_callback, def);
+    result = deliver_error(rstate, err);  // send error *before* returning local domain
+    
+    if (result < 0 || err)
+        {
+        abort_request(rstate);
+        unlink_request(rstate);
+        return;
+        }
+
+    // provide local. as the first domain automatically
+    add_default = kDNSServiceFlagsDefault | kDNSServiceFlagsAdd | kDNSServiceFlagsFinished;
+    reply = format_enumeration_reply(rstate, "local.", add_default, ifi, 0);
+    tr = send_msg(reply);
+    if (tr == t_error || tr == t_terminated) 
+        {
+        freeL("handle_enum_request", def);
+        freeL("handle_enum_request", all);
+        abort_request(rstate);
+        unlink_request(rstate);
+        return;
+        }
+    if (tr == t_complete) freeL("handle_enum_request", reply);
+    if (tr == t_morecoming) append_reply(rstate, reply); // couldn't send whole reply because client is blocked - link into list
+    }
+
+static void enum_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
+    {
+    char domain[MAX_ESCAPED_DOMAIN_NAME];
+    domain_enum_t *de = question->QuestionContext;
+    DNSServiceFlags flags = 0;
+    reply_state *reply;
+
+    #pragma unused(m)
+    if (answer->rrtype != kDNSType_PTR) return;
+    if (AddRecord)
+       {
+        flags |= kDNSServiceFlagsAdd;
+        if (de->type == mDNS_DomainTypeRegistrationDefault || de->type == mDNS_DomainTypeBrowseDefault)
+            flags |= kDNSServiceFlagsDefault;
+       }
+    else
+       {
+        flags |= kDNSServiceFlagsRemove;
+       }
+    ConvertDomainNameToCString(&answer->rdata->u.name, domain);
+    reply = format_enumeration_reply(de->rstate, domain, flags, mDNSPlatformInterfaceIndexfromInterfaceID(&mDNSStorage, answer->InterfaceID), kDNSServiceErr_NoError);
+    if (!reply)
+       {
+        LogMsg("ERROR: enum_result_callback, format_enumeration_reply");
+        return;
+       }
+    reply->next = NULL;
+    append_reply(de->rstate, reply);
+    return;
+    }
+
+static reply_state *format_enumeration_reply(request_state *rstate, char *domain, DNSServiceFlags flags, uint32_t ifi, DNSServiceErrorType err)
+    {
+    int len;
+    reply_state *reply;
+    char *data;
+    
+    
+    len = sizeof(DNSServiceFlags);
+    len += sizeof(uint32_t);
+    len += sizeof(DNSServiceErrorType);
+    len += strlen(domain) + 1;
+  
+    reply = create_reply(enumeration_reply, len, rstate);
+    reply->rhdr->flags = flags;
+    reply->rhdr->ifi = ifi;  
+    reply->rhdr->error = err;
+    data = reply->sdata;
+    put_string(domain, &data);
+    return reply;
+    }
+
+static void enum_termination_callback(void *context)
+    {
+    enum_termination_t *t = context;
+    mDNS *coredata = &mDNSStorage;
+
+    mDNS_StopGetDomains(coredata, &t->all->question);
+    mDNS_StopGetDomains(coredata, &t->def->question);
+    freeL("enum_termination_callback", t->all);
+    freeL("enum_termination_callback", t->def);
+    t->rstate->termination_context = NULL;
+    freeL("enum_termination_callback", t);
+    }
+
+static void handle_reconfirm_request(request_state *rstate)
+    {
+    AuthRecord *rr;
+
+    rr = read_rr_from_ipc_msg(rstate->msgdata, 0);
+    if (!rr) return;
+    mDNS_ReconfirmByValue(&mDNSStorage, &rr->resrec);
+    abort_request(rstate);
+    unlink_request(rstate);
+    freeL("handle_reconfirm_request", rr);
+    }
+
+
+// setup rstate to accept new reg/dereg requests
+static void reset_connected_rstate(request_state *rstate)
+    {
+    rstate->ts = t_morecoming;
+    rstate->hdr_bytes = 0;
+    rstate->data_bytes = 0;
+    if (rstate->msgbuf) freeL("reset_connected_rstate", rstate->msgbuf);
+    rstate->msgbuf = NULL;
+    rstate->bufsize = 0;
+    }
+
+
+
+// returns a resource record (allocated w/ malloc) containing the data found in an IPC message
+// data must be in format flags, interfaceIndex, name, rrtype, rrclass, rdlen, rdata, (optional)ttl
+// (ttl only extracted/set if ttl argument is non-zero).  returns NULL for a bad-parameter error
+static AuthRecord *read_rr_from_ipc_msg(char *msgbuf, int ttl)
+    {
+    char *rdata, name[256];
+    AuthRecord *rr;
+    DNSServiceFlags flags;
+    uint32_t interfaceIndex;
+    uint16_t type, class, rdlen;
+    int storage_size;
+
+    flags = get_flags(&msgbuf);
+    interfaceIndex = get_long(&msgbuf);
+    if (get_string(&msgbuf, name, 256) < 0)
+        {
+        LogMsg("ERROR: read_rr_from_ipc_msg - get_string");
+        return NULL;
+        }
+    type = get_short(&msgbuf);    
+    class = get_short(&msgbuf);
+    rdlen = get_short(&msgbuf);
+
+    if (rdlen > sizeof(RDataBody)) storage_size = rdlen;
+    else storage_size = sizeof(RDataBody);
+    
+    rr = mallocL("read_rr_from_ipc_msg", sizeof(AuthRecord) - sizeof(RDataBody) + storage_size);
+    if (!rr)   
+        { 
+        my_perror("ERROR: malloc");  
+        exit(1);
+        }
+    bzero(rr, sizeof(AuthRecord));  // ok if oversized rdata not zero'd
+    rr->resrec.rdata = &rr->rdatastorage;
+    rr->resrec.InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex);
+    if (!MakeDomainNameFromDNSNameString(&rr->resrec.name, name))
+       {
+        LogMsg("ERROR: bad name: %s", name);
+        freeL("read_rr_from_ipc_msg", rr);
+        return NULL;
+       }
+    rr->resrec.rrtype = type;
+    if ((flags & kDNSServiceFlagsShared) == kDNSServiceFlagsShared)
+        rr->resrec.RecordType = kDNSRecordTypeShared;
+    if ((flags & kDNSServiceFlagsUnique) == kDNSServiceFlagsUnique)
+        rr->resrec.RecordType = kDNSRecordTypeUnique;
+    rr->resrec.rrclass = class;
+    rr->resrec.rdlength = rdlen;
+    rr->resrec.rdata->MaxRDLength = rdlen;
+    rdata = get_rdata(&msgbuf, rdlen);
+    memcpy(rr->resrec.rdata->u.data, rdata, rdlen);
+    if (ttl)   
+       {
+        rr->resrec.rroriginalttl = get_long(&msgbuf);
+       }
+    return rr;
+    }
+
+
+// generate a response message for a browse result, service registration result, or any other call with the
+// identical callback signature.  on successful completion rep is set to point to a malloc'd reply_state struct,
+// and mStatus_NoError is returned.  otherwise the appropriate error is returned.
+
+static mStatus gen_rr_response(domainname *servicename, mDNSInterfaceID id, request_state *request, reply_state **rep)
+    {
+    char *data;
+    int len;
+    domainlabel name;
+    domainname type, dom;
+       char namestr[MAX_DOMAIN_LABEL+1];               // Unescaped name: up to 63 bytes plus C-string terminating NULL.
+       char typestr[MAX_ESCAPED_DOMAIN_NAME];
+       char domstr [MAX_ESCAPED_DOMAIN_NAME];
+
+    *rep = NULL;
+    
+    if (!DeconstructServiceName(servicename, &name, &type, &dom))
+        return kDNSServiceErr_Unknown;
+
+    ConvertDomainLabelToCString_unescaped(&name, namestr);
+    ConvertDomainNameToCString(&type, typestr);
+    ConvertDomainNameToCString(&dom, domstr);
+
+    // calculate reply data length
+    len = sizeof(DNSServiceFlags);
+    len += sizeof(uint32_t);  // if index
+    len += sizeof(DNSServiceErrorType);
+    len += strlen(namestr) + 1;
+    len += strlen(typestr) + 1;
+    len += strlen(domstr) + 1;
+    
+    *rep = create_reply(query_reply, len, request);
+    (*rep)->rhdr->flags = 0;
+    (*rep)->rhdr->ifi = mDNSPlatformInterfaceIndexfromInterfaceID(&mDNSStorage, id);
+    (*rep)->rhdr->error = kDNSServiceErr_NoError;    
+    data = (*rep)->sdata;
+    
+    put_string(namestr, &data);
+    put_string(typestr, &data);
+    put_string(domstr, &data);
+    return mStatus_NoError;
+    }
+
+
+static int build_domainname_from_strings(domainname *srv, char *name, char *regtype, char *domain)
+    {
+    domainlabel n;
+    domainname d, t;
+
+    if (!MakeDomainLabelFromLiteralString(&n, name)) return -1;
+    if (!MakeDomainNameFromDNSNameString(&t, regtype)) return -1;
+    if (!MakeDomainNameFromDNSNameString(&d, domain)) return -1;
+    if (!ConstructServiceName(srv, &n, &t, &d)) return -1;
+    return 0;
+    }
+
+
+// append a reply to the list in a request object
+static void append_reply(request_state *req, reply_state *rep)
+    {
+    reply_state *ptr;
+
+    if (!req->replies) req->replies = rep;
+    else
+       {
+        ptr = req->replies;
+        while (ptr->next) ptr = ptr->next;
+        ptr->next = rep;
+       }
+    rep->next = NULL;
+    }
+
+
+// read_msg may be called any time when the transfer state (rs->ts) is t_morecoming.
+// returns the current state of the request (morecoming, error, complete, terminated.)
+// if there is no data on the socket, the socket will be closed and t_terminated will be returned
+static int read_msg(request_state *rs)
+    {
+    uint32_t nleft;
+    int nread;
+    char buf[4];   // dummy for death notification 
+    
+    if (rs->ts == t_terminated || rs->ts == t_error)
+        {
+        LogMsg("ERROR: read_msg called with transfer state terminated or error");
+        rs->ts = t_error;
+        return t_error;
+        }
+        
+    if (rs->ts == t_complete)
+       {  // this must be death or something is wrong
+        nread = recv(rs->sd, buf, 4, 0);
+        if (!nread)    {  rs->ts = t_terminated;  return t_terminated;         }
+        if (nread < 0) goto rerror;
+        LogMsg("ERROR: read data from a completed request.");
+        rs->ts = t_error;
+        return t_error;
+       }
+
+    if (rs->ts != t_morecoming)
+        {
+        LogMsg("ERROR: read_msg called with invalid transfer state (%d)", rs->ts);
+        rs->ts = t_error;
+        return t_error;
+        }
+        
+    if (rs->hdr_bytes < sizeof(ipc_msg_hdr))
+       {
+        nleft = sizeof(ipc_msg_hdr) - rs->hdr_bytes;
+        nread = recv(rs->sd, (char *)&rs->hdr + rs->hdr_bytes, nleft, 0);
+        if (nread == 0)        { rs->ts = t_terminated;  return t_terminated;          }
+        if (nread < 0) goto rerror;
+        rs->hdr_bytes += nread;
+        if (rs->hdr_bytes > sizeof(ipc_msg_hdr))
+            {
+            LogMsg("ERROR: read_msg - read too many header bytes");
+            rs->ts = t_error;
+            return t_error;
+            }
+       }
+
+    // only read data if header is complete
+    if (rs->hdr_bytes == sizeof(ipc_msg_hdr))
+       {
+        if (rs->hdr.datalen == 0)  // ok in removerecord requests
+            {
+            rs->ts = t_complete;
+            rs->msgbuf = NULL;
+            return t_complete;
+            }
+        
+        if (!rs->msgbuf)  // allocate the buffer first time through
+            {
+            rs->msgbuf = mallocL("read_msg", rs->hdr.datalen);
+            if (!rs->msgbuf)
+               {
+                my_perror("ERROR: malloc");
+                rs->ts = t_error;
+                return t_error;
+               }
+            rs->msgdata = rs->msgbuf;
+            }
+        nleft = rs->hdr.datalen - rs->data_bytes;
+        nread = recv(rs->sd, rs->msgbuf + rs->data_bytes, nleft, 0);
+        if (nread == 0)        { rs->ts = t_terminated;  return t_terminated;  }
+        if (nread < 0) goto rerror;
+        rs->data_bytes += nread;
+        if (rs->data_bytes > rs->hdr.datalen)
+            {
+            LogMsg("ERROR: read_msg - read too many data bytes");
+            rs->ts = t_error;
+            return t_error;
+            }
+        }
+
+    if (rs->hdr_bytes == sizeof(ipc_msg_hdr) && rs->data_bytes == rs->hdr.datalen)
+        rs->ts = t_complete;
+    else rs->ts = t_morecoming;
+
+    return rs->ts;
+
+rerror:
+    if (errno == EAGAIN || errno == EINTR) return rs->ts;      
+    my_perror("ERROR: read_msg");
+    rs->ts = t_error;
+    return t_error;
+    }
+
+
+static int send_msg(reply_state *rs)
+    {
+    ssize_t nwriten;
+    
+    if (!rs->msgbuf)
+        {
+        LogMsg("ERROR: send_msg called with NULL message buffer");
+        return t_error;
+        }
+    
+    if (rs->request->no_reply) //!!!KRS this behavior should be optimized if it becomes more common
+        {
+        rs->ts = t_complete;
+        freeL("send_msg", rs->msgbuf);
+        return t_complete;
+        }
+
+    nwriten = send(rs->sd, rs->msgbuf + rs->nwriten, rs->len - rs->nwriten, 0);
+    if (nwriten < 0)
+       {
+        if (errno == EINTR || errno == EAGAIN) nwriten = 0;
+        else
+            {
+            if (errno == EPIPE)
+               {
+                LogMsg("broken pipe - cleanup should be handled by run-loop read wakeup");
+                rs->ts = t_terminated;
+                rs->request->ts = t_terminated;
+                return t_terminated;  
+               }
+            else
+               {
+                my_perror("ERROR: send\n");
+                rs->ts = t_error;
+                return t_error;
+               }
+            }
+        }
+    rs->nwriten += nwriten;
+
+    if (rs->nwriten == rs->len)
+       {
+        rs->ts = t_complete;
+        freeL("send_msg", rs->msgbuf);
+       }
+    return rs->ts;
+    }
+
+
+
+static reply_state *create_reply(reply_op_t op, int datalen, request_state *request)
+{
+    reply_state *reply;
+    int totallen;
+
+    
+    if ((unsigned)datalen < sizeof(reply_hdr))
+        {
+        LogMsg("ERROR: create_reply - data length less than lenght of required fields");
+        return NULL;
+        }
+    
+    totallen = datalen + sizeof(ipc_msg_hdr);
+    reply = mallocL("create_reply", sizeof(reply_state));
+    if (!reply) 
+        {
+        my_perror("ERROR: malloc");
+        exit(1);
+        }
+    bzero(reply, sizeof(reply_state));
+    reply->ts = t_morecoming;
+    reply->sd = request->sd;
+    reply->request = request;
+    reply->len = totallen;
+    reply->msgbuf = mallocL("create_reply", totallen);
+    if (!reply->msgbuf)
+        {
+        my_perror("ERROR: malloc");
+        exit(1);
+        }
+    bzero(reply->msgbuf, totallen);
+    reply->mhdr = (ipc_msg_hdr *)reply->msgbuf;
+    reply->rhdr = (reply_hdr *)(reply->msgbuf + sizeof(ipc_msg_hdr));
+    reply->sdata = reply->msgbuf + sizeof(ipc_msg_hdr) + sizeof(reply_hdr);
+    reply->mhdr->version = VERSION;
+    reply->mhdr->op.reply_op = op;
+    reply->mhdr->datalen = totallen - sizeof(ipc_msg_hdr);
+    return reply;
+    }
+
+
+static int deliver_error(request_state *rstate, mStatus err)
+    {
+    int nwritten = -1;
+    undelivered_error_t *undeliv;
+    
+    nwritten = send(rstate->errfd, &err, sizeof(mStatus), 0);
+    if (nwritten < (int)sizeof(mStatus))
+        {
+        if (errno == EINTR || errno == EAGAIN)   
+            nwritten = 0;
+        if (nwritten < 0)
+            {
+            my_perror("ERROR: send - unable to deliver error to client");
+            goto error;
+            }
+        //client blocked - store result and come backr
+        undeliv = mallocL("deliver_error", sizeof(undelivered_error_t));
+        if (!undeliv)
+            {
+            my_perror("ERROR: malloc");
+            exit(1);
+            }
+        undeliv->err = err;
+        undeliv->nwritten = nwritten;
+        undeliv->sd = rstate->errfd;
+        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)
+static transfer_state send_undelivered_error(request_state *rs)
+    {
+    int nwritten;
+    
+    nwritten = send(rs->u_err->sd, (char *)(&rs->u_err) + rs->u_err->nwritten, sizeof(mStatus) - rs->u_err->nwritten, 0);
+    if (nwritten < 0)
+        {
+        if (errno == EINTR || errno == EAGAIN)
+            nwritten = 0;
+        else
+            {
+            my_perror("ERROR: send - unable to deliver error to client\n");
+            if (rs->u_err->sd == rs->sd) close (rs->u_err->sd);
+            return t_error;
+            }
+        }
+    if (nwritten + rs->u_err->nwritten == sizeof(mStatus))
+        {
+        if (rs->u_err->sd == rs->sd) close(rs->u_err->sd);
+        freeL("send_undelivered_error", rs->u_err);
+        rs->u_err = NULL;
+        return t_complete;
+        }
+    rs->u_err->nwritten += nwritten;
+    return t_morecoming;
+    }
+
+
+// send bogus data along with an error code to the app callback
+// returns 0 on success (linking reply into list of not fully delivered),
+// -1 on failure (request should be aborted)
+static int deliver_async_error(request_state *rs, reply_op_t op, mStatus err)
+    {
+    int len;
+    reply_state *reply;
+    transfer_state ts;
+    
+    if (rs->no_reply) return 0;
+    len = 256;         // long enough for any reply handler to read all args w/o buffer overrun
+    reply = create_reply(op, len, rs);
+    reply->rhdr->error = err;
+    ts = send_msg(reply);
+    if (ts == t_error || ts == t_terminated)
+        {
+        freeL("deliver_async_error", reply);
+        return -1;
+        }
+    else if (ts == t_complete) freeL("deliver_async_error", reply);
+    else if (ts == t_morecoming) append_reply(rs, reply);   // client is blocked, link reply into list
+    return 0;
+    }
+
+
+static void abort_request(request_state *rs)
+    {
+    reply_state *rep, *ptr;
+
+    if (rs->terminate) rs->terminate(rs->termination_context);  // terminate field may not be set yet
+    if (rs->msgbuf) freeL("abort_request", rs->msgbuf);
+    CFRunLoopRemoveSource(CFRunLoopGetCurrent(), rs->rls, kCFRunLoopDefaultMode);
+    CFRunLoopSourceInvalidate(rs->rls);
+    CFRelease(rs->rls);
+    CFSocketInvalidate(rs->sr);
+    CFRelease(rs->sr);
+    rs->sd = -1;
+    if (rs->errfd >= 0) close(rs->errfd);
+    rs->errfd = -1;
+
+    // free pending replies
+    rep = rs->replies;
+    while(rep)
+       {
+        if (rep->msgbuf) freeL("abort_request", rep->msgbuf);
+        ptr = rep;
+        rep = rep->next;
+        freeL("abort_request", ptr);
+       }
+    
+    if (rs->u_err)
+        {
+        freeL("abort_request", rs->u_err);
+        rs->u_err = NULL;
+        }
+    }
+
+
+static void unlink_request(request_state *rs)
+    {
+    request_state *ptr;
+    
+    if (rs == all_requests)
+        {
+        all_requests = all_requests->next;
+        freeL("unlink_request", rs);
+        return;
+        }
+    for(ptr = all_requests; ptr->next; ptr = ptr->next)
+        if (ptr->next == rs)
+            {
+            ptr->next = rs->next;
+            freeL("unlink_request", rs);
+            return;
+        }
+    }
+    
+
+
+//hack to search-replace perror's to LogMsg's
+static void my_perror(char *errmsg)
+    {
+    LogMsg("%s: %s", errmsg, strerror(errno));
+    }
+
+
index 560c75ff3e36688dbee600ff1d46e3f414ed42f5..b482fb89c643c30f0f98e3c39c1d8b38a97486a7 100644 (file)
@@ -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
index 537c0eedcc7576c146cef683478057af02ea4962..de026a47dcbedb22f2b6f6b48e5758283710b3bf 100644 (file)
@@ -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
index 6e23cf336e5021b9bd5ceb007c1da4b669cdb084..cd8cafb1a963519ca6e448ea1e344ad878e5efb6 100644 (file)
@@ -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
index 40256a0d96580546ec2f8a32b6c66c18f21704f9..11c9149ddacd28ea0a43e59ff5b7c5e15e71d565 100644 (file)
@@ -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
index de05091330340e3544be8a6f7576730c54e07b9d..396b7e9fd5c06a555278806fbd6f7abfcf85ade0 100644 (file)
@@ -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
index 37df61a118feab63771a1e3cb7a58b78d56bd7ed..e174e4f06a7c278fdafa4d207f95f79ae1b183bd 100644 (file)
@@ -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
index 0dfbd5b0ca00dcf05813a75a8cea44472eb149ef..ddd81f901a83d3fd0f196aa6b924fe399b1ae91e 100644 (file)
@@ -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
index 3a0cdb24054abda14d847e3fbcbb6f83fe786447..7acb0b512a1be39de67aa0228c2b499cdeaaf054 100644 (file)
@@ -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
index e5dc4f799ccd8aad59778005f96c266f40c5bd36..a26a1e759b68fda74fe0281d5f9fc8df7c43fc0c 100644 (file)
@@ -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
index 73c2505811f0fcf91add4a3f5284a4d52d7c68d6..3c16ff761f4a3b88ca416c6b2adc742c5d14b7c3 100644 (file)
@@ -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
index 5bc823ef56c1f63fdf33321de83950439da63603..ba28f412b32572e06e1e9bae165ab7fafe9b148b 100644 (file)
@@ -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
index fb1437ff298649ef64c492bffdbc2e84763da86c..1f4fe133816f955cb4f09d80b1d8861faa56f3d4 100644 (file)
@@ -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
index de86ab868acdb5eca8f9a63bdcdf879dbc579953..991fc08b97ae6815528e53aa6c330483ed25ab77 100644 (file)
@@ -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
index 43f3e6d6f510af0fc6b98f67c378d29cb8893598..77775105d88e217313d0571970e29c9a4db8cb34 100644 (file)
@@ -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
index 506a6bef902ce2f4bbcb887a524b3d028efbded7..6622a5dd2d1b53baf16dd772eddda1eba412b7c9 100644 (file)
@@ -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
index fb4331e9bcbe8162173954550ebb1e50374be2d9..3672152459ed954d69746d50ca97362325ce8d7d 100644 (file)
@@ -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
index beda06624cf9870934032f6d86aa4d31f0e8f932..7e49566e1d1f4cbac12812184d72edec03334c29 100644 (file)
@@ -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
index af1135d16484193dc6b0bdc6ec884b0a8ddf40a7..eaa6a70e675a9ac7bdf1f691da1e2780621fe864 100644 (file)
@@ -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
index 41f56e8075c2e603abae71bccbaff4b2b98e93fc..1f76fc225f4d84ab84adf32267013e46fda91931 100644 (file)
@@ -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
index 0fa57f3f2f37d589db54717a0c5ad13a9a2c10ee..77e3dcb13e72718abbaa21d31bd0c54b310f21e1 100644 (file)
@@ -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
index d1323002214b6ea500222acb68129a3fec04cbe3..618bbb3d3e37459b43ea8f48afda5ef60bfaa2b9 100644 (file)
@@ -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
index edb704759f72de4220d720a97f4f326b409e1f8d..ca84436895996fc920521ca60ea7b3e77ecac04e 100755 (executable)
@@ -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
index d1fb0393008b8a81dd96bbf17cea316d44c96c5d..f5be4aabc1f4b1b042187139b9a7614a42563ae9 100755 (executable)
@@ -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
index e1f012e597bcb23d4fdb10438dffef59bae5f563..161e635e0f50e8b23f24c5ff85050928ac8ed558 100755 (executable)
@@ -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
index 492dbb6a366d62caf9a8c63362517bc05ca0eb5e..2bf5ddd55da27ba8f962f47c6a1b3c11cca0a7bc 100755 (executable)
@@ -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