From: Apple Date: Sat, 20 Dec 2003 02:16:26 +0000 (+0000) Subject: mDNSResponder-58.3.tar.gz X-Git-Tag: v58.3^0 X-Git-Url: https://git.saurik.com/apple/mdnsresponder.git/commitdiff_plain/8abd123626ad1b60fee108d578e684e40d129d0a mDNSResponder-58.3.tar.gz --- diff --git a/Makefile b/Makefile index 0e843e9..4a5b090 100644 --- 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) diff --git a/mDNSCore/mDNS.c b/mDNSCore/mDNS.c index 13ff2f0..8edb170 100755 --- a/mDNSCore/mDNS.c +++ b/mDNSCore/mDNS.c @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in @@ -46,6 +44,11 @@ Change History (most recent first): $Log: mDNS.c,v $ +Revision 1.307.2.2 2003/12/20 01:51:40 cheshire +: 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 : 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 { diff --git a/mDNSCore/mDNSClientAPI.h b/mDNSCore/mDNSClientAPI.h index e7e56cf..1297a21 100755 --- a/mDNSCore/mDNSClientAPI.h +++ b/mDNSCore/mDNSClientAPI.h @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/mDNSCore/mDNSDebug.h b/mDNSCore/mDNSDebug.h index 0ac194f..65b6daf 100755 --- a/mDNSCore/mDNSDebug.h +++ b/mDNSCore/mDNSDebug.h @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/mDNSCore/mDNSPlatformFunctions.h b/mDNSCore/mDNSPlatformFunctions.h index 71645b2..8f07d59 100755 --- a/mDNSCore/mDNSPlatformFunctions.h +++ b/mDNSCore/mDNSPlatformFunctions.h @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/mDNSMacOS9/CarbonResource.r b/mDNSMacOS9/CarbonResource.r index 853a4ac..105a398 100644 --- a/mDNSMacOS9/CarbonResource.r +++ b/mDNSMacOS9/CarbonResource.r @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/mDNSMacOS9/Mac OS Test Responder.c b/mDNSMacOS9/Mac OS Test Responder.c index bd8f376..7c55ca3 100644 --- a/mDNSMacOS9/Mac OS Test Responder.c +++ b/mDNSMacOS9/Mac OS Test Responder.c @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/mDNSMacOS9/Mac OS Test Searcher.c b/mDNSMacOS9/Mac OS Test Searcher.c index fc5d803..d55dcd5 100644 --- a/mDNSMacOS9/Mac OS Test Searcher.c +++ b/mDNSMacOS9/Mac OS Test Searcher.c @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/mDNSMacOS9/mDNSMacOS9.c b/mDNSMacOS9/mDNSMacOS9.c index efef8b8..cdb49b3 100644 --- a/mDNSMacOS9/mDNSMacOS9.c +++ b/mDNSMacOS9/mDNSMacOS9.c @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/mDNSMacOS9/mDNSMacOS9.h b/mDNSMacOS9/mDNSMacOS9.h index 1256183..d707f9f 100755 --- a/mDNSMacOS9/mDNSMacOS9.h +++ b/mDNSMacOS9/mDNSMacOS9.h @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/mDNSMacOS9/mDNSPrefixCarbon.h b/mDNSMacOS9/mDNSPrefixCarbon.h index d05d257..95f1a48 100644 --- a/mDNSMacOS9/mDNSPrefixCarbon.h +++ b/mDNSMacOS9/mDNSPrefixCarbon.h @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/mDNSMacOS9/mDNSPrefixCarbonDebug.h b/mDNSMacOS9/mDNSPrefixCarbonDebug.h index 4824cc2..2c31a97 100644 --- a/mDNSMacOS9/mDNSPrefixCarbonDebug.h +++ b/mDNSMacOS9/mDNSPrefixCarbonDebug.h @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/mDNSMacOS9/mDNSPrefixClassic.h b/mDNSMacOS9/mDNSPrefixClassic.h index 9cc2013..d275361 100644 --- a/mDNSMacOS9/mDNSPrefixClassic.h +++ b/mDNSMacOS9/mDNSPrefixClassic.h @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/mDNSMacOSX/Applications/DNSServiceBrowser/BrowserController.h b/mDNSMacOSX/Applications/DNSServiceBrowser/BrowserController.h index 8f81a9f..f58c914 100755 --- a/mDNSMacOSX/Applications/DNSServiceBrowser/BrowserController.h +++ b/mDNSMacOSX/Applications/DNSServiceBrowser/BrowserController.h @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/mDNSMacOSX/Applications/DNSServiceBrowser/BrowserController.m b/mDNSMacOSX/Applications/DNSServiceBrowser/BrowserController.m index a3e9cb0..1dbe2a4 100755 --- a/mDNSMacOSX/Applications/DNSServiceBrowser/BrowserController.m +++ b/mDNSMacOSX/Applications/DNSServiceBrowser/BrowserController.m @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/mDNSMacOSX/Applications/DNSServiceBrowser/main.m b/mDNSMacOSX/Applications/DNSServiceBrowser/main.m index 492c5c2..c340509 100644 --- a/mDNSMacOSX/Applications/DNSServiceBrowser/main.m +++ b/mDNSMacOSX/Applications/DNSServiceBrowser/main.m @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/mDNSMacOSX/Applications/DNSServiceRegistration/RegistrationController.h b/mDNSMacOSX/Applications/DNSServiceRegistration/RegistrationController.h index df059d8..ca53bf2 100644 --- a/mDNSMacOSX/Applications/DNSServiceRegistration/RegistrationController.h +++ b/mDNSMacOSX/Applications/DNSServiceRegistration/RegistrationController.h @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/mDNSMacOSX/Applications/DNSServiceRegistration/RegistrationController.m b/mDNSMacOSX/Applications/DNSServiceRegistration/RegistrationController.m index 3b2226c..6255179 100644 --- a/mDNSMacOSX/Applications/DNSServiceRegistration/RegistrationController.m +++ b/mDNSMacOSX/Applications/DNSServiceRegistration/RegistrationController.m @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/mDNSMacOSX/Applications/DNSServiceRegistration/main.m b/mDNSMacOSX/Applications/DNSServiceRegistration/main.m index 492c5c2..c340509 100644 --- a/mDNSMacOSX/Applications/DNSServiceRegistration/main.m +++ b/mDNSMacOSX/Applications/DNSServiceRegistration/main.m @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/mDNSMacOSX/Applications/HAAutomounter/HAAutomounter.h b/mDNSMacOSX/Applications/HAAutomounter/HAAutomounter.h index 928cf02..7bb3e90 100644 --- a/mDNSMacOSX/Applications/HAAutomounter/HAAutomounter.h +++ b/mDNSMacOSX/Applications/HAAutomounter/HAAutomounter.h @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/mDNSMacOSX/Applications/HAAutomounter/HAAutomounter.m b/mDNSMacOSX/Applications/HAAutomounter/HAAutomounter.m index 9647f6f..4aae5ed 100644 --- a/mDNSMacOSX/Applications/HAAutomounter/HAAutomounter.m +++ b/mDNSMacOSX/Applications/HAAutomounter/HAAutomounter.m @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/mDNSMacOSX/Applications/HAAutomounter/main.m b/mDNSMacOSX/Applications/HAAutomounter/main.m index 53b9e68..6ad4471 100644 --- a/mDNSMacOSX/Applications/HAAutomounter/main.m +++ b/mDNSMacOSX/Applications/HAAutomounter/main.m @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/mDNSMacOSX/CFSocket.c b/mDNSMacOSX/CFSocket.c index 0552040..519a899 100644 --- a/mDNSMacOSX/CFSocket.c +++ b/mDNSMacOSX/CFSocket.c @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/mDNSMacOSX/CFSocketPuma.c b/mDNSMacOSX/CFSocketPuma.c index 3a7e266..e0cf87c 100644 --- a/mDNSMacOSX/CFSocketPuma.c +++ b/mDNSMacOSX/CFSocketPuma.c @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/mDNSMacOSX/DNSServiceDiscoveryDefines.h b/mDNSMacOSX/DNSServiceDiscoveryDefines.h index bd5b11b..b6d3a9a 100644 --- a/mDNSMacOSX/DNSServiceDiscoveryDefines.h +++ b/mDNSMacOSX/DNSServiceDiscoveryDefines.h @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/mDNSMacOSX/DNSServiceDiscoveryReply.defs b/mDNSMacOSX/DNSServiceDiscoveryReply.defs index 6ae6004..942fb6b 100644 --- a/mDNSMacOSX/DNSServiceDiscoveryReply.defs +++ b/mDNSMacOSX/DNSServiceDiscoveryReply.defs @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/mDNSMacOSX/DNSServiceDiscoveryRequest.defs b/mDNSMacOSX/DNSServiceDiscoveryRequest.defs index a4596af..eb400b1 100644 --- a/mDNSMacOSX/DNSServiceDiscoveryRequest.defs +++ b/mDNSMacOSX/DNSServiceDiscoveryRequest.defs @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/mDNSMacOSX/SampleUDSClient.c b/mDNSMacOSX/SampleUDSClient.c index bca8eea..7838fc1 100755 --- a/mDNSMacOSX/SampleUDSClient.c +++ b/mDNSMacOSX/SampleUDSClient.c @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/mDNSMacOSX/SamplemDNSClient.c b/mDNSMacOSX/SamplemDNSClient.c index 1b824dd..f905bd7 100644 --- a/mDNSMacOSX/SamplemDNSClient.c +++ b/mDNSMacOSX/SamplemDNSClient.c @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/mDNSMacOSX/daemon.c b/mDNSMacOSX/daemon.c index d0af244..35baa0d 100644 --- a/mDNSMacOSX/daemon.c +++ b/mDNSMacOSX/daemon.c @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in @@ -38,6 +36,9 @@ Change History (most recent first): $Log: daemon.c,v $ +Revision 1.134.2.3 2003/12/12 01:21:30 cheshire + mDNSResponder should not run as root + Revision 1.134.2.2 2003/12/05 00:03:35 cheshire Use buffer size MAX_ESCAPED_DOMAIN_NAME instead of 256 @@ -204,6 +205,7 @@ Add $Log header #include #include #include +#include #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; diff --git a/mDNSMacOSX/dns_sd.h b/mDNSMacOSX/dns_sd.h index 9b9c037..eaed335 100755 --- a/mDNSMacOSX/dns_sd.h +++ b/mDNSMacOSX/dns_sd.h @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/mDNSMacOSX/dnssd_clientstub.c b/mDNSMacOSX/dnssd_clientstub.c index a5b1ef7..7277eda 100755 --- a/mDNSMacOSX/dnssd_clientstub.c +++ b/mDNSMacOSX/dnssd_clientstub.c @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/mDNSMacOSX/dnssd_ipc.c b/mDNSMacOSX/dnssd_ipc.c index 3ee14b5..186f4d3 100644 --- a/mDNSMacOSX/dnssd_ipc.c +++ b/mDNSMacOSX/dnssd_ipc.c @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/mDNSMacOSX/dnssd_ipc.h b/mDNSMacOSX/dnssd_ipc.h index 4585284..2b7b323 100644 --- a/mDNSMacOSX/dnssd_ipc.h +++ b/mDNSMacOSX/dnssd_ipc.h @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/mDNSMacOSX/mDNSMacOSX.h b/mDNSMacOSX/mDNSMacOSX.h index f5a7656..b255cd0 100644 --- a/mDNSMacOSX/mDNSMacOSX.h +++ b/mDNSMacOSX/mDNSMacOSX.h @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/mDNSMacOSX/uds_daemon.c b/mDNSMacOSX/uds_daemon.c index 9c5a653..5cc63fc 100644 --- a/mDNSMacOSX/uds_daemon.c +++ b/mDNSMacOSX/uds_daemon.c @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/mDNSPosix/Client.c b/mDNSPosix/Client.c index 193272d..bf223d1 100755 --- a/mDNSPosix/Client.c +++ b/mDNSPosix/Client.c @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/mDNSPosix/ExampleClientApp.c b/mDNSPosix/ExampleClientApp.c index 8561388..a0531bc 100644 --- a/mDNSPosix/ExampleClientApp.c +++ b/mDNSPosix/ExampleClientApp.c @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/mDNSPosix/ExampleClientApp.h b/mDNSPosix/ExampleClientApp.h index d9b20c5..4274a46 100644 --- a/mDNSPosix/ExampleClientApp.h +++ b/mDNSPosix/ExampleClientApp.h @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/mDNSPosix/Identify.c b/mDNSPosix/Identify.c index f773796..412f829 100644 --- a/mDNSPosix/Identify.c +++ b/mDNSPosix/Identify.c @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/mDNSPosix/NetMonitor.c b/mDNSPosix/NetMonitor.c index 3b7aff0..8a90d24 100644 --- a/mDNSPosix/NetMonitor.c +++ b/mDNSPosix/NetMonitor.c @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/mDNSPosix/ProxyResponder.c b/mDNSPosix/ProxyResponder.c index 193b082..a982423 100644 --- a/mDNSPosix/ProxyResponder.c +++ b/mDNSPosix/ProxyResponder.c @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/mDNSPosix/Responder.c b/mDNSPosix/Responder.c index d644675..6130e0c 100755 --- a/mDNSPosix/Responder.c +++ b/mDNSPosix/Responder.c @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/mDNSPosix/mDNSPosix.c b/mDNSPosix/mDNSPosix.c index 3d289e6..9092fdd 100755 --- a/mDNSPosix/mDNSPosix.c +++ b/mDNSPosix/mDNSPosix.c @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/mDNSPosix/mDNSPosix.h b/mDNSPosix/mDNSPosix.h index 915acb7..a254568 100755 --- a/mDNSPosix/mDNSPosix.h +++ b/mDNSPosix/mDNSPosix.h @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/mDNSPosix/mDNSUNP.c b/mDNSPosix/mDNSUNP.c index 26699f0..fa9bda0 100755 --- a/mDNSPosix/mDNSUNP.c +++ b/mDNSPosix/mDNSUNP.c @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/mDNSPosix/mDNSUNP.h b/mDNSPosix/mDNSUNP.h index a764aa0..21d13f1 100755 --- a/mDNSPosix/mDNSUNP.h +++ b/mDNSPosix/mDNSUNP.h @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/mDNSShared/dns_sd.h b/mDNSShared/dns_sd.h new file mode 100755 index 0000000..eaed335 --- /dev/null +++ b/mDNSShared/dns_sd.h @@ -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 +#include +#include +#include + + +/* 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. + * ... + * + * 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 ... + * (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 index 0000000..7277eda --- /dev/null +++ b/mDNSShared/dnssd_clientstub.c @@ -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 index 0000000..186f4d3 --- /dev/null +++ b/mDNSShared/dnssd_ipc.c @@ -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 index 0000000..2b7b323 --- /dev/null +++ b/mDNSShared/dnssd_ipc.h @@ -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 +#include +#include +#include +#include +#include +#include + +//#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 index 0000000..5cc63fc --- /dev/null +++ b/mDNSShared/uds_daemon.c @@ -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 + Use buffer size MAX_ESCAPED_DOMAIN_NAME instead of 256 + +Revision 1.22 2003/08/19 16:03:55 ksekar +Bug #: : 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 + SIGINFO dump should include resolves started by DNSServiceQueryRecord + +Revision 1.20 2003/08/16 03:39:01 cheshire + InterfaceID -1 indicates "local only" + +Revision 1.19 2003/08/15 20:16:03 cheshire + 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 #: : Bug: buffer overrun when reading long rdata from client + +Revision 1.17 2003/08/14 02:18:21 cheshire + Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord + +Revision 1.16 2003/08/13 23:58:52 ksekar +Bug #: : 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 #: : 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 +#include +#include +#include +#include + +// 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)); + } + + diff --git a/mDNSVxWorks/mDNSVxWorks.c b/mDNSVxWorks/mDNSVxWorks.c index 560c75f..b482fb8 100644 --- a/mDNSVxWorks/mDNSVxWorks.c +++ b/mDNSVxWorks/mDNSVxWorks.c @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/mDNSVxWorks/mDNSVxWorks.h b/mDNSVxWorks/mDNSVxWorks.h index 537c0ee..de026a4 100644 --- a/mDNSVxWorks/mDNSVxWorks.h +++ b/mDNSVxWorks/mDNSVxWorks.h @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/mDNSWindows/Applications/RendezvousBrowser/Windows/Sources/AboutDialog.cpp b/mDNSWindows/Applications/RendezvousBrowser/Windows/Sources/AboutDialog.cpp index 6e23cf3..cd8cafb 100644 --- a/mDNSWindows/Applications/RendezvousBrowser/Windows/Sources/AboutDialog.cpp +++ b/mDNSWindows/Applications/RendezvousBrowser/Windows/Sources/AboutDialog.cpp @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/mDNSWindows/Applications/RendezvousBrowser/Windows/Sources/AboutDialog.h b/mDNSWindows/Applications/RendezvousBrowser/Windows/Sources/AboutDialog.h index 40256a0..11c9149 100644 --- a/mDNSWindows/Applications/RendezvousBrowser/Windows/Sources/AboutDialog.h +++ b/mDNSWindows/Applications/RendezvousBrowser/Windows/Sources/AboutDialog.h @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/mDNSWindows/Applications/RendezvousBrowser/Windows/Sources/Application.cpp b/mDNSWindows/Applications/RendezvousBrowser/Windows/Sources/Application.cpp index de05091..396b7e9 100644 --- a/mDNSWindows/Applications/RendezvousBrowser/Windows/Sources/Application.cpp +++ b/mDNSWindows/Applications/RendezvousBrowser/Windows/Sources/Application.cpp @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/mDNSWindows/Applications/RendezvousBrowser/Windows/Sources/Application.h b/mDNSWindows/Applications/RendezvousBrowser/Windows/Sources/Application.h index 37df61a..e174e4f 100644 --- a/mDNSWindows/Applications/RendezvousBrowser/Windows/Sources/Application.h +++ b/mDNSWindows/Applications/RendezvousBrowser/Windows/Sources/Application.h @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/mDNSWindows/Applications/RendezvousBrowser/Windows/Sources/ChooserDialog.cpp b/mDNSWindows/Applications/RendezvousBrowser/Windows/Sources/ChooserDialog.cpp index 0dfbd5b..ddd81f9 100644 --- a/mDNSWindows/Applications/RendezvousBrowser/Windows/Sources/ChooserDialog.cpp +++ b/mDNSWindows/Applications/RendezvousBrowser/Windows/Sources/ChooserDialog.cpp @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/mDNSWindows/Applications/RendezvousBrowser/Windows/Sources/ChooserDialog.h b/mDNSWindows/Applications/RendezvousBrowser/Windows/Sources/ChooserDialog.h index 3a0cdb2..7acb0b5 100644 --- a/mDNSWindows/Applications/RendezvousBrowser/Windows/Sources/ChooserDialog.h +++ b/mDNSWindows/Applications/RendezvousBrowser/Windows/Sources/ChooserDialog.h @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/mDNSWindows/Applications/RendezvousBrowser/Windows/Sources/StdAfx.cpp b/mDNSWindows/Applications/RendezvousBrowser/Windows/Sources/StdAfx.cpp index e5dc4f7..a26a1e7 100644 --- a/mDNSWindows/Applications/RendezvousBrowser/Windows/Sources/StdAfx.cpp +++ b/mDNSWindows/Applications/RendezvousBrowser/Windows/Sources/StdAfx.cpp @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/mDNSWindows/Applications/RendezvousBrowser/Windows/Sources/StdAfx.h b/mDNSWindows/Applications/RendezvousBrowser/Windows/Sources/StdAfx.h index 73c2505..3c16ff7 100644 --- a/mDNSWindows/Applications/RendezvousBrowser/Windows/Sources/StdAfx.h +++ b/mDNSWindows/Applications/RendezvousBrowser/Windows/Sources/StdAfx.h @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/mDNSWindows/Applications/RendezvousBrowser/WindowsCE/Sources/Application.cpp b/mDNSWindows/Applications/RendezvousBrowser/WindowsCE/Sources/Application.cpp index 5bc823e..ba28f41 100644 --- a/mDNSWindows/Applications/RendezvousBrowser/WindowsCE/Sources/Application.cpp +++ b/mDNSWindows/Applications/RendezvousBrowser/WindowsCE/Sources/Application.cpp @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/mDNSWindows/Applications/RendezvousBrowser/WindowsCE/Sources/Application.h b/mDNSWindows/Applications/RendezvousBrowser/WindowsCE/Sources/Application.h index fb1437f..1f4fe13 100644 --- a/mDNSWindows/Applications/RendezvousBrowser/WindowsCE/Sources/Application.h +++ b/mDNSWindows/Applications/RendezvousBrowser/WindowsCE/Sources/Application.h @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/mDNSWindows/Applications/RendezvousBrowser/WindowsCE/Sources/BrowserDialog.cpp b/mDNSWindows/Applications/RendezvousBrowser/WindowsCE/Sources/BrowserDialog.cpp index de86ab8..991fc08 100644 --- a/mDNSWindows/Applications/RendezvousBrowser/WindowsCE/Sources/BrowserDialog.cpp +++ b/mDNSWindows/Applications/RendezvousBrowser/WindowsCE/Sources/BrowserDialog.cpp @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/mDNSWindows/Applications/RendezvousBrowser/WindowsCE/Sources/BrowserDialog.h b/mDNSWindows/Applications/RendezvousBrowser/WindowsCE/Sources/BrowserDialog.h index 43f3e6d..7777510 100644 --- a/mDNSWindows/Applications/RendezvousBrowser/WindowsCE/Sources/BrowserDialog.h +++ b/mDNSWindows/Applications/RendezvousBrowser/WindowsCE/Sources/BrowserDialog.h @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/mDNSWindows/Applications/RendezvousBrowser/WindowsCE/Sources/StdAfx.cpp b/mDNSWindows/Applications/RendezvousBrowser/WindowsCE/Sources/StdAfx.cpp index 506a6be..6622a5d 100644 --- a/mDNSWindows/Applications/RendezvousBrowser/WindowsCE/Sources/StdAfx.cpp +++ b/mDNSWindows/Applications/RendezvousBrowser/WindowsCE/Sources/StdAfx.cpp @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/mDNSWindows/Applications/RendezvousBrowser/WindowsCE/Sources/StdAfx.h b/mDNSWindows/Applications/RendezvousBrowser/WindowsCE/Sources/StdAfx.h index fb4331e..3672152 100644 --- a/mDNSWindows/Applications/RendezvousBrowser/WindowsCE/Sources/StdAfx.h +++ b/mDNSWindows/Applications/RendezvousBrowser/WindowsCE/Sources/StdAfx.h @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/mDNSWindows/Applications/RendezvousTest/Tool.c b/mDNSWindows/Applications/RendezvousTest/Tool.c index beda066..7e49566 100644 --- a/mDNSWindows/Applications/RendezvousTest/Tool.c +++ b/mDNSWindows/Applications/RendezvousTest/Tool.c @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/mDNSWindows/Applications/RendezvousTest/ToolPrefixWindows.h b/mDNSWindows/Applications/RendezvousTest/ToolPrefixWindows.h index af1135d..eaa6a70 100644 --- a/mDNSWindows/Applications/RendezvousTest/ToolPrefixWindows.h +++ b/mDNSWindows/Applications/RendezvousTest/ToolPrefixWindows.h @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/mDNSWindows/Applications/RendezvousTest/ToolPrefixWindowsDebug.h b/mDNSWindows/Applications/RendezvousTest/ToolPrefixWindowsDebug.h index 41f56e8..1f76fc2 100644 --- a/mDNSWindows/Applications/RendezvousTest/ToolPrefixWindowsDebug.h +++ b/mDNSWindows/Applications/RendezvousTest/ToolPrefixWindowsDebug.h @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/mDNSWindows/DNSServices/DNSServiceDiscovery.c b/mDNSWindows/DNSServices/DNSServiceDiscovery.c index 0fa57f3..77e3dcb 100644 --- a/mDNSWindows/DNSServices/DNSServiceDiscovery.c +++ b/mDNSWindows/DNSServices/DNSServiceDiscovery.c @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/mDNSWindows/DNSServices/DNSServiceDiscovery.h b/mDNSWindows/DNSServices/DNSServiceDiscovery.h index d132300..618bbb3 100644 --- a/mDNSWindows/DNSServices/DNSServiceDiscovery.h +++ b/mDNSWindows/DNSServices/DNSServiceDiscovery.h @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/mDNSWindows/DNSServices/DNSServices.c b/mDNSWindows/DNSServices/DNSServices.c index edb7047..ca84436 100755 --- a/mDNSWindows/DNSServices/DNSServices.c +++ b/mDNSWindows/DNSServices/DNSServices.c @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/mDNSWindows/DNSServices/DNSServices.h b/mDNSWindows/DNSServices/DNSServices.h index d1fb039..f5be4aa 100755 --- a/mDNSWindows/DNSServices/DNSServices.h +++ b/mDNSWindows/DNSServices/DNSServices.h @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/mDNSWindows/mDNSWin32.c b/mDNSWindows/mDNSWin32.c index e1f012e..161e635 100755 --- a/mDNSWindows/mDNSWin32.c +++ b/mDNSWindows/mDNSWin32.c @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/mDNSWindows/mDNSWin32.h b/mDNSWindows/mDNSWin32.h index 492dbb6..2bf5ddd 100755 --- a/mDNSWindows/mDNSWin32.h +++ b/mDNSWindows/mDNSWin32.h @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in